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

    Texture Tag Output

    Cinema 4D SDK
    c++ sdk r20
    2
    15
    2.6k
    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.
    • r_giganteR
      r_gigante
      last edited by

      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:

      • TextureTag Manual
        and
      • Materials and Shaders Overview.

      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.

      1 Reply Last reply Reply Quote 3
      • D
        d_schmidt
        last edited by

        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

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

          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

          1 Reply Last reply Reply Quote 3
          • D
            d_schmidt
            last edited by d_schmidt

            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

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

              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

              1 Reply Last reply Reply Quote 1
              • D
                d_schmidt
                last edited by d_schmidt

                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

                Edit:

                I want to clarify that I'm looking to accomplish something similar to how the displacer object in this example is able to use the linked texture tag(set to spherical projection, and using any movements of the texture) to correctly displace the plane. I want to be able to get the same data that I assume the Displacer is getting access to so that I can create my own custom outputs.

                alt text

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

                  Hi Dan, thanks for providing further details on it and sorry for coming late here.

                  Actually I spent some time to run some test and, in the end, I confirm that what you're looking for can be delivered also on Python if sampling shader is sufficient.

                  In my tests, I also found that BaseChannel::Sample() has the same behavior or BaseShader::Sample() and both are "somehow" actually agnostic to tiling.
                  What should be evaluated before hand is if we're sampling the "first" tile or its repetition and this can be done via a simple helper function that, for the sole UVW case (you can extend the cases by looking at the ShdProjectPoint here), looks like as:

                  TEX_EPSILON = 0.0001
                  
                  def TestUVW(texdata, uvw):
                      # check texdata
                      if texdata is None or uvw is None:
                          return False
                  
                      # update the UVW value by evaluting TextureTag offset/tiles
                      if texdata["proj"] == c4d.P_UVW:
                          uvw.x = (uvw.x - texdata["ox"]) * texdata["invLenx"];
                          uvw.y = (uvw.y - texdata["oy"]) * texdata["invLeny"];
                          
                          # if tiling simply return
                          if texdata["texflag"] & c4d.TEX_TILE:
                              return True
                  
                          # return True only if UV coord are referring to the first tile, False otherwise
                          return (uvw.x >= -TEX_EPSILON and uvw.x <= 1.0+TEX_EPSILON) and (uvw.y >= -TEX_EPSILON and uvw.y <= 1.0+TEX_EPSILON)
                  
                      return false
                  

                  Given that, the whole code to sample an object where UVW mapping and a non-tiling TextureTag are assigned looks as:

                  import c4d
                  
                  TEX_EPSILON = 0.0001
                  
                  def TestUVW(texdata, uvw):
                      # check texdata
                      if texdata is None or uvw is None:
                          return False
                  
                      # update the UVW value by evaluting TextureTag offset/tiles
                      if texdata["proj"] == c4d.P_UVW:
                          uvw.x = (uvw.x - texdata["ox"]) * texdata["invLenx"];
                          uvw.y = (uvw.y - texdata["oy"]) * texdata["invLeny"];
                          
                          # if tiling simply return
                          if texdata["texflag"] & c4d.TEX_TILE:
                              return True
                  
                          # return True only if UV coord are referring to the first tile, False otherwise
                          return (uvw.x >= -TEX_EPSILON and uvw.x <= 1.0+TEX_EPSILON) and (uvw.y >= -TEX_EPSILON and uvw.y <= 1.0+TEX_EPSILON)
                  
                      return false
                  
                  
                  # Main function
                  def main():
                      if op is None:
                          return
                  
                      # get the current TextureTag / Material / UVWTag
                      currentTextureTag = op.GetTag(c4d.Ttexture)
                      currentMaterial =  currentTextureTag[c4d.TEXTURETAG_MATERIAL]
                      currentUVWTag = op.GetTag(c4d.Tuvw)
                      # get the shader associated to the color slot
                      shd = currentMaterial[c4d.MATERIAL_COLOR_SHADER]
                      # init via  InitRenderStruct()
                      initRS = c4d.modules.render.InitRenderStruct()
                      c4d.INITRENDERRESULT_OK == shd.InitRender(initRS)
                  
                      # init the ChannelData
                      chanData = c4d.modules.render.ChannelData()
                      chanData.n = c4d.Vector(0.0, 0.0, 1.0)
                      chanData.d = c4d.Vector(0.01,0.01,0.01)
                      chanData.scale = 1.0
                  
                      # prepare the data for testing the UVW
                      texdata = {
                      "proj" : currentTextureTag[c4d.TEXTURETAG_PROJECTION],
                      "ox" : currentTextureTag[c4d.TEXTURETAG_OFFSETX],
                      "oy" : currentTextureTag[c4d.TEXTURETAG_OFFSETY],
                      "invLenx" : currentTextureTag[c4d.TEXTURETAG_TILESX],
                      "invLeny" : currentTextureTag[c4d.TEXTURETAG_TILESY],
                      "texflag" : 0
                      }
                  
                      # check the tiling state
                      if currentTextureTag[c4d.TEXTURETAG_TILE]:
                          texdata["texflag"] = texdata["texflag"] & TEX_TILE
                  
                      points = op.GetAllPoints()
                      polygons = op.GetAllPolygons()
                  
                      pointcount = 10
                      # loop over the data in the UVW set to retrieve the color
                      uvwdict = currentUVWTag.GetSlow(0)
                  
                      spot1 = uvwdict["a"]
                      spot2 = uvwdict["c"]
                      print polygons[0]
                      point1 = points[polygons[0].a]
                      print point1
                      point2 = points[polygons[0].c]
                      print point2
                      for i in xrange(pointcount+1):
                          for j in xrange(pointcount+1):
                              col = c4d.Vector(-1)
                              localUVW = c4d.Vector (spot1.x + (spot2.x-spot1.x) / pointcount * i, spot1.y + (spot2.y - spot1.y) / pointcount * j, 0)
                              localPOS = c4d.Vector (point1.x + (point2.x-point1.x) / pointcount * i, 0, point1.z + (point2.z - point1.z) / pointcount * j)
                  
                              if (TestUVW(texdata, localUVW)):
                                  chanData.p = localUVW
                                  col = shd.Sample(chanData)
                  
                              print  i, ",", j, " / ", localPOS, " / ", localUVW, "/", col
                  
                      # free the allocated resources
                      shd.FreeRender()
                  
                  # Execute main()
                  if __name__=='__main__':
                      main()
                  

                  For all the points hitting the mapping with the shader, the color is returned, whilst for the remaining points (-1, -1, -1) is returned.

                  Best, Riccardo

                  1 Reply Last reply Reply Quote 3
                  • D
                    d_schmidt
                    last edited by

                    Hi Riccardo!

                    No worries about the wait, I really appreciate all of the help you've been giving me. I'm going over the code you provided and working to implement one of the other projections to make sure I properly understand it.

                    With the code you provided I'm confused about the handling of tiling. Why is it necessary to implement return True if it is tiling? Would just taking the modulo of the uvw.x and uvw.y not work? In my few tests it seems to do the job.

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

                      Hi Dan,

                      the approach I depicted is just one of the many viable and shouldn't be deemed as "the" approach. I'm simply returning True to avoid checking for the passed uvw being in the "1st" tile.

                      But, again, feel free to experiment and if you find a better approach just share your code for the sake of our community growth.

                      Best, Riccardo

                      1 Reply Last reply Reply Quote 0
                      • D
                        d_schmidt
                        last edited by

                        Hi again, Riccardo!

                        If I figure it out I'll be sure to post it.

                        I've been trying to get some of the other projection types to work but I've been having trouble with them. So I went to Flat Projection since it seems like the simplest one on the list.

                        case P_FLAT: case P_SPATIAL:
                            {
                              Vector d = p * tdp->im;
                              uv->x =  (d.x*0.5-tdp->ox)*lenxinv;
                              uv->y = -(d.y*0.5+tdp->oy)*lenyinv;
                              break;
                            }
                        

                        Modifying your code with it though isn't giving me the sort of outputs I would be expecting.

                        import c4d
                        import math
                        TEX_EPSILON = 0.0001
                        
                        def TestUVW(texdata, uvw):
                            # check texdata
                            if texdata is None or uvw is None:
                                return False
                        
                            # update the UVW value by evaluting TextureTag offset/tiles
                            if texdata["proj"] == c4d.P_UVW:
                                uvw.x = (uvw.x - texdata["ox"]) * texdata["invLenx"];
                                uvw.y = (uvw.y - texdata["oy"]) * texdata["invLeny"];
                        
                                # if tiling simply return
                                if texdata["texflag"] & c4d.TEX_TILE:
                                    return True
                        
                                # return True only if UV coord are referring to the first tile, False otherwise
                                return (uvw.x >= -TEX_EPSILON and uvw.x <= 1.0+TEX_EPSILON) and (uvw.y >= -TEX_EPSILON and uvw.y <= 1.0+TEX_EPSILON)
                        
                            return false
                        
                        #code I added
                        def TestFlat(texdata,p):
                            d = p * texdata["im"]
                            uv = c4d.Vector()
                            uv.x =  (d.x*.5-texdata["ox"])*texdata["invLenx"]
                            uv.y = -(d.y*.5+texdata["oy"])*texdata["invLeny"]
                            
                            return uv
                        # Main function
                        def main():
                            if op is None:
                                return
                        
                            # get the current TextureTag / Material / UVWTag
                            currentTextureTag = op.GetTag(c4d.Ttexture)
                            currentMaterial =  currentTextureTag[c4d.TEXTURETAG_MATERIAL]
                            currentUVWTag = op.GetTag(c4d.Tuvw)
                            # get the shader associated to the color slot
                            shd = currentMaterial[c4d.MATERIAL_COLOR_SHADER]
                            # init via  InitRenderStruct()
                            initRS = c4d.modules.render.InitRenderStruct()
                            c4d.INITRENDERRESULT_OK == shd.InitRender(initRS)
                        
                            # init the ChannelData
                            chanData = c4d.modules.render.ChannelData()
                            chanData.n = c4d.Vector(0.0, 0.0, 1.0)
                            chanData.d = c4d.Vector(0.01,0.01,0.01)
                            chanData.scale = 1.0
                          
                            # prepare the data for testing the UVW
                            invlenx = 0
                            invleny =0
                            if currentTextureTag[c4d.TEXTURETAG_LENGTHX] !=0:
                                invlenx = 1.0/currentTextureTag[c4d.TEXTURETAG_LENGTHX]
                            if currentTextureTag[c4d.TEXTURETAG_LENGTHY] !=0:
                                invleny = 1.0/currentTextureTag[c4d.TEXTURETAG_LENGTHY]
                            
                            texdata = {
                            "proj" : currentTextureTag[c4d.TEXTURETAG_PROJECTION],
                            "ox" : currentTextureTag[c4d.TEXTURETAG_OFFSETX],
                            "oy" : currentTextureTag[c4d.TEXTURETAG_OFFSETY],
                            "invLenx" : invlenx,#currentTextureTag[c4d.TEXTURETAG_TILESX],
                            "invLeny" : invleny,#currentTextureTag[c4d.TEXTURETAG_TILESY],
                            "texflag" : 0,
                            "lenx" : currentTextureTag[c4d.TEXTURETAG_LENGTHX],
                            "leny" : currentTextureTag[c4d.TEXTURETAG_LENGTHY],
                            "im":~currentTextureTag.GetMl()
                            
                            }
                            
                            # check the tiling state
                            if currentTextureTag[c4d.TEXTURETAG_TILE]:
                                texdata["texflag"] = texdata["texflag"] & c4d.TEX_TILE
                        
                            points = op.GetAllPoints()
                            polygons = op.GetAllPolygons()
                        
                            pointcount = 10
                            # loop over the data in the UVW set to retrieve the color
                            uvwdict = currentUVWTag.GetSlow(0)
                        
                            spot1 = uvwdict["a"]
                            spot2 = uvwdict["c"]
                            point1 = points[polygons[0].a]
                            point2 = points[polygons[0].c]
                            check = c4d.Vector()
                            for i in xrange(pointcount+1):
                                for j in xrange(pointcount+1):
                                    col = c4d.Vector(-1)
                                    localUVW = c4d.Vector (spot1.x + (spot2.x-spot1.x) / pointcount * i, spot1.y + (spot2.y - spot1.y) / pointcount * j, 0)
                                    localPOS = c4d.Vector (point1.x + (point2.x-point1.x) / pointcount * i, 0, point1.z + (point2.z - point1.z) / pointcount * j)
                                
                                    if texdata["proj"] == c4d.TEXTURETAG_PROJECTION_UVW:
                                        if (TestUVW(texdata, localUVW)):
                                            chanData.p = localUVW
                                            col = shd.Sample(chanData)
                                    
                                    if texdata["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                            flatprojection = TestFlat(texdata,localUVW)
                                            chanData.p = flatprojection
                                            col = shd.Sample(chanData)
                        
                        
                                    print  i, ",", j, " / ", localPOS, " / ", localUVW, "/",flatprojection,"/", col
                        
                            # free the allocated resources
                            shd.FreeRender()
                        
                        # Execute main()
                        if __name__=='__main__':
                            main()
                        

                        I took texdata["im"] to mean the inverted matrix of the Texture Tag because of the documentation saying "The inverse of the texture projection matrix. " Because of the default scale of 100 on the texture tag it was making everything really tiny, so I started to use GetNormalized on texdata["im"]. Even in that case it wasn't outputting what I was expecting.

                        I modified your output to show what TestFlat() was returning and what was actually being sampled.

                         print  i, ",", j, " / ", localPOS, " / ", localUVW, "/",flatprojection,"/", col
                        

                        Given a normal flat texture I thought that flatprojection would go from vector(.25,0,0) to vector(.75,1,0), but it's actually going from vector(0,-.5,0) to vector(.5,0,0). The latter seems consistent with the code I wrote, but that doesn't seem to be what give the correct output.

                        Here is my current setup, with a simple gradient texture and a one polygon 200x200 plane.
                        alt text

                        Am I still missing something? Am I wrong about what matrix texdata["im"] is supposed to be? The flat projection could is simple enough that I don't see many places where I could have made a mistake.

                        Dan

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

                          Hi Dan, thanks for following up and sorry for coming late here.

                          With regard to your new post, there are a few points to clarify:

                          • the snippet found in the TexData page in our documentation should be used to compute the UV value for a certain point not for testing a point being inside or outside first tile;

                          That said, you are supposed i would suggest to write the coder above as:

                          # return the UV of a certain point when flat projection is used
                          def ComputeFlatMapping(mappingInfo, p):
                              uv = c4d.Vector()
                              # check projection being set to flat
                              if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                  d = p * mappingInfo["im"]
                                  uv.x = (d.x * .5 - mappingInfo["ox"]) * mappingInfo["invLenx"] + 0.5
                                  uv.y = (d.y * .5 + mappingInfo["oy"]) * mappingInfo["invLeny"] + 0.5
                              return uv
                          

                          and later on in the code do something like:

                              # compute the UV value at two vertexes
                                  if currentTextureTag[c4d.TEXTURETAG_PROJECTION] == c4d.TEXTURETAG_PROJECTION_UVW:
                                      spot1 = uvwdict["a"]
                                      spot2 = uvwdict["c"]
                                  else:
                                      # non UVW cases should be generated on the fly during the sampling loop
                                      spot1 = 0
                                      spot2 = 0
                          

                          The whole code should then look like (I've cleaned and reorganized a few items there):

                          import c4d
                          import math
                          TEX_EPSILON = 0.0001
                          
                          # test if a given uv value-set is inside first tile (0-1) or outside it
                          def TestTiling(mappingInfo, uvw):
                              # check passed arguments
                              if mappingInfo is None or uvw is None:
                                  return False
                          
                              # update the UVW value by evaluating TextureTag offset/tiles
                              if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_UVW:
                                  uvw.x = (uvw.x - mappingInfo["ox"]) * mappingInfo["invLenx"]
                                  uvw.y = (uvw.y - mappingInfo["oy"]) * mappingInfo["invLeny"]
                          
                              # if tiling simply return
                              if mappingInfo["texflag"] & c4d.TEX_TILE:
                                  return True
                          
                              # return True only if UV coord are referring to the first tile, False otherwise
                              return (uvw.x >= -TEX_EPSILON and uvw.x <= 1.0+TEX_EPSILON) and (uvw.y >= -TEX_EPSILON and uvw.y <= 1.0+TEX_EPSILON)
                          
                          # return the UV of a certain point when flat projection is used
                          def ComputeFlatMapping(mappingInfo, p):
                              uv = c4d.Vector()
                              # check projection being set to flat
                              if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                  d = p * mappingInfo["im"]
                                  uv.x = (d.x * .5 - mappingInfo["ox"]) * mappingInfo["invLenx"] + 0.5
                                  uv.y = (d.y * .5 + mappingInfo["oy"]) * mappingInfo["invLeny"] + 0.5
                              return uv
                          
                          # Main function
                          def main():
                              if op is None:
                                  return
                          
                              # get the current TextureTag / Material / UVWTag
                              currentTextureTag = op.GetTag(c4d.Ttexture)
                              currentMaterial =  currentTextureTag[c4d.TEXTURETAG_MATERIAL]
                          
                              mappingInfo = {
                                  "proj" : currentTextureTag[c4d.TEXTURETAG_PROJECTION],
                                  "ox" : currentTextureTag[c4d.TEXTURETAG_OFFSETX],
                                  "oy" : currentTextureTag[c4d.TEXTURETAG_OFFSETY],
                                  "invLenx" : currentTextureTag[c4d.TEXTURETAG_TILESX],
                                  "invLeny" : currentTextureTag[c4d.TEXTURETAG_TILESY],
                                  "texflag" : 0,
                                  "lenx" : currentTextureTag[c4d.TEXTURETAG_LENGTHX],
                                  "leny" : currentTextureTag[c4d.TEXTURETAG_LENGTHY],
                                  "im":~currentTextureTag.GetMl()
                              }
                          
                              # check the tiling state
                              if currentTextureTag[c4d.TEXTURETAG_TILE] == 1:
                                  print "here tiling"
                                  mappingInfo["texflag"] = mappingInfo["texflag"] | c4d.TEX_TILE
                          
                              points = op.GetAllPoints()
                              polygons = op.GetAllPolygons()
                          
                              intermediatePointsCnt = 10
                              point1 = points[polygons[0].a]
                              point2 = points[polygons[0].c]
                          
                              # get the first UVWTag
                              currentUVWTag = op.GetTag(c4d.Tuvw)
                              if currentUVWTag is None:
                                  return
                          
                              # access the tag values
                              uvwdict = currentUVWTag.GetSlow(0)
                          
                              # compute the UV value at two vertexes
                              if currentTextureTag[c4d.TEXTURETAG_PROJECTION] == c4d.TEXTURETAG_PROJECTION_UVW:
                                  spot1 = uvwdict["a"]
                                  spot2 = uvwdict["c"]
                              else:
                                  # non UVW cases should be generated on the fly during the sampling loop
                                  spot1 = 0
                                  spot2 = 0
                          
                              # get the shader associated to the color slot
                              shd = currentMaterial[c4d.MATERIAL_COLOR_SHADER]
                              # init via  InitRenderStruct()
                              initRS = c4d.modules.render.InitRenderStruct()
                              c4d.INITRENDERRESULT_OK == shd.InitRender(initRS)
                          
                              # init the ChannelData
                              chanData = c4d.modules.render.ChannelData()
                              chanData.n = c4d.Vector(0.0, 0.0, 1.0)
                              chanData.d = c4d.Vector(0.01,0.01,0.01)
                              chanData.scale = 1.0
                          
                              for j in xrange(intermediatePointsCnt + 1):
                                  for i in xrange(intermediatePointsCnt + 1):
                                      col = c4d.Vector(-1)
                                      localPOS = c4d.Vector (point1.x + (point2.x - point1.x) / intermediatePointsCnt * i, 0, point1.z + (point2.z - point1.z) / intermediatePointsCnt * j)
                                      localUVW = c4d.Vector (spot1.x + (spot2.x - spot1.x) / intermediatePointsCnt * i, spot1.y + (spot2.y - spot1.y) / intermediatePointsCnt * j, 0)
                                      
                                      # if theoretical projection is used recompute the UVW for the sampled point
                                      if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                          localUVW = ComputeFlatMapping(mappingInfo, localPOS)
                          
                                      if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_UVW or mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                          if (TestTiling(mappingInfo, localUVW)):
                                              chanData.p = localUVW
                                              col = shd.Sample(chanData)
                          
                                      print localPOS, "/", localUVW, "/",col
                          
                              # free the allocated resources
                              shd.FreeRender()
                          
                          # Execute main()
                          if __name__=='__main__':
                              main()
                          

                          For the sake of completeness, please find also attached to the test scene used to verify the code .

                          Hoping this helps you to further aim in the desired direction, give best.

                          Riccardo

                          D 1 Reply Last reply Reply Quote 3
                          • D
                            d_schmidt @r_gigante
                            last edited by

                            Hi again Riccardo, sorry about another late response but I was finally able to go through your code again. I see where I when wrong in understanding where the Flat projection stuff would take over.

                            Going through your code I saw a few things that didn't make sense to me and I just want to make sure I went about them in the right way.

                             if currentTextureTag[c4d.TEXTURETAG_PROJECTION] == c4d.TEXTURETAG_PROJECTION_UVW:
                                    spot1 = uvwdict["a"]
                                    spot2 = uvwdict["c"]
                                else:
                                    # non UVW cases should be generated on the fly during the sampling loop
                                    spot1 = 0#These need to be swapped to c4d.Vector(0), since later on it's looking for a vector.
                                    spot2 = 0
                            

                            And then the second one:

                            def ComputeFlatMapping(mappingInfo, p):
                                uv = c4d.Vector()
                                # check projection being set to flat
                                if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                    d = p * mappingInfo["im"]
                                    uv.x = (d.x * .5 - mappingInfo["ox"]) * mappingInfo["invLenx"] + 0.5
                                    uv.y = (d.y * .5 + mappingInfo["oy"]) * mappingInfo["invLeny"] + 0.5 # this needs to be changed to "-(d.y * .5 + mappingInfo["oy"]) * mappingInfo["invLeny"] + 0.5"
                                return uv
                            

                            Without changing it to minus in your checkerboard example doesn't seem to return the correct color samples. I was getting Vector(0,0,0) when I should have been getting Vector(1,1,1) and vice versa from what I could tell.

                            Swapping uv.y to the minus seemed to fix that.

                            Then I tried a new test with a new material, each quarter of it being a different color. Even with my 'fix' I was getting incorrect outputs.

                            My new test

                            What I'm getting as an output:

                            Vector(-300, 0, 200) / Vector(0.793, 0.803, 0) / Vector(1, 0, 0)
                            Vector(-400, 0, 300) / Vector(0.086, 0.803, 0) / Vector(0, 0, 0)
                            Vector(-300, 0, 300) / Vector(0.44, 0.45, 0) / Vector(0, 0, 0)
                            Vector(-200, 0, 300) / Vector(0.793, 0.096, 0) / Vector(1, 0, 0)
                            Vector(-300, 0, 400) / Vector(0.086, 0.096, 0) / Vector(0, 0, 0)
                            

                            When I expect to get:

                            Vector(-300, 0, 200) / Vector(0.793, 0.803, 0) / Vector(1, 0, 0)
                            Vector(-400, 0, 300) / Vector(0.086, 0.803, 0) / Vector(0, 0, 0)
                            Vector(-300, 0, 300) / Vector(0.44, 0.45, 0) / Vector(1, 1, 1)
                            Vector(-200, 0, 300) / Vector(0.793, 0.096, 0) / Vector(0, 0, 1)
                            Vector(-300, 0, 400) / Vector(0.086, 0.096, 0) / Vector(1, 1, 1)
                            

                            After all of that I still have one more question: where the end +.5 came from for the last bit of code. They are missing from the TexData example, but from what I can tell it needs them to function correctly.

                                  /*TexData example for Flat Projection*/
                                  Vector d = p * tdp->im;
                                  uv->x =  (d.x*0.5-tdp->ox)*lenxinv;
                                  uv->y = -(d.y*0.5+tdp->oy)*lenyinv;
                            
                                    /* as opposed to  your code*/
                                    uv.x = (d.x * .5 - mappingInfo["ox"]) * mappingInfo["invLenx"] + 0.5
                                    uv.y = (d.y * .5 + mappingInfo["oy"]) * mappingInfo["invLeny"] + 0.5
                            
                            

                            I'm just worried in doing the other projection types that there will be an unknown variable that I don't know that I need to add.

                            Again, thank you so much for all of your help, Riccardo.

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

                              Hi Dan, thanks for following up.

                              Here are my considerations based on your comments:

                              1. Without changing it to minus in your checkerboard example doesn't seem to return the correct color samples. I was getting Vector(0,0,0) when I should have been getting Vector(1,1,1) and vice versa from what I could tell.

                              I think it's a bug in how the Layer shader in your scene is sampled.
                              Using a grandient-only shader (new scene) makes the script generating consistent results
                              0_1552060778053_144ffd79-840d-4da0-9d57-e5678ee95a8c-image.png

                              In this case the "relevant" values are:

                              Vector(-300, 0, 200) / Vector(0.793, 0.803, 0) / Vector(1, 0, 0)
                              Vector(-400, 0, 300) / Vector(0.086, 0.803, 0) / Vector(0, 1, 0)
                              Vector(-300, 0, 300) / Vector(0.44, 0.45, 0) / Vector(0, 0, 1)
                              Vector(-200, 0, 300) / Vector(0.793, 0.096, 0) / Vector(1, 1, 1)
                              Vector(-300, 0, 400) / Vector(0.086, 0.096, 0) / Vector(0, 0, 1)
                              
                              1. Swapping uv.y to the minus seemed to fix that.

                              I agree, my bad there! Correct code should look like:

                              def ComputeFlatMapping(mappingInfo, p):
                                  uv = c4d.Vector()
                                  # check projection being set to flat
                                  if mappingInfo["proj"] == c4d.TEXTURETAG_PROJECTION_FLAT:
                                      d = p * mappingInfo["im"]
                                      uv.x = (d.x * .5 - mappingInfo["ox"]) * mappingInfo["invLenx"] + 0.5
                                      uv.y = -(d.y * .5 + mappingInfo["oy"]) * mappingInfo["invLeny"] + 0.5
                                  return uv
                              
                              1. After all of that I still have one more question: where the end +.5 came from for the last bit of code. They are missing from the TexData example, but from what I can tell it needs them to function correctly.

                              Here I've just debugged the values returned by the code responsible for generating UV values and I found that the values were missing a +0.5 shift.

                              Best, Riccardo

                              1 Reply Last reply Reply Quote 0
                              • D
                                d_schmidt
                                last edited by

                                Hi Riccardo,

                                Thanks for the first response. My bad with not catching that it was a layer shader bug, I figured I had done something wrong with the sampling. I'll start looking into the other projection samplings.

                                Dan

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