POV-Ray : Newsgroups : povray.binaries.images : Friday abstract preview: fluffy knot : Re: Friday abstract preview: fluffy knot Server Time21 Feb 2024 22:30:20 EST (-0500)
 Re: Friday abstract preview: fluffy knot
 From: Bald Eagle Date: 25 Feb 2023 18:10:00 Message:
Cousin Ricky <ric### [at] yahoocom> wrote:
> I don't know whether to say this is late, because I didn't get it posted
> on Friday, or early, because the object isn't quite debugged.  So I'm
> calling it a preview of some future Friday.
>
> The problem is that I can't get the fur to align at the loop join.

Nice.

I had that thread where I showed the normals on the bunny mesh - can't find that
in a search - no surprise there.

But I also found this recently, and wonder if this might help:

https://www.realtimerendering.com/resources/RTNews/html/rtnv7n5.html

A better method:

Consistently orient all of the polygons (you need to know which edges are shared
to do this, and this isn't possible for some objects-- e.g. mobius strips, Klein
bottles, etc).

Now, choose the point 'P' in the middle of the bounding box of the object. For
each triangle in the object, compute a signed volume for the tetrahedron formed
by the triangle and P. Arrange your calculation so that the area will be
positive if P is left-hand-side of the triangle and negative if P is on the
right-hand-side of the triangle. (if your triangle is ABC, then doing
(AB.cross.BC).dot.P will have this property).

Add up all of the volumes. If the result is positive, then the normals are
oriented 'outside'. If the result is negative, then the normals are oriented
'inside'. If the result is zero or very close to zero, then the object is flat
or has just as many concave parts as convex parts.

This will always work for completely enclosed objects, and does the right thing
for surfaces-- it chooses the orientation that marks the surface 'most convex'.
It works for self-intersecting objects.

Here's the code I use:
(If you have Inventor 1, this is in the 'ivnorm' code:)
int i, j;

int total_v = 0;
SbVec3f average(0.0, 0.0, 0.0);

for (j = 0; j < length(); j++)
{
Face *f = (*this)[j];
if (f->degenerate) continue;

for (i = 0; i < f->nv; i++)
{
average += verts[f->v[i]];
++total_v;
}
}
average /= (float) total_v;

float result = 0.0;

for (j = 0; j < length(); j++)
{
Face *f = (*this)[j];
if (f->degenerate) continue;

for (i = 1; i < f->nv-1; i++)
{
SbVec3f v1 = verts[f->v[0]] - average;
SbVec3f v2 = verts[f->v[i]] - average;
SbVec3f v3 = verts[f->v[i+1]] - average;

float t = (v1.cross(v2)).dot(v3);
if (f->orientation == Face::CCW)
{
result += t;
}
else if (f->orientation == Face::CW)
{
result -= t;
}
else
{
assert(0);
}
}
}
return result > 0;

- BW