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)
{

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
//GePrint(obj->GetName());

const SReal *weights;
for (BaseTag *baseTag = obj->GetFirstTag(); baseTag; baseTag = baseTag->GetNext())
{
if (!baseTag->IsInstanceOf(Tvertexmap)) continue;

VertexMapTag *vmapTag = (VertexMapTag * )baseTag;

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:

``````
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

{
//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

//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;

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