Grabbing bitmap data off a Shader [SOLVED]



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 09/10/2011 at 09:59, xxxxxxxx wrote:

    Hi there,

    I'm attempting to port some existing Delaunay Triangulation code over to work in Cinema 4d. I'd like to preface this with that I'm not an experienced C4d user, and I'm doing this as part of a collab project with a friend. However I've many years of programming experience in a professional setting so I'm guessing my issue will be more on the C4d side of things.

    I've basically setup a scene with a plane which has a single textureTag on it, which points to a material with a single colour shader on it. The texture for the colour shader is a bitmap. I am running the following code in a python generator to grab the plane and attempt to pull the bitmap off of it. However I'm getting None back for the bitmap.

    Code

    import c4d
    import inspect
    from c4d import utils

    def main() :
        doc = c4d.documents.GetActiveDocument()
        vidPlane = doc.SearchObject('vidPlane')
        print vidPlane
        
        textureTag = vidPlane.GetTag(c4d.Ttexture)
        print textureTag
        
        material = textureTag.GetMaterial()
        print material
        
        colShader = material[c4d.MATERIAL_COLOR_SHADER]
        print colShader
        
        colBitmap = colShader.GetBitmap()

    colBitmap == None

    print colBitmap

    Output

    <c4d.BaseObject object called 'vidPlane/Plane' with ID 5168 at 0x000000000DFB41F0>
    <c4d.TextureTag object called 'Texture/Texture' with ID 5616 at 0x000000000DFB41B0>
    <c4d.BaseMaterial object called 'videoMaterial/Mat' with ID 5703 at 0x000000000DFB41D0>
    <c4d.BaseShader object called 'Bitmap/Bitmap' with ID 5833 at 0x0000000012A3EAA8>
    None

    Usually at this point I'd check out the documentation, however it appears the documentation is rather lacking. On a side note if anyone knows where the source of this c4d namespace is would be incredibly handy) Is there anything obviously wrong with what I'm doing here?

    I'm running in R13.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 09/10/2011 at 14:13, xxxxxxxx wrote:

    Hi Matt,

    the GetPreview() function needs to be updated in the documentation. By wrapping InitRender()/FreeRender() around this call you can extract the bitmap of a bitmap shader.
    For this code snippet 13.029 is required.

    import c4d
    import inspect
    from c4d import utils
    from c4d.modules import render
      
    def main() :
        doc = c4d.documents.GetActiveDocument()
        vidPlane = doc.SearchObject('vidPlane')
        print vidPlane
        
        textureTag = vidPlane.GetTag(c4d.Ttexture)
        print textureTag
        
        material = textureTag.GetMaterial()
        print material
        
        colShader = material[c4d.MATERIAL_COLOR_SHADER]
        print colShader
        
        irs=render.InitRenderStruct() #helper class, members are currently read-only (13.029)
        
        colShader.InitRender(irs)
        colBitmap = colShader.GetBitmap()
        colShader.FreeRender() #must definetly be called after InitRender() otherwise a memleak occurs
        
        # colBitmap == None
        print colBitmap
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 09/10/2011 at 14:29, xxxxxxxx wrote:

    That makes sense. Guess it has to be rendered before you extract it!

    Thanks, I'll get right on this.



  • On 08/12/2014 at 19:22, xxxxxxxx wrote:

    This works great, but I have a problem.
    It renders the first frame of the material/texture, but I want it to render the material based on a particular frame number.

    How do I do that?

    Thanks



  • On 09/12/2014 at 02:01, xxxxxxxx wrote:

    Hello,

    this thread deals with getting the preview of a shader, not of a material. Please do not confuse this.

    The frame may be defined in the InitRenderStruct object. As documented it's parameters are currently read-only.

    Alternatively you could use the shader's Sample() function to sample the shader yourself. The time would be defined in the ChannelData parameter or setting the BaseDocument's time via SetTime() and calling ExecutePasses(). This may depend on the specific shader.

    Best wishes,
    Sebastian



  • On 09/12/2014 at 13:19, xxxxxxxx wrote:

    I'm having some difficulty getting 'Sample()' to do what I want.  I'll keep trying.

    What I'm trying to do is display an animated texture in a GeUserArea.
    I've displayed it with the method above, but alas only for the first frame.
    Is there another way of accomplishing what I'm trying to do?



  • On 09/12/2014 at 14:40, xxxxxxxx wrote:

    I can't seem to set the time to make 'Sample()' work.

    According to the docs, just like the working example above, you have to wrap 'Sample()' between 'InitRender()' and 'FreeRender()'.

    The render structure passed to 'InitRender()' says it is read only, and that the time is set to 'Current Time'.
    But when I do the following:

     
    irs=render.InitRenderStruct()
    print 'Render structure frame: ', irs.time.GetFrame(irs.fps)
    	
    colShader.InitRender(irs)
      
    cd = c4d.modules.render.ChannelData()
    cd.t = 2.0
    cd.p = Vector(0.25, 0.25, 0)
    smpl = colShader.Sample(cd)
    print smpl
      
    colShader.FreeRender()
    

    ...the time printed out for the irs is always 0, no matter what the doc is set to.

    Also, setting the channel data time as I did above seems to have no effect on the sample either.
    I am getting a correct sample of the color at the 'cd.p' I specify, but only at frame 0.

    What am I doing wrong?



  • On 10/12/2014 at 03:12, xxxxxxxx wrote:

    Hello,

    as described above the behavior of a shader depends on the shader. For example the output result may depend on the current state of some animated parameter. In this case the time member of ChannelData may be ignored and the shader has to be animated by setting the time of the host document and calling ExecutePasses().

    Best wishes,
    Sebastian



  • On 10/12/2014 at 08:59, xxxxxxxx wrote:

    I tried:

    doc.ExecutePasses(None, True, True, True, 0)
    

    ...in every spot of my code above, and set the document time to different frames, and I still can't get a sample at a time other than the first frame.

    It seems that when you call:

    irs=render.InitRenderStruct()
    colShader.InitRender(irs)
    

    ...the default render structure time of 0 is what is used for the sample no matter what you do after that.

    Has anyone sampled a:

    material[c4d.MATERIAL_COLOR_SHADER]
    

    ...at a time other than 0?

    Help!



  • On 10/12/2014 at 10:18, xxxxxxxx wrote:

    Hello,

    you must animate the document before calling InitRender() as this function is used by the shader to prepare chaches etc. The exact behavior depends on the shader. Something like this should work:

      
      fps = doc.GetFps()  
      
      # frame 30  
      time = c4d.BaseTime(30,fps)  
        
      doc.SetTime(time)  
      doc.ExecutePasses(None,True,False,False,c4d.BUILDFLAGS_0)  
        
      irs=render.InitRenderStruct()  
      colShader.InitRender(irs)  
        
      # sample shader here      
      # ....  
      
      colShader.FreeRender()   
    

    best wishes,
    Sebastian



  • On 10/12/2014 at 11:10, xxxxxxxx wrote:

    Hello,

    just a small additional note.
    If your shader has a movie or a picture sequence in it, than ExecutePasses seems to be not enough.
    In my plugin I have to fake and recalculate the:
     Shader[c4d.BITMAPSHADER_TIMING_FROM]
    parameter do make it happen.

    Best wishes
    Martin



  • On 10/12/2014 at 12:29, xxxxxxxx wrote:

    Exactly!

    I said I have an animated texture.  It can be either an image sequence, or a movie.
    It just doesn't work.

    Are you just setting the value for [c4d.BITMAPSHADER_TIMING_FROM] back and fourth to make it work?

    Thanks



  • On 10/12/2014 at 12:45, xxxxxxxx wrote:

    first of all I calculate the right frame,
    with
    [c4d.BITMAPSHADER_TIMING_MODE]
    [c4d.BITMAPSHADER_TIMING_TIMING]
    [c4d.BITMAPSHADER_TIMING_RANGEFROM]
    [c4d.BITMAPSHADER_TIMING_RANGETO]
    because the user might have set a loop or a specific startframe e.g.

    But than I simply set the value for [c4d.BITMAPSHADER_TIMING_FROM]
    for every frame to the corresponding doctime

    I asked the question a few month ago, but there seems to be no other way.

    Best wishes
    Martin



  • On 10/12/2014 at 13:52, xxxxxxxx wrote:

    Martin,

    Thank you very much, you just saved me a lot of time.
    It is a hack for sure, but it works like a charm, and now I don't have to use Sample() either, I can get the whole bitmap....whew!

    Whoever did this:

    irs=render.InitRenderStruct() #helper class, members are currently read-only (13.029)
    

    ...as read only blew it.
    You need to be able to set the time in the render structure so you can get the bitmap at different times.

    Thanks again.

    Chris


Log in to reply