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



  • 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



  • 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



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



  • @r_gigante , sorry to uncover this old topic, but this issue remains pending on my desk, and I would like to close it for good. There's a couple of questions about the Vertex Map shader that remained unanswered:

    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.

    I don't know anything about VolumeData, never used it. But I see hints on the documentation like VolumeBuilder, PointsToVolume and MeshToVolume without any context on why they exist and how they are useful, and that makes me have a slight hope of sampling that shader.

    It's hard to accept that the colors I see over my mesh on the viewport are impossible to access. That would be really helpful on our plugin workflow.



  • Hi Roger, thanks for following up.

    With regard to "previewing" a Vertex Map in viewport you're not actually seeing the output generated by the VertexMap shader but the actual data belonging to VertexMap Tag where the VolumeData information is no needed at all.

    Finally, despite the naming similarity, VolumeBuilder, PointsToVolume and MeshToVolume have nothing to do with VolumeData.
    While the first three are indeed related to the new Volume-based modeling workflow introduced in R20, the latter, present in Cinema since time, has relevance in the context of rendering and is responsible for storing all the scene data information ready to be dispatched to a rendering engine.

    Best, Riccardo



  • @r_gigante said in Sampling effect channel shaders:

    With regard to "previewing" a Vertex Map in viewport you're not actually seeing the output generated by the VertexMap shader but the actual data belonging to VertexMap Tag where the VolumeData information is no needed at all.

    Sure, makes complete sense. There's no shader involved at this point, only the tag.
    I will study a workaround using the VertexMapTag data.

    There's just one unanswered question to close this topic...
    Is there a way to check if a specific shader needs VolumeData?
    Would be nice to warn the user when the selected shader will not work within this feature.



  • Hi Roger,

    although I see your concern, in the current API there are no means to know beforehand if a certain shader requires a valid VolumeData instance to be passed within the ChannelData instance to deliver a "proper" sampling.
    Being the VolumeData pointer equal to nullptr in the ChannelData constructor, there's actually nothing back when the BaseShader::Sample() methods are invoked without a valid VolumeData being passed.

    Last but not least, also BaseShader::GetRenderInfo() isn't of any help in this case.

    Best, Riccardo



  • Thanks Riccardo, I think we reached the bottom of this issue.

    I just finished implementing a workaround, getting the tag associated with the shader, it's polygon, points and uvw tag, then paint each face with the average vertex value in a bitmap using GeClipMat. Working really good!

    Best,
    Roger