Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    Sampling effect channel shaders

    Cinema 4D SDK
    r20 c++ sdk
    2
    11
    2.4k
    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.
    • rsodreR
      rsodre
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • r_giganteR
        r_gigante
        last edited by r_gigante

        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

        1 Reply Last reply Reply Quote 1
        • rsodreR
          rsodre
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • r_giganteR
            r_gigante
            last edited by

            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

            1 Reply Last reply Reply Quote 2
            • r_giganteR
              r_gigante
              last edited by

              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

              rsodreR 1 Reply Last reply Reply Quote 1
              • rsodreR
                rsodre @r_gigante
                last edited by

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

                rsodreR 1 Reply Last reply Reply Quote 0
                • rsodreR
                  rsodre @rsodre
                  last edited by

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

                  1 Reply Last reply Reply Quote 0
                  • r_giganteR
                    r_gigante
                    last edited by

                    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

                    rsodreR 1 Reply Last reply Reply Quote 3
                    • rsodreR
                      rsodre @r_gigante
                      last edited by

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

                      1 Reply Last reply Reply Quote 0
                      • r_giganteR
                        r_gigante
                        last edited by

                        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

                        rsodreR 1 Reply Last reply Reply Quote 3
                        • rsodreR
                          rsodre @r_gigante
                          last edited by

                          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

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post