Any reliable polygon normal calculation code?

Posted by Jenko on Game Development See other posts from Game Development or by Jenko
Published on 2011-02-06T05:38:51Z Indexed on 2011/02/06 7:33 UTC
Read the original article Hit count: 346

Filed under:
|
|
|

Do you have any reliable face normal calculation code?

I'm using this but it fails when faces are 90 degrees upright or similar.

        // the normal point
        var x:Number = 0;
        var y:Number = 0;
        var z:Number = 0;

        // if is a triangle with 3 points
        if (points.length == 3) {

            // read vertices of triangle
            var Ax:Number, Bx:Number, Cx:Number;
            var Ay:Number, By:Number, Cy:Number;
            var Az:Number, Bz:Number, Cz:Number;
            Ax = points[0].x;   Bx = points[1].x;   Cx = points[2].x;
            Ay = points[0].y;   By = points[1].y;   Cy = points[2].y;
            Az = points[0].z;   Bz = points[1].z;   Cz = points[2].z;

            // calculate normal of a triangle
            x = (By - Ay) * (Cz - Az) - (Bz - Az) * (Cy - Ay);
            y = (Bz - Az) * (Cx - Ax) - (Bx - Ax) * (Cz - Az);
            z = (Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax);

        // if is a polygon with 4+ points
        }else if (points.length > 3){

            // calculate normal of a polygon using all points
            var n:int = points.length;          
            x = 0;
            y = 0;
            z = 0

            // ensure all points above 0
            var minx:Number = 0, miny:Number = 0, minz:Number = 0;
            for (var p:int = 0, pl:int = points.length; p < pl; p++) {
                var po:_Point3D = points[p] = points[p].clone();
                if (po.x < minx) {  minx = po.x;     }
                if (po.y < miny) {  miny = po.y;     }
                if (po.z < minz) {  minz = po.z;     }
            }
            if (minx > 0 || miny > 0 || minz > 0){
                for (p = 0; p < pl; p++) {
                    po = points[p];
                    po.x -= minx;
                    po.y -= miny;
                    po.z -= minz;
                }
            }

            var cur:int = 1, prev:int = 0, next:int = 2;
            for (var i:int = 1; i <= n; i++) {

                // using Newell method
                x += points[cur].y * (points[next].z - points[prev].z);
                y += points[cur].z * (points[next].x - points[prev].x);
                z += points[cur].x * (points[next].y - points[prev].y);
                cur = (cur+1) % n;
                next = (next+1) % n;
                prev = (prev+1) % n;
            }
        }

        // length of the normal
        var length:Number = Math.sqrt(x * x + y * y + z * z);

        // if area is 0
        if (length == 0) {
            return null;

        }else{
            // turn large values into a unit vector
            x = x / length;
            y = y / length;
            z = z / length;
        }

© Game Development or respective owner

Related posts about 3d

Related posts about normals