Detecting shader animation [SOLVED]



  • 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!



  • 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



  • 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.



  • 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



  • 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



  • 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);
        
        
        
    

Log in to reply