Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Detecting shader animation [SOLVED]

    SDK Help
    0
    6
    597
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 02/06/2016 at 23:17, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   14+ 
      Platform:   Windows  ;   Mac OSX  ; 
      Language(s) :     C++  ;

      ---------
      Hi,

      I am having a problem detecting animation on a sampled shader, like an animated noise shader or movie file loaded as a bitmap.
      When using dirty flags on a noise shader for example, I get an update only when parameters (like global scale) are keyframed, but not with the built-in animation speed which does not require keyframes.
      Also, dirty flags seem to have no effect on animated movie files.

      Here is the code I am using to get the shader, as discussed in an earlier thread of mine.

        
      	AutoAlloc<BaseBitmap> bmp;
      	BaseShader* shaderLink = (BaseShader* )bc->GetLink(MYSHADERLINK,doc);
        
      	if (shaderLink)
      	{
      		InitRenderStruct irs;
      		shaderLink->InitRender(irs);
        
      		LONG bitmapWidth = 100; 
      		LONG bitmapHeight = 100; 
        
      		IMAGERESULT res = bmp->Init(bitmapWidth, bitmapHeight);
        
      		if (res == IMAGERESULT_OK)
      		{
      			ChannelData chD;
      			chD.p = Vector(0, 0, 0);
      			chD.n = Vector(0, 1, 0);
      			chD.d = Vector(0, 0, 0);
      			chD.texflag = TEX_TILE;
      			chD.vd = NULL;
      			chD.off = 0.0;
      			chD.scale = 0.0;
      			chD.t = doc->GetTime().GetFrame(doc->GetFps()); //doesn't do anything
        
      			for (LONG x=0; x < bitmapWidth; x++) 
      			{
      				for (LONG y=0; y < bitmapHeight; y++) 
      				{
      					chD.p.x = (Real) x / bitmapWidth;
      					chD.p.y = (Real) y /bitmapHeight;
      					Vector pixel = shaderLink->Sample(&chD);
        
      					LONG r1 = pixel.x * 255;
      					LONG g1 = pixel.y * 255;
      					LONG b1 = pixel.z * 255;
      					bmp->SetPixel(x, y, r1, g1, b1);
      				}
      			}
      		}
      		shaderLink->FreeRender(); 
      	}
        
      
      

      Any help on auto-updating animated shaders would be great. Thanks!

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 03/06/2016 at 02:17, xxxxxxxx wrote:

        Hello,

        the "t" element of ChannelData is not the frame number. It is the time in seconds. So you have to set the time using:

          
        channelData.t = doc->GetTime().Get();  
        

        The dirty flags of these shaders do not change because these shaders do not become dirty. An element becomes dirty if it was changed, if internal data like parameters was changed. But these shaders do not change over time, they just deliver different return values (Sample()) for different input values. So technically these shaders are not animated.

        So I guess you have to manually check if the given shader may be of a type that is time dependent and check if the parameters that do enable that behaviour are set.

        Best wishes,
        Sebastian

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 03/06/2016 at 05:16, xxxxxxxx wrote:

          Thanks Sebastian. I got it working with the noise shader from your suggestion.

          Any idea on how to force the loading of complete movie files? So far I am just getting the first frame of the video.

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 03/06/2016 at 08:47, xxxxxxxx wrote:

            Hello,

            what exactly do you mean with "loading of complete movie files"? Do yo mean to load an image sequence? To do that you would have to press the BITMAPSHADER_CALCULATE button.

            Best wishes,
            Sebastian

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 03/06/2016 at 09:12, xxxxxxxx wrote:

              This is how I've done it.
              In order to capture each frame of a movie loaded in a shader. I change the "Movie Start Frame" attribute then extract the image.

              //This is how to render the images of a movie file in the color channel's shader to bitmap images  
                
              Bool SimplePlugin::Execute(BaseDocument *doc)  
              {  
                BaseMaterial *mat = doc->GetFirstMaterial();  
                if (!mat) return FALSE;  
                
                ////////////////////////////////////////////////////////////////////////////////////////////////////////  
                //Get the values for the "Movie Start Frame" & "Movie End Frame" in a shader just in case you need them  
                
                GeData data;  
                mat->GetParameter(DescID(MATERIAL_COLOR_SHADER), data, DESCFLAGS_GET_0);  
                
                BaseShader *shader = static_cast<BaseShader*>(data.GetLink(doc, Xbitmap));  
                if (!shader || !shader->IsInstanceOf(Xbitmap)) return false;  
                
                shader->GetParameter(DescID(BITMAPSHADER_TIMING_FROM), data, DESCFLAGS_GET_0);  
                const LONG startTime = data.GetLong();  
                GePrint("Start: " + LongToString(startTime));  
                
                shader->GetParameter(DescID(BITMAPSHADER_TIMING_TO), data, DESCFLAGS_GET_0);  
                const LONG endTime = data.GetLong();  
                GePrint("End: " + LongToString(endTime));  
                ////////////////////////////////////////////////////////////////////////////////////////////////////////  
                
                
                //In the following code block we will extract the shader's image to a bitmap image  
                AutoAlloc<BaseBitmap> bmp;  
                
                //We need to set the "Movie Start Frame" attribute to the same value as the time scrubber  
                //Otherwise..we will only capture the first frame of the movie file in the shader  
                LONG curframe = doc->GetTime().GetFrame(doc->GetFps());  
                shader->SetParameter(DescID(BITMAPSHADER_TIMING_FROM), curframe, DESCFLAGS_SET_0);  
                
                //Capture the movie's color values depending on the frame the scrubber is at  
                if(shader)  
                {  
                    InitRenderStruct irs;  
                    shader->InitRender(irs);  
                
                    LONG bitmapWidth = 100;  
                    LONG bitmapHeight = 100;  
                    IMAGERESULT res = bmp->Init(bitmapWidth, bitmapHeight);  
                    if (res == IMAGERESULT_OK)  
                    {  
                        ChannelData cd;  
                        cd.p = Vector(0, 0, 0);  
                        cd.n = Vector(0, 1, 0);  
                        cd.d = Vector(0, 0, 0);  
                        cd.texflag = TEX_TILE;  
                        cd.vd = NULL;  
                        cd.off = 0.0;  
                        cd.scale = 0.0;              
                        cd.t = curframe;              
                
                        for (LONG x = 0; x < bitmapWidth; x++)  
                        {  
                            for (LONG y = 0; y < bitmapHeight; y++)  
                            {  
                                cd.p.x = (Real)x / bitmapWidth;  
                                cd.p.y = (Real)y / bitmapHeight;  
                                Vector pixel = shader->Sample(&cd);  
                
                                LONG r1 = pixel.x * 255;  
                                LONG g1 = pixel.y * 255;  
                                LONG b1 = pixel.z * 255;  
                                bmp->SetPixel(x, y, r1, g1, b1);  
                            }  
                        }  
                    }  
                
                    ShowBitmap(bmp);  
                    shader->FreeRender();  
                }  
                
                
                EventAdd();  
                return TRUE;  
              }
              

              -ScottA

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 03/06/2016 at 11:19, xxxxxxxx wrote:

                Thank you Scott. This line was the missing link

                    
                    
                    shader->SetParameter(DescID(BITMAPSHADER_TIMING_FROM), curframe, DESCFLAGS_SET_0);
                    
                    
                    
                
                1 Reply Last reply Reply Quote 0
                • First post
                  Last post