Rendering a Vertex Map [SOLVED]



  • On 31/08/2016 at 06:10, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   14+ 
    Platform:   Windows  ;   Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Hello,

    I am trying to create a shader that renders a vertex map according to its weights, similar to the C4D Vertex Map shader.

    In the output of the shader, I am stuck on how to apply the vertex map weights to the shader.

    Here is some code:

      
    if (cd->vd)
    {
    	RayObject* link = cd->vd->op->link;   // get the object to which the shader is applied
      
    	const SReal *weights;
    	for (BaseTag* baseTag = link->GetFirstTag(); baseTag; baseTag = baseTag->GetNext())
    	{
    		if (!baseTag->IsInstanceOf(Tvertexmap)) continue;
    			
    		VertexMapTag *vmapTag = (VertexMapTag * )baseTag;
    		weights = vmapTag ->GetDataAddressR();						// successfully got the weights of the vertex map
      
    		// ..................... how to render these weights????
    					
    	}
    }
      
    
    

    Any help would be greatly appreciated.



  • On 31/08/2016 at 23:29, xxxxxxxx wrote:

    Basically I am looking for a way to get the vertex index, which I would then feed into the weights and get the result.

    I could get the polygon ID with cd->vd->lhit and then GetyPolygon() and extract the vertex IDs out of it, but it renders the result polygon-rigid.

    Anyway to get the vertex index inside the shader Output ?



  • On 01/09/2016 at 01:52, xxxxxxxx wrote:

    Hello,

    as you said, you can get the ID of the hit polygon with GetPolygon(). Also you can get the RayObject that was hit with GetObject().

    Then you can use the polygon ID to access the polygon from the polygon array of the RayObject. The polygon stores the indices of the used vertices. With that vertex indices you can access the data stored in the vertex map.

    Please notice that inside a shader you do not sample a vertex. You sample a point on the surface. This point is inside the polygon that is defined by the vertices. So you have to interpolate the different values of the given vertices to end up with one value for your point. One can easily obtain the needed weights using GetWeights().

    best wishes,
    Sebastian



  • On 01/09/2016 at 02:14, xxxxxxxx wrote:

    I was missing the interpolation with GetWeights()

    Thank you for the hint Sebastian!



  • On 01/09/2016 at 08:19, xxxxxxxx wrote:

    Could you please post the working solution?
    I hate it when people ask questions and then never post the solution.

    Vector MyShader::Output(BaseShader *chn, ChannelData *cd)  
    {  
      Real px = cd->p.x;  
      Real py = cd->p.y;  
      
      Vector outputColor(0.0);  //black  
      
      //This code block runs only while rendering  
      if (cd->vd && cd->vd->op)  
      {  
          //Get the name of the host object only when scene is rendered  
          BaseObject *obj = cd->vd->op->link;  
          //GePrint(obj->GetName());  
      
          const SReal *weights;  
          for (BaseTag *baseTag = obj->GetFirstTag(); baseTag; baseTag = baseTag->GetNext())  
          {  
              if (!baseTag->IsInstanceOf(Tvertexmap)) continue;  
      
              VertexMapTag *vmapTag = (VertexMapTag * )baseTag;  
              weights = vmapTag->GetDataAddressR();  
      
              LONG count = vmapTag->GetDataCount();  
              for (LONG i = 0; i<count; i++)  
              {  
                  GePrint(RealToString(weights[i]));  //Print the weight values in the vmapTag                 
              }  
                
              RayHitID hid = cd->vd->lhit;  
              RayObject *robj = hid.GetObject(cd->vd);  //The object            
              LONG poly = hid.GetPolygon();             //The polygons hit by the render rays  
      
      
              //Now what?  
      
       
          }  
      
      }  
      
      return outputColor;
    

    Thanks,
    -ScottA



  • On 01/09/2016 at 10:26, xxxxxxxx wrote:

    Sorry about that. It wasn't intentional.

    Anyway, you are almost there. You just need to calculate the barycentric weights with GetWeights(), like this:

      
    	PolygonObject* pobj = ToPoly(link);
    	CPolygon *polys = pobj->GetPolygonW();
      
    	CPolygon poly = polys[polyID]; // polyID is the polygon index
      
    	// the following is inspired by the SDK documentation
      
    	RayPolyWeight weight;
    	cd->vd->GetWeights(cd->vd->lhit, cd->vd->p, &weight);
      
    	Real rWeightA, rWeightB, rWeightC, rWeightD;
    	LONG lIndexA = poly.a;
    	LONG lIndexB = poly.b;
    	LONG lIndexC = poly.c;
    	LONG lIndexD = poly.d; 
    	rWeightA = weights[lIndexA];
    	rWeightB = weights[lIndexB];
    	rWeightC = weights[lIndexC];
    	rWeightD = weights[lIndexD];
    	
    	outputColor = weight.wa * rWeightA + weight.wb * rWeightB + weight.wc * rWeightC + weight.wd * rWeightD;
      
    
    

    I hope this helps you out.



  • On 01/09/2016 at 11:34, xxxxxxxx wrote:

    Thanks a lot for the missing pieces. I'm sure it will help other people too. 🍺

    My working code:

    //This code maps and renders the color values from a Tvertexmap tag to a specific polygon on an object  
      
    Vector MyShader::Output(BaseShader *chn, ChannelData *cd)  
    {  
      //These are not used..For reference purposes only  
      //Real px = cd->p.x;  
      //Real py = cd->p.y;  
      
      //Start out with everything rendered black  
      Vector outputColor(0);  
      
      //This code block runs only while rendering  
      if (cd->vd && cd->vd->op)  
      {  
          //Get the host object only when the scene is rendered  
          BaseObject *obj = cd->vd->op->link;  
      
          //Cast it to a polygon type object  
          PolygonObject *pobj = ToPoly(obj);  
      
          //The specific polygon that we want to apply the vertex map tag's values to  
          //Change as desired  
          LONG polyID = 0;  
          CPolygon *polys = pobj->GetPolygonW();          
          CPolygon poly = polys[polyID];  
      
          //Not used..For reference purposes only          
          //RayHitID hid = cd->vd->lhit;  
          //RayObject *robj = hid.GetObject(cd->vd);  //The object            
          //LONG poly = hid.GetPolygon();             //The polygons hit by the render rays  
      
          const SReal *weights;  
          for (BaseTag *baseTag = obj->GetFirstTag(); baseTag; baseTag = baseTag->GetNext())  
          {  
              if (!baseTag->IsInstanceOf(Tvertexmap)) continue;  
      
              VertexMapTag *vmapTag = (VertexMapTag * )baseTag;  
              weights = vmapTag->GetDataAddressR();  
                
              RayPolyWeight weight;  
              cd->vd->GetWeights(cd->vd->lhit, cd->vd->p, &weight);  
      
              Real rWeightA, rWeightB, rWeightC, rWeightD;  
              LONG lIndexA = poly.a;  
              LONG lIndexB = poly.b;  
              LONG lIndexC = poly.c;  
              LONG lIndexD = poly.d;  
              rWeightA = weights[lIndexA];  
              rWeightB = weights[lIndexB];  
              rWeightC = weights[lIndexC];  
              rWeightD = weights[lIndexD];  
              outputColor = weight.wa * rWeightA + weight.wb * rWeightB + weight.wc * rWeightC + weight.wd * rWeightD;  
          }  
      }  
      
      return outputColor;  
    }
    

    -ScottA


Log in to reply