# Difference between revisions of "Calculating a Surface Normal"

From OpenGL.org

Blue Prawn (Talk | contribs) m (→Newell's Method: shorter lines to fit in the browser window) |
m (added perl version) |
||

(2 intermediate revisions by 2 users not shown) | |||

Line 14: | Line 14: | ||

Given that a vector is a structure composed of three floating point numbers and a Triangle is a structure composed of three Vectors, based on the above definitions: | Given that a vector is a structure composed of three floating point numbers and a Triangle is a structure composed of three Vectors, based on the above definitions: | ||

− | < | + | <source lang="pascal"> |

Begin Function CalculateSurfaceNormal (Input Triangle) Returns Vector | Begin Function CalculateSurfaceNormal (Input Triangle) Returns Vector | ||

Line 27: | Line 27: | ||

End Function | End Function | ||

− | </ | + | </source> |

== Newell's Method == | == Newell's Method == | ||

Line 33: | Line 33: | ||

Also you can use a Newell's method for an arbitrary 3D polygon. | Also you can use a Newell's method for an arbitrary 3D polygon. | ||

− | < | + | <source lang="pascal"> |

Begin Function CalculateSurfaceNormal (Input Polygon) Returns Vector | Begin Function CalculateSurfaceNormal (Input Polygon) Returns Vector | ||

Line 43: | Line 43: | ||

Set Vertex Next to Polygon.verts[(Index plus 1) mod Polygon.vertexNumber] | Set Vertex Next to Polygon.verts[(Index plus 1) mod Polygon.vertexNumber] | ||

− | Set Normal.x to Sum of Normal.x and (multiply (Current.y minus Next.y) by (Current.z plus Next.z) | + | Set Normal.x to Sum of Normal.x and (multiply (Current.y minus Next.y) by (Current.z plus Next.z)) |

− | Set Normal.y to Sum of Normal.y and (multiply (Current.z minus Next.z) by (Current.x plus Next.x) | + | Set Normal.y to Sum of Normal.y and (multiply (Current.z minus Next.z) by (Current.x plus Next.x)) |

− | Set Normal.z to Sum of Normal.z and (multiply (Current.x minus Next.x) by (Current.y plus Next.y) | + | Set Normal.z to Sum of Normal.z and (multiply (Current.x minus Next.x) by (Current.y plus Next.y)) |

End Cycle | End Cycle | ||

Line 52: | Line 52: | ||

End Function | End Function | ||

− | </ | + | </source> |

+ | |||

+ | |||

+ | |||

+ | == Perl version for a triangle: == | ||

+ | <source lang="perl"> | ||

+ | sub CalculateSurfaceNormal { | ||

+ | my($p1,$p2,$p3)=@_; my($x,$y,$z)=(0,1,2); | ||

+ | |||

+ | my($N,$U,$V); | ||

+ | |||

+ | $U->[$x]=$p2->[$x] - $p1->[$x]; | ||

+ | $U->[$y]=$p2->[$y] - $p1->[$y]; | ||

+ | $U->[$z]=$p2->[$z] - $p1->[$z]; | ||

+ | |||

+ | $V->[$x]=$p3->[$x] - $p1->[$x]; | ||

+ | $V->[$y]=$p3->[$y] - $p1->[$y]; | ||

+ | $V->[$z]=$p3->[$z] - $p1->[$z]; | ||

+ | |||

+ | $N->[$x]=$U->[$y]*$V->[$z] - $U->[$z]*$V->[$y]; | ||

+ | $N->[$y]=$U->[$z]*$V->[$x] - $U->[$x]*$V->[$z]; | ||

+ | $N->[$z]=$U->[$x]*$V->[$y] - $U->[$y]*$V->[$x]; | ||

+ | |||

+ | return ($N->[$x],$N->[$y],$N->[$z]); | ||

+ | } | ||

+ | |||

+ | # example usage:- | ||

+ | print join("\t", &CalculateSurfaceNormal([qw( 1 0 0 )], | ||

+ | [qw( 0 1 0 )], | ||

+ | [qw( 0 0 1 )] )); | ||

+ | </source> | ||

+ | |||

[[Category:Algorithm]] | [[Category:Algorithm]] |

## Latest revision as of 10:49, 13 January 2013

## Algorithm

A surface normal for a triangle can be calculated by taking the vector cross product of two edges of that triangle. The order of the vertices used in the calculation will affect the direction of the normal (in or out of the face w.r.t. winding).

So for a triangle p1, p2, p3, if the vector *U* = p2 - p1 and the vector *V* = p3 - p1 then the normal *N* = *U X V* and can be calculated by:

*N*x = *U*y*V*z - *U*z*V*y

*N*y = *U*z*V*x - *U*x*V*z

*N*z = *U*x*V*y - *U*y*V*x

## Pseudo-code

Given that a vector is a structure composed of three floating point numbers and a Triangle is a structure composed of three Vectors, based on the above definitions:

```
Begin Function CalculateSurfaceNormal (Input Triangle) Returns Vector
Set Vector U to (Triangle.p2 minus Triangle.p1)
Set Vector V to (Triangle.p3 minus Triangle.p1)
Set Normal.x to (multiply U.y by V.z) minus (multiply U.z by V.y)
Set Normal.y to (multiply U.z by V.x) minus (multiply U.x by V.z)
Set Normal.z to (multiply U.x by V.y) minus (multiply U.y by V.x)
Returning Normal
End Function
```

## Newell's Method

Also you can use a Newell's method for an arbitrary 3D polygon.

```
Begin Function CalculateSurfaceNormal (Input Polygon) Returns Vector
Set Vertex Normal to (0, 0, 0)
Begin Cycle for Index in [0, Polygon.vertexNumber)
Set Vertex Current to Polygon.verts[Index]
Set Vertex Next to Polygon.verts[(Index plus 1) mod Polygon.vertexNumber]
Set Normal.x to Sum of Normal.x and (multiply (Current.y minus Next.y) by (Current.z plus Next.z))
Set Normal.y to Sum of Normal.y and (multiply (Current.z minus Next.z) by (Current.x plus Next.x))
Set Normal.z to Sum of Normal.z and (multiply (Current.x minus Next.x) by (Current.y plus Next.y))
End Cycle
Returning Normalize(Normal)
End Function
```

## Perl version for a triangle:

```
sub CalculateSurfaceNormal {
my($p1,$p2,$p3)=@_; my($x,$y,$z)=(0,1,2);
my($N,$U,$V);
$U->[$x]=$p2->[$x] - $p1->[$x];
$U->[$y]=$p2->[$y] - $p1->[$y];
$U->[$z]=$p2->[$z] - $p1->[$z];
$V->[$x]=$p3->[$x] - $p1->[$x];
$V->[$y]=$p3->[$y] - $p1->[$y];
$V->[$z]=$p3->[$z] - $p1->[$z];
$N->[$x]=$U->[$y]*$V->[$z] - $U->[$z]*$V->[$y];
$N->[$y]=$U->[$z]*$V->[$x] - $U->[$x]*$V->[$z];
$N->[$z]=$U->[$x]*$V->[$y] - $U->[$y]*$V->[$x];
return ($N->[$x],$N->[$y],$N->[$z]);
}
# example usage:-
print join("\t", &CalculateSurfaceNormal([qw( 1 0 0 )],
[qw( 0 1 0 )],
[qw( 0 0 1 )] ));
```