[Code] How do you compute weighted vertex normals?
-
@chris fullmer said:
Wouldn't it have something to do with the angle between the 2 edges of the face at that vertex * that face's normal. Something so that a small sliver of a face - only 5 degrees for example, would get its normal * 5. Then a face with 90 degrees would get its normal weight * 90. Then combine all those normals, and the vector will be greater than 1, so normalize it to scale it back down.
Would that give an appropriate weight to each face in the overall vertex normal?
What you describe is one of the methods in the links in my OP. The problem is that I don't fully understand how to implement the weighting...
-
This appear to work:
<span class="syntaxdefault"><br />def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">vertex_normal</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vertex </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">faces </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vertex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">faces<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vertex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">edges<br /> point </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vertex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">position<br /> </span><span class="syntaxkeyword">return </span><span class="syntaxdefault">nil </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">faces</span><span class="syntaxkeyword">.empty?<br /> </span><span class="syntaxdefault">normal </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Vector3d</span><span class="syntaxkeyword">.new( </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">until faces</span><span class="syntaxkeyword">.empty?<br /> </span><span class="syntaxdefault">face </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">faces</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">shift<br /> e1</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">e2 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">edges </span><span class="syntaxkeyword">& </span><span class="syntaxdefault">edges<br /> pt1 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">e1</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other_vertex</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vertex </span><span class="syntaxkeyword">).</span><span class="syntaxdefault">position<br /> pt2 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">e2</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other_vertex</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vertex </span><span class="syntaxkeyword">).</span><span class="syntaxdefault">position<br /> v1 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">point</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">vector_to</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">pt1 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">v2 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">point</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">vector_to</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">pt2 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">angle </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">v1</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">angle_between</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">v2 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">face_normal </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">normal<br /> face_normal</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">angle<br /> normal </span><span class="syntaxkeyword">+= </span><span class="syntaxdefault">face_normal<br /> end<br /> normal</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">normalize</span><span class="syntaxkeyword">!<br /> </span><span class="syntaxdefault">end<br /></span>
-
Though, the linked article seem to also take into account the face area... wonder what importance that has...
-
hmm... it must be flawed. if a face is connected to the vertex then vector1.angle_between( vector2 ) won't give the correct angle, as it only return angles between 0 - 180 degrees. Either I need to deal with each triangle in each face, or I calculate the full angle.
-
Stupid typo is my code should be
norm ****+**** fnor
not '*********
'... I've corrected the original - it should now work as expected - weighting vertex-normals dependent on the face's areas! -
This seem to account for wide angle corners:
<span class="syntaxdefault"><br /> def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">vertex_normal</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vertex </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">faces </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vertex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">faces<br /> edges </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vertex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">edges<br /> point </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vertex</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">position<br /> normal </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">Geom</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Vector3d</span><span class="syntaxkeyword">.new( </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">0 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">until faces</span><span class="syntaxkeyword">.empty?<br /> </span><span class="syntaxdefault">face </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">faces</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">shift<br /> e1</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">e2 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">edges </span><span class="syntaxkeyword">& </span><span class="syntaxdefault">edges<br /> pt1 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">e1</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other_vertex</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vertex </span><span class="syntaxkeyword">).</span><span class="syntaxdefault">position<br /> pt2 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">e2</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">other_vertex</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vertex </span><span class="syntaxkeyword">).</span><span class="syntaxdefault">position<br /> v1 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">point</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">vector_to</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">pt1 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">v2 </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">point</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">vector_to</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">pt2 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">angle </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">full_angle_between</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">v1</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">v2</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">normal </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">face_normal </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">normal<br /> face_normal</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">length </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">angle<br /> normal </span><span class="syntaxkeyword">+= </span><span class="syntaxdefault">face_normal<br /> end<br /> normal</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">normalize</span><span class="syntaxkeyword">!<br /> </span><span class="syntaxdefault">end<br /> <br /> def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">full_angle_between</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vector1</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">vector2</span><span class="syntaxkeyword">, </span><span class="syntaxdefault">normal </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">cross </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vector1 </span><span class="syntaxkeyword">* </span><span class="syntaxdefault">vector2<br /> direction </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">cross </span><span class="syntaxkeyword">% </span><span class="syntaxdefault">normal<br /> angle </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">vector1</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">angle_between</span><span class="syntaxkeyword">( </span><span class="syntaxdefault">vector2 </span><span class="syntaxkeyword">)<br /> </span><span class="syntaxdefault">angle </span><span class="syntaxkeyword">= </span><span class="syntaxdefault">360.degrees </span><span class="syntaxkeyword">- </span><span class="syntaxdefault">angle </span><span class="syntaxkeyword">if </span><span class="syntaxdefault">direction </span><span class="syntaxkeyword">> </span><span class="syntaxdefault">0.0<br /> angle<br /> end<br /></span>
-
@tig said:
Stupid typo is my code should be
norm ****+**** fnorm
not '*********
'... I've corrected the original - it should now work as expected !!!!I'll revisit your code again. http://www.bytehazard.com/code/vertnorm.html mentions that using the area still makes some faces weigh too much, but that it's not that notable. But since it looks to require less computing that checking the angles then it might be preferable.
-
hm... I added face area to the equations, but that yielded deviating normals depending how I divided the large face.
removing the face area appear to yield the exact same result.
Weighted by angle:- Vector3d(0.419345, 0.0772543, 0.904534)
- Vector3d(0.419345, 0.0772543, 0.904534)
- Vector3d(0.419345, 0.0772543, 0.904534)
Weighted by area * angle:
- Vector3d(0.324298, 0.116468, 0.938758)
- Vector3d(0.706956, 0.253896, 0.660114)
- Vector3d(0.770689, 0.276785, 0.573959)
-
I wonder if the linked article uses the face area because they computer the normals for lighting...
-
Several coplanar faces at a vertex are the same as one face of the same area as the bits? So the both area-weight-adjusted vertex-normals will be the same.
I think it is more for lighting... -
@tig said:
Several coplanar faces at a vertex are the same as one face of the same area as the bits? So the both area-weight-adjusted vertex-normals will be the same.
But if a vertex is connected to three sides, one large and two small, then using the area would make the normal lean toward the large area, would it not?
-
Not if the two small areas were equivalent to the large one... then it'd be 'balanced'...
The large area pulls it over then the 1st small are pulls it back and then the 2nd small area pulls it back again.
IF there's a large and a small area the large one 'wins'. -
By computer you mean compute?
-
@voljanko said:
By computer you mean compute?
A simple typo by tt in the original title - but we understood what he meant... -
I'm trying to follow your conversation,but not sure to understand what are you trying to do.
Do you want to align faces that are nearly aligned? -
@tig said:
Not if the two small areas were equivalent to the large one... then it'd be 'balanced'...
The large area pulls it over then the 1st small are pulls it back and then the 2nd small area pulls it back again.
IF there's a large and a small area the large one 'wins'.Yes, but when they are not, which would be in any non-regular mesh. So I still wonder why one would use area to weigh the normals.
-
-
@voljanko said:
I'm trying to follow your conversation,but not sure to understand what are you trying to do.
Do you want to align faces that are nearly aligned?No, I just want to compute the vertex normals.
In this particular case I need it to be able to calculate some of the topographical characteristic of the mesh. -
My full_angle_between code seem to not work in all scenarios... back to the drawing table...
-
Now I seemed to have corrected it. I had to ensure the vectors I used came in the same direction as the edge loop.
Advertisement