Texture Tag Output



  • Hello!

    I've been trying to get the 'output' of a Texture Tag in a similar way to how the Shader Effector and the Displacer Deformer does.

    Using the Displacer Deformer to explain what I mean. If the "Channel" parameter is set to "Color" instead of "Custom" I now feed the "Texture Tag" field a texture tag. The Displacer now using all the information from that texture tag to do its calculations, such as the shaders, the projection, and the PSR.

    The Displacer is referencing the Texture Tag to calculate a greyscale value at a given position for each polygon point. Instead of using the Displacer though, I would want to be able to use in my own points with the Texture Tag and retrieve the greyscale value of those custom locations.

    I'm not really sure where to start exploring this, I was looking at some things like ChannelData and VolumeData, but that didn't seem to be what I needed. Any help to point me in the right direction would be greatly appreciated!


  • Global Moderator

    Hi d_schmidt and thanks for reaching us.

    With regard to your request, what you actually need to do is to "sample" a BaseShader used somewhere in the material referred by the TextureTag.

    The topic is indeed not too complex but requires some reading in order to get comfortable and proficient with the means provided in the API before dipping toes in sampling shaders.
    I recommend:

    I also point you to this thread where sampling the color at meshes vertexes is shown using a Python script. Maybe it will simply help you to glue together the information got by reading the reference above.

    Best, Riccardo.



  • Hi Riccardo!

    Sorry about the late response but I had to start working on something else for a few days. I went through all of your recommended links and the thread and I think I'm getting a better idea of how the Material, Texture Tag, and the UVWs interact and I'm able to get the shader color at UVW points of my choice.

    I had a follow up question of how this process would work while using a different type of projection Spherical, Cylindrical, Cubic for example. The way I currently understand it is that the texture tag's matrix would be used to determine this, but I'm not sure how the matrix should come into play. It's possible I missed something in the links you provided but I would appreciate another push in the correct direction.

    Dan


  • Global Moderator

    Hi Dan, thanks for following up here.

    With regard to your comment, the texture tag's matrix takes place when passed as 4th argument of the GenerateUVW(). This matrix is actually responsible for positioning the "virtual mapping gizmo" in space with respect to the object itself

    To be more clear image you need you've a plane placed on the origin and laying on XZ. You need to create a flat mapping on it rotated by 45 degrees on w, stretched by 0.5 on u and 2.0 on v and shifted from the origin of a certain amount.

    Assuming you also have a material existing in the Material Manager running the script below will execute the task.

    # Main function
    def main():
        # check that an object is selected
        if op is None:
            return
    
        # get the active material
        activeMat = doc.GetActiveMaterial()
        if activeMat is None:
            return
    
        # instantiate a TextureTag
        texTag = c4d.TextureTag()
        if texTag is None:
            return
    
        # set the mapping type
        texTag[c4d.TEXTURETAG_PROJECTION] = c4d.TEXTURETAG_PROJECTION_FLAT
        # turn off tiling
        texTag[c4d.TEXTURETAG_TILE] = False
        # link to the active material
        texTag[c4d.TEXTURETAG_MATERIAL] = activeMat
        
        # apply some modification to the spatial position of the texturetag
        angleDeg = -90
        # orient the virtual flat gizmo from xy-plane to xz-plane
        texTagMatrix = c4d.utils.RotAxisToMatrix(c4d.Vector(1,0,0), math.radians(angleDeg))
        # rotate around the local Z-axis by 30degs
        angleDeg = 45
        texTagMatrix = texTagMatrix * c4d.utils.RotAxisToMatrix(c4d.Vector(0,0,1), math.radians(angleDeg))
        # stretch the texture by 0.5 on X-axis and 2 on Z-axis
        texTagMatrix.Scale(c4d.Vector(0.5,1,2))
        # apply some offset to the texture
        texTagMatrix.off = c4d.Vector(50,0,-100)
    
        # generate the corresponding UVWTag using the mapping settings specific in the TextureTag
        uvwTag = c4d.utils.GenerateUVW(op, op.GetMg(), texTag, texTagMatrix)
        texTag[c4d.TEXTURETAG_PROJECTION] = 6
        if op.GetTag(c4d.Tuvw) is None:
            op.InsertTag(uvwTag)
        if op.GetTag(c4d.Ttexture) is None:
            op.InsertTag(texTag)
        c4d.EventAdd()
    
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    In this context the TextureTag's matrix actually plays the role that can be seen by manipulating the mapping when an object is in Texture Mode

    Best, Riccardo



  • Hello.

    Thank you for all of the help! Just to make sure I'm on the same page as you I ran your code with a Checkerboard shader and got this as a result.

    alt text

    I've been doing some tests but I'm not getting the results I was looking for with this code.

    import c4d
    from c4d import gui
    
    def main():
        currentUVWTag = op.GetTag(c4d.Tuvw)
        currentMaterial = op.GetTag(c4d.Ttexture).GetMaterial()
        shd = currentMaterial[c4d.MATERIAL_COLOR_SHADER]
        # init via  InitRenderStruct()
        initRS = c4d.modules.render.InitRenderStruct()
        c4d.INITRENDERRESULT_OK == shd.InitRender(initRS)
        chanData = c4d.modules.render.ChannelData()
        pointcount = 10
        checks=range(pointcount)
        # loop over the data in the UVW set to retrieve the color
        uvwdict = currentUVWTag.GetSlow(0)
    
        spot1 = uvwdict["a"]
        spot2 = uvwdict["c"]
        for y in checks:
            for x in checks:
                local = c4d.Vector(spot1.x+(spot2.x/pointcount*x),spot1.y+(spot2.y/pointcount*y),0)
                chanData.p =  local
                col = shd.Sample(chanData)
                print  local, "/", col
    
    
        shd.FreeRender()
    
    if __name__=='__main__':
        main()
    

    The idea is using the UVW tag created by your code on a 1 polygon plane. Then using 'a' and 'c' I'm trying to browse the entire polygon, sampling it in a ten by ten grid. The results aren't what I expected though. I'm returning the location and the color, and I would think I would get getting some sort of 'empty' value where the shader isn't drawing, but it's always returning the color vector of the checkerboard. Do I need to be sampling the texture instead of the shader? Or am I doing something else wrong?

    Dan


  • Global Moderator

    Hi Dan, thanks for following up.

    With regard to the code posted I think there are two things to check:

    • the expression used to compute the linear interpolation is incorrect: it should rather be spot1.x + (spot2.x - spot1.x) / pointcount*x as well as for y

    • beware of properly specifying the ChannelData::texflag and specify the correct TEX flag.

    Last but not least, in Python you can only sample shaders being the BaseShader::Sample available. On C++ instead it's also possible sample BaseChannels via BaseChannel::Sample.

    Best, Riccardo



  • Thanks again, Riccardo. I really appreciate all of the help.

    I noticed the sampling coordinate issue right before I checked back here, sorry about such a simple mistake.

    If I had to redo the code in C++ that would be totally fine. BaseChannel::Sample would work to give me the end output once I pass it the correct UVW coordinate, right? Would there be a better way to get what the UVW coordinate would be at a given point in C++? I'm not seeing a simple way to pass the Texture Tag and there for the projection type to it. This seems like it's possibly pretty simply but I'm not properly understanding it.

    Dan