Point normals (again)
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2009 at 04:15, xxxxxxxx wrote:
Quote: Originally posted by c4dJack on 25 January 2009
>
> * * *
>
> Cool, thank you very much
>
> I'll check that out.
>
> With CreatePhongNormals() I have the problem that the normals often seem to point into senseless directions. As I understood it, CreatePhongNormals() will return an array of normals, one for each point of the mesh. By weighting the normals of the points of a polygon with the barycentric coordinates, I should get a good normal for each position on a polygon. But I just get crap
>
> Have to figure out what going wrong, you are right. Anyway, a fallback solutions for meshes without Phong tag is a good think, so thanks again!
>
> Greetings,
> Jack
>
> * * *
See your comment in bold above... this is a misunderstanding, or at least a mis-statement.
The array has one for each point of every polygon (quad) in the mesh. For example, let's say the mesh is 2 side-by-side quads, that share a common edge where they meet, so the mesh has 6 vertices.
The array returned from CreatePhongNormals() has 8 (eight) normals in it - one for each vertex of each polygon - not 6 (if the mesh was 2 triangles, you'd still get 8 normals).
The normals are in the same order that the vertex indices are, so for example://--------- S N I P ---------- NormalStruct *pNorms = (NormalStruct * )op->CreatePhongNormals(); if( !pNorms ) pNorms = ComputeVertexNormals(op); // call the code above, after fixing it up a bit if( !pNorms ) { complain(); return; } Vector *pVertices = op->GetPointW(); CPolygon *pPolys = op->GetPolygonW(); LONG numPolys = op->GetPolygonCount(); LONG polyNdx; for(polyNdx=0; polyNdx<numPolys ; polyNdx++) { Vector pVert; Vector pNorm; pVert = pVertices[pPolys[polyNdx].a]; pNorm = pNorms[polyNdx].a; do_something(pVert, pNorm); pVert = pVertices[pPolys[polyNdx].b]; pNorm = pNorms[polyNdx].b; do_something(pVert, pNorm); pVert = pVertices[pPolys[polyNdx].c]; pNorm = pNorms[polyNdx].c; do_something(pVert, pNorm); if( pPolys[polyNdx].c != pPolys[polyNdx].d ) { pVert = pVertices[pPolys[polyNdx].d]; pNorm = pNorms[polyNdx].d; do_something(pVert, pNorm); } } //--------- S N I P ----------
Does that help?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2009 at 04:22, xxxxxxxx wrote:
...also note that the above implies that you will likely end up with many 'duplicate' normals (anywhere polygons share a common vertex and there is no phong-edge-break). This is fine if you're just interested in what the normals are, but may require further processing if you want to eliminate duplicates and convert it to a table lookup (ie. my Riptide / Riptide Pro .obj exporters do that before saving the normals).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2009 at 04:43, xxxxxxxx wrote:
Oops.. I left out something in my latest code sample above... whether you get a buffer returned from CreatePhongNormals() or my other code above, in each case be sure to GeFree() the buffer when done :).
EDIT: I see that I also left off the '*' on Vector *pVert ; Vector *pNorm ; declarations above (I typed that example in by hand - spur of the moment).
EDIT2: Actually, because of the way the rest of that is coded, those would just be Vectors instead of pointers to Vectors, so just ignore the 'p' in front of those variable names . -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2009 at 05:00, xxxxxxxx wrote:
Ah!! OK, then either I misunderstood the documentation, or it should be made more clear there. Thanks again! This is the best "Point Normals" thread ever
Additional question: What if my mesh is triangulated? Regarding your example with 2 quad polygons = 6 vertices = 8 elements in CreatePhongNormals() array... if I triangulate your example mesh, I would get 4 tri polygons = 6 vertices = 12 elements in normal array. Right? Because there are three vertices per polygon? Or would I still get 4 vertices per polygon (= 16 elements), just the 4th one is not used?
Cheers,
Jack -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2009 at 05:25, xxxxxxxx wrote:
Quote: Originally posted by c4dJack on 25 January 2009
>
> * * *
>
> ...I would get 4 tri polygons = 6 vertices = 12 elements in normal array. Right? Because there are three vertices per polygon? Or would I still get 4 vertices per polygon (= 16 elements), just the 4th one is not used?
>
>
> * * *Underlined.
Basically, you always get 4 x number_of_polygons ... one for each (a,b,c,d) corner of the quad - whether the 4th is used, or not.
As an aside, this is also how the UVW Tag works... except that it has routines to let you get each uv-polygon: UVWStruct uvw = pUVs->Get(polyNdx); I modeled the NormalStruct on the UVWStruct -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 25/01/2009 at 05:37, xxxxxxxx wrote:
It's best to think of it this way:
CPolygon = vertex-polygon
UVWStruct = uv-polygon
NormalStruct = normal-polygon
...all of the above always have 4 elements (a,b,c,d). The only practical difference is that the CPolygon contains indices into the vertex array as it's elements and the other two contain the actual UV/Normal Vector itself instead of an index, as the 4 elements. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 10:40, xxxxxxxx wrote:
Sorry, to push this up again, but:
What , if I don't work with polygons, but just with points? I can't use NormalStruct results here, since I just have a point index. How can I find out the Vertex Normal for a specific point?
Thanks in advance!
Cheers,
Jack -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 11:33, xxxxxxxx wrote:
I'm trying to understand this, so I wrote a function to get the Vertex Normal of just one point (I know this will be slow if I want them for several points, but it's just a test).
Strangely, I get the weirdest results. The normals point in all kinds of directions, but not into the correct one.
>
\> Vector GetVertexNormal(LONG PointIndex, PolygonObject \*op) \> { \> // Variables \> CPolygon \*pNeighborPoly; \> Neighbor neighbor; \> LONG j, faceCnt, \*pFaces = NULL; \> Vector v1, v2, vNorm = Vector(0,0,0); \> CPolygon \*m_pPolys = op->GetPolygonW(); \> Vector \*m_pPoints = op->GetPointW(); \> \> // Init Neighbor class \> if (!neighbor.Init(op->GetPointCount(), m_pPolys, op->GetPolygonCount(), NULL)) \> return vNorm; \> \> // Get polygons attached to point \> neighbor.GetPointPolys(PointIndex, &pFaces;, &faceCnt;); \> \> for(j=0; j<faceCnt; j++) \> { \> pNeighborPoly = &m;\_pPolys[pFaces[j]]; \> \> // Compute face normal \> v1 = m_pPoints[pNeighborPoly->b] - m_pPoints[pNeighborPoly->a]; \> v2 = m_pPoints[pNeighborPoly->c] - m_pPoints[pNeighborPoly->a]; \> vNorm += v1 % v2; // get cross-product \> } \> vNorm /= faceCnt; \> \> // Return resuling normal vector \> return !vNorm; \> } \>
Thanks for any help!
Greetings,
Jack -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 12:07, xxxxxxxx wrote:
I'm just waking up, but your code "looks" ok (should be working), so I'm wondering if maybe the code that's asking for 'some' point's normal is maybe asking about the wrong point? (or something).
Anyway, for debugging purposes, I sometimes call a utility routine like this...
>\> \> \> \> > //------------------------------------------------------------- \> > // AddSplineObject() \> > //------------------------------------------------------------- \> > void AddSplineObject(BaseDocument *pDoc, const String& name, const Vector& pos, const Vector& axis, const Real& length) \> > { \> > SplineObject *pSpline = SplineObject::Alloc(2,Tlinear); // allocate spline object \> > if( pSpline ) \> > { \> > if( pSpline->MakeVariableTag(Tsegment,1) ) \> > { \> > Vector *padr = pSpline->GetPointW(); \> > Segment *sadr = pSpline->GetSegmentW(); \> \> \> \> \> sadr[0].cnt = 2; \> > sadr[0].closed = false; \> \> \> \> \> padr[0] = pos; \> > padr[1] = pos + (axis * length); \> \> \> \> \> pSpline->SetName(name); \> > pDoc->InsertObject(pSpline, NULL, NULL); \> > pDoc->AddUndo(UNDO_NEW, pSpline); \> > pSpline->Message(MSG_UPDATE); \> > } \> > } \> > } \> > \> \>
...you can pass the point your asking about as the 'pos' arg, and the generated normal as the 'axis' arg and use 1 or 10 or whatever for the length. It adds a spline object, showing a visual representation of the normal (be sure to either StartUndo() or comment out that AddUndo() line).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 12:16, xxxxxxxx wrote:
....in your code, I'd also change:
vNorm = Vector(0,0,0); to vNorm = Vector(0,1,0); //default to pointing straight up
...and also, after:
// Get polygons attached to point neighbor.GetPointPolys(PointIndex, &pFaces, &faceCnt); ...you should add: if( !faceCnt ) return vNorm;
...to avoid any potential divide-by-zero below there.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 12:24, xxxxxxxx wrote:
Also keep in mind that if edge-breaks are involved, each vertex can have more than one Normal. In other words, (vertex) Normals are really polygon-relative - none of the above code takes edge-breaks into account, so you end up with smoothed (averaged) normals at each vertex.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 14:40, xxxxxxxx wrote:
In this particular case I won't care about edge breaks. Each Vertex Normal should just be the average of it's surrounding polygons.
But I HAVE to get the normal vectors by addressing them with the point index.
My code is now like this.
I pass an initialized Neighbor class object to the function, that speeds it up a lot. Anyway, the normals still point into totally stupid directions.Also I noticed, that faceCnt is always 3 for each point. But the geometry is (for testing) just a cube subdivided object, so there *should* be 4 faces for each point.
>
Vector GetVertexNormal(LONG PointIndex, PolygonObject \*op, Neighbor \*neighbor) \> { \> // Variables \> CPolygon \*pNeighborPoly; \> LONG j, faceCnt, \*pFaces = NULL; \> Vector v1, v2, vNorm = Vector(C_FLOATZERO, C_FLOATONE, C_FLOATZERO); \> CPolygon \*m_pPolys = op->GetPolygonW(); \> Vector \*m_pPoints = op->GetPointW(); \> \> // Get polygons attached to point \> neighbor->GetPointPolys(PointIndex, &pFaces;, &faceCnt;); \> if(!faceCnt) return vNorm; \> \> for(j=0; j<faceCnt; j++) \> { \> pNeighborPoly = &m;\_pPolys[pFaces[j]]; \> \> // Compute face normal \> v1 = m_pPoints[pNeighborPoly->b] - m_pPoints[pNeighborPoly->a]; \> v2 = m_pPoints[pNeighborPoly->c] - m_pPoints[pNeighborPoly->a]; \> vNorm += v1 % v2; // get cross-product \> } \> vNorm /= faceCnt; \> \> // Return resuling normal vector \> return !vNorm; \> }
Greetings,
Jack -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 05/08/2009 at 15:10, xxxxxxxx wrote:
Oh wait. My mistake. Code works fine. If I modify the geometry while calculating an array of Vertex normals, it's no wonder they point into seemingly stupid directions.
Thanks a thousand times!
Cheers,
Jack -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 06/08/2009 at 00:32, xxxxxxxx wrote:
That looks ok to me. Just some stuff you can improve (taking triangles or quadrangles into account) :
>
\> for (j=0; j<faceCnt; j++) \> { \> pNeighborPoly = &m;\_pPolys[pFaces[j]]; \> \> // Compute face normal \> if (pNeighborPoly->c == pNeighborPoly->d) //triangle \> { \> v1 = m_pPoints[pNeighborPoly->b] - m_pPoints[pNeighborPoly->a]; \> v2 = m_pPoints[pNeighborPoly->c] - m_pPoints[pNeighborPoly->a]; \> } \> else //quadrangle \> { \> v1 = m_pPoints[pNeighborPoly->c] - m_pPoints[pNeighborPoly->a]; \> v2 = m_pPoints[pNeighborPoly->d] - m_pPoints[pNeighborPoly->b]; \> } \> \> vNorm += v1 % v2; // get cross-product \> } \> \> //vNorm /= faceCnt; not necessary, normalizing is enough \> \> // Return resuling normal vector \> return !vNorm; \>
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 06/08/2009 at 03:07, xxxxxxxx wrote:
Quote: Originally posted by Giblet on 05 August 2009
>
> * * *
>
> ....in your code, I'd also change:
>
>\> \> \> \> > vNorm = Vector(0,0,0); \> \> \> \> \> to \> \> \> \> \> vNorm = Vector(0,1,0); //default to pointing straight up \> \> \> \> .... \> > \> \>
>
> * * *
D'oh! Ignore the above suggestion... or at least reset it to all zeros before you enter that loop below there - I was just trying to account for points not connected to ANY polygons, but you should probably handle that error condition differently anyway.
@Matthias - thanks for the corrections/additions... I'd forgotten about th normalization, so that extra divide at the end of the loop is not needed.