phong tag
-
Dear c4d fellows,
I'm building polygonal objects using c++ in cinema4d (r20).I have a small question.
I need to create phong tag to make my polygonal surface smooth.
Do I need to ascribe phong tag to each polygon constituing the surface or a single phong tag to the whole surface?I scanned through different sources of c4d forums and met no formal math definition of a phong angle.
Does somebody have a good source with explanation of phong angle in cinema 4D?Also, as far as I understand I can easily set up the normal direction to orient the polygons correctly.
Here is a very self explaining example from sdk:https://developers.maxon.net/docs/cpp/2023_2/page_manual_normaltag.html
But I heard that phong tag might override normal tags.
It is quite scary.Suppose I set up my normals for each polygon of my surface (with love and care). Then I introduce phong tag and ... all my normals will be destroyed?
Yaroslav.
-
Phong is a cheat. It doesn't destroy anything, it is just an instruction for the shader to calculate the normals at the corners of a polygon as if it bends towards the adjacent polygons. (That may effectively overwrite a normals tag, I don't know, but even if, it doesn't change the data in a normals tag.)
A Phong angle has no mathematical "definition", it is just the angle between two polygons that say: hey shader, if the angle is larger than this, then don't bend the normals of the corners but treat it as the sharp edge it is. As such, there is only one Phong angle per object. The Phong tag really only consists of that overall angle (and a few settings), not of an angle per polygon (or worse, a Phong tag per polygon...)
If that angle is not good enough, you can use Phong breaks, and define per edge where to apply a sharp break in the shading, regardless of the angle between the polys that meet in that edge.
Using a normals tag is great for imports from CAD programs, as it exactly reflect the normals set up there. It may be problematic if the user changes the object, however, as the fixed normals may not fit the changed poly flow - while the information of a Phong tag is dynamically applied by the shader, and cheat-smoothes any surface.
-
What a nice and comprehensive answer!
Thank you so much! Everything is crystal clear now!
-
Hi @Yaroslav,
thank you for reaching out to us. And thank you @Cairyn for providing an answer.
The phong normal of a vertex is defined mathematically as the linear interpolation of the vertex normals of its neighboring vertices. In practice this is carried out also respecting edge breaks and an angle limit of the triangle planes taking part in the process of finding such a neighboring vertex.
We cannot publish Cinema 4D's internal phong normal algorithm, but it probably does not differ much from what you will find commonly defined in books and web-resources. You can use Cinema 4D's variant of a neighbor storage, the
Neighbor
class to find the neighboring vertices for a given vertex. Please be aware thatNeighbor::GetPointOneRingPoints
is currently bugged, so you cannot rely on this method.It also noteworthy that a phong tag is procedural in nature, so that there is nothing to define for it other than its parameters. It also the case that manually defined normals, i.e., a
NormalTag
, will always take precedence over aPhongTag
in shading and the latter will under no circumstances overwrite the former.I hope this helps and cheers,
Ferdinand -
Thank you Ferdinand for explaining everything!
Currently, I decided to temper with the normals of my polygon object to make smoothing by hand.
However, what I noticed, is the following:Suppose I don't create normal tag and simply create a phong tag for my polyobject.
Unfortunately, despite appearing in the menu of the object, somehow it doesn't work (despite my changing the phong angle in the menu).At the moment I created a function which simulates the extrude functionality (for the reasons of plugin, I refrain from using the built in c4d extrude function )
I feed it with initial closed spline, the extrude height and precision (The way I interpolate curved elements of the spline with line elements)
void wall(BaseDocument* document, SplineObject* spline, double height, double precision) { LineObject* spline_linear = spline->GetLineObject(document, precision); int n1 = spline_linear->GetPointCount(); Vector* gp = spline_linear->GetPointW(); // define point and polygon count const Int32 polyCnt = n1; const Int32 pointCnt = 4 * n1; // create polygon object PolygonObject* const polygonObject = PolygonObject::Alloc(pointCnt, polyCnt); // insert object into the document document->InsertObject(polygonObject, nullptr, nullptr); // access point and polygon data Vector* const points3 = polygonObject->GetPointW(); CPolygon* const polygons = polygonObject->GetPolygonW(); for (int i = 0; i < n1 - 1; i++) { // set points points3[4 * i] = gp[i]; points3[4 * i + 1] = gp[i + 1]; points3[4 * i + 2] = Vector(gp[i + 1].x, 100, gp[i + 1].z); points3[4 * i + 3] = Vector(gp[i].x, 100, gp[i].z); // set polygon polygons[i] = CPolygon(4 * i, 4 * i + 1, 4 * i + 2, 4 * i + 3); } points3[4 * (n1 - 1)] = gp[n1 - 1]; points3[4 * (n1 - 1) + 1] = gp[0]; points3[4 * (n1 - 1) + 2] = Vector(gp[0].x, 100, gp[0].z); points3[4 * (n1 - 1) + 3] = Vector(gp[n1 - 1].x, 100, gp[n1 - 1].z); // set polygon polygons[n1 - 1] = CPolygon(4 * (n1 - 1), 4 * (n1 - 1) + 1, 4 * (n1 - 1) + 2, 4 * (n1 - 1) + 3); BaseTag* phongTag = polygonObject->MakeTag(Tphong); polygonObject->Message(MSG_UPDATE); }
I wonder What has gone wrong?
The thing builds nice polygonal object, but it is not smooth! ![alt text] -
Hi @Yaroslav,
the reason why this is happening is because your mesh is disjunct. In a simplified manner for two quads you want to get a mesh that looks like this, where numbers are vertices:
3───4───6 │ A │ B │ 1───2───5
But you code actually produces something like this:
3───4 7───8 │ A │ │ B │ 1───2 5───6
I.e., the polygons
A
andB
produced by your code are disjunct and therefore there won't happen any phong interpolation for your normals. Since, for example, the vertex2
has no neighboring vertex6
, as6
is only connected to5
(which happens to have the same coordinates as2
).In your
for
loop you create 4 new vertices on each iteration, which is two too many You have to either create four on the first iteration and then look back one iteration for all other iterations to get the adjacent vertices. Or first create all vertices and then create the polygons.I hope this helps and cheers,
Ferdinand -
Ferdinand,
that indeed helps a lot!
The points are indeed too many ))
I may imagine how... well, "unsofisticated" my piece of code looks.
Thank you for going so far in the explanation!Yaroslav.
-
Hi @Yaroslav,
I may imagine how... well, "unsofisticated" my piece of code looks.
no, not at all. Manually creating polygon objects can be a pretty confusing, because you always have that problem of "have I already defined that vertex?". So it's perfectly normal to trip over something like this.
Cheers,
Ferdinand -
@Yaroslav
If you are simply looking for a way to manipulate vertex normals there is a great plugin out there:
http://frostsoft.blogspot.com/2012/01/vertex-normal-tool-plugin_80.html?m=1