Sampling effect channel shaders



  • Hi!

    I have a BaseLink containing a BaseShader that is used as a distribution map on my object, it's not in a material. I usually can sample it fine when using color, texture or a surface like checkerboard. Now I'm trying to sample Effects shaders, having mixed bad results.

    The Vertex Map shader always returns zero, even inverted. I can check the vertex map is ok because there's a material using the same Vertex Map tag on the mesh. When I assign the this tag to my shader, I wish I would get the same result I see pained on the mesh.

    Using the Spline shader give me some warnings when Sample is called (CRITICAL: Stop: Having more than one strong reference to a block which is going to be reallocated is unsafe and CRITICAL: Stop: Could not determine old block size and therefore cannot resize). Then it crashes C4D.

    Is that anything different I need to do to initialize those effect shaders before sampling?

    Thanks,
    Roger


  • Global Moderator

    Hi rsodre, thanks for writing us and sorry for coming late here.

    With regard to your question, I'm actually missing one relevant information: are you inside a VideoPostData context? Or what?

    In order to use BaseShader::Sample() it's requested to pass a properly-filled InitRenderStruct as well as to fire InitRender/FreeRender as shown in this page of our documentation.

    Along the notes above, while certain shaders do not (e.g. texture maps), sampling other type of shaders (e.g. VertexMap) requires the InitRenderStruct passed to be provided with a VolumeData data member (InitRenderStruct::vd) properly populated. That said, only in the context of VideoPostData proper VolumeData information can be obtained and further reused inside your sampling functionality.

    Looking forward to hear about your context, give best.
    Riccardo



  • Hi Riccardo,

    I'm sure calling InitRender/FreeRender, and I can sample textures, so I think that's not the issue.

    My shader is not in a VideoPost, it's in a tag. I need to sample before rendering, during expression Execute(), is there any way to get a VolumeData in that context?

    Does the Spline effect shader also needs a VolumeData? I wonder why... That's a shader that i think users will use often, and having this limitation would be a turn down.

    Thanks,
    Roger


  • Global Moderator

    Hi Roger, thanks for following up.

    With regard to the Spline Shader I confirm that it can be properly sampled without specifying the VolumeData (which is instead needed by VertexMap Shader)

    The following test code works flawlessly on my side

    EXECUTIONRESULT PC_11051_TagData::Execute (BaseTag *tag, BaseDocument *doc, BaseObject *op, BaseThread *bt, Int32 priority, EXECUTIONFLAGS flags)
    {
      if (!tag || !doc || !op || !bt)
        return EXECUTIONRESULT::OUTOFMEMORY;
      
      // allocate and init the InitRenderStruct
      InitRenderStruct irs(doc);
      
      // check the color space
      COLORSPACETRANSFORMATION transform = COLORSPACETRANSFORMATION::NONE;
      // check if linear workflow is enabled
      if (irs.linear_workflow)
        transform = COLORSPACETRANSFORMATION::LINEAR_TO_SRGB;
      
      // find for the attached TextureTag and the related material
      TextureTag* opTTag = (TextureTag*)op->GetTag(Ttexture);
      if (!opTTag)
        return EXECUTIONRESULT::OK;
      
      BaseMaterial* opMat = opTTag->GetMaterial();
      if (!opMat)
        return EXECUTIONRESULT::OK;
      
      // look for the material BaseContainer and the BaseList2D associated to the color param
      BaseContainer* activeMatBC = opMat->GetDataInstance();
      if (!activeMatBC)
        return EXECUTIONRESULT::OK;
    
      BaseList2D* activeMatColorBL = activeMatBC->GetLink(MATERIAL_COLOR_SHADER, doc);
      if (!activeMatColorBL)
        return EXECUTIONRESULT::OK;
      
      // cast to BaseShader
      BaseShader* activeMatColorBS = (BaseShader*)activeMatColorBL;
      
      // define the ChannelData and set the u/v coords for sampling
      ChannelData chData;
      chData.p = Vector(0.5, 0.5, 0);
      
      // call the InitRender before executing sampling
      const INITRENDERRESULT res = activeMatColorBS->InitRender(irs);
      if (res != INITRENDERRESULT::OK)
        return EXECUTIONRESULT::OK;
      
      // sample
      const Vector sampledValue = activeMatColorBS->Sample(&chData);
      // correct based on the color space transformation
      const Vector transformedColor = TransformColor(sampledValue, transform).Clamp01();
      // just print
      DiagnosticOutput("Shader '@' sample at [@,@]: @ / @", maxon::String(activeMatColorBL->GetName()), chData.p.x, chData.p.y, sampledValue, transformedColor);
      
      // call the FreeRender to release allocated memory used for sampling
      activeMatColorBS->FreeRender();
      
      return EXECUTIONRESULT::OK;
    }
    

    The "same" code used inside a PythonTag works as well

    def main():
            # look for an attached TextureTag
            textureTag = op.GetObject().GetTag(c4d.Ttexture)
            if textureTag is None:
                return
            # look for the referred material
            mat = textureTag.GetMaterial()
            if mat is None:
                return
            # look for the shader in the color param
            shd = mat[c4d.MATERIAL_COLOR_SHADER]
            if shd is None:
                return
            
            # init, sample and free
            initRS = c4d.modules.render.InitRenderStruct()
            c4d.INITRENDERRESULT_OK == shd.InitRender(initRS)
            chanData = c4d.modules.render.ChannelData()
            chanData.p = c4d.Vector(0.5,0.5,0)
            print "Shader '",shd.GetName(),"' sample at [",chanData.p.x,",",chanData.p.y,"]: ", shd.Sample(chanData)
            shd.FreeRender()
    

    Finally a screenshot of the test scene
    0_1539104613530_20ea149b-fdf9-432e-97d9-15b91a5eaa46-image.png

    Hoping it helps, don't hesitate to get back for any further help.

    Riccardo


  • Global Moderator

    Hi roger, can I consider this topic as solved or do you need any further investigation?

    If solved, please mark the thread as solved OR, in the three-bullet menu of a post, click on "Mark this post as the correct answer".

    Best, Riccardo



  • @r_gigante Good timing! I just finished my implementation based on your example, now it's working fine, thanks.

    I found out the crash was caused by using Sample inside a parallel_for. Enclosing he Sample() call with a maxon::SpinLock::Lock() and Unlock() fixed it.

    And I was not using TransformColor(), so the sampled values were not consistent with the material.

    I have just a couple of questions before closing this.

    How can we see the preview of the Vertex Map shader in the viewport if there's no VolumeData available at this point?

    Is there a way to check if a specific shader needs VolumeData? Would be nice to warn the user that a shader (like Vertex Map) cannot be used if selected.