forked from: away3d classifySphere() fix

by yonatan2 forked from away3d classifySphere() fix (diff: 20)
♥0 | Line 176 | Modified 2012-04-11 00:04:45 | MIT License
play

ActionScript3 source code

/**
 * Copyright yonatan2 ( http://wonderfl.net/user/yonatan2 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/uYMy
 */

// forked from yonatan2's away3d classifySphere() fix
// forked from yonatan's flash on 2012-4-8
package {
    import flash.events.*;
    import flash.geom.*;
    import away3d.core.geom.*;
    import com.bit101.components.*;

    public class FlashTest extends VBox {
        private var txt:TextArea;
        private var sliX:HUISlider, sliY:HUISlider, sliZ:HUISlider, sliRad:HUISlider, sliFOV:HUISlider, sliZN:HUISlider, sliZF:HUISlider;
        private var f:FrustumPatch = new FrustumPatch;
        private var sigl:SiGLCore = new SiGLCore(465,465);
        
        public function FlashTest() {
            width=height=465;

            sliX = new HUISlider(this, 0, 0, "X", classify);
            sliY = new HUISlider(this, 0, 0, "Y", classify);
            sliZ = new HUISlider(this, 0, 0, "Z", classify);
            sliRad = new HUISlider(this, 0, 0, "Radius", classify);
            sliFOV = new HUISlider(this, 0, 0, "FOV", classify);
            sliZN = new HUISlider(this, 0, 0, "near Z", classify);
            sliZF = new HUISlider(this, 0, 0, "far Z", classify);
            for each(var s:HUISlider in [sliX, sliY, sliZ]) {
                s.minimum = -1000; s.maximum = 1000;
            }
            sliRad.maximum = 500; sliRad.value = 100;
            sliFOV.minimum = 1; sliFOV.maximum = 180; sliFOV.value = 45;
            sliZN.minimum = -1000; sliZN.maximum = 1000; sliZN.value = sigl.zNear;
            sliZF.minimum = -1000; sliZF.maximum = 1000; sliZF.value = sigl.zFar;
            
            txt = new TextArea(this);
            txt.height = 200; txt.width=465;
            

            //sliY.value = 800; sliX.value = 230; classify(null); // should be OUT
        }
        
        private function classify(e:Event):void {
            sigl.fieldOfView = sliFOV.value;
            sigl.setZRange(sliZN.value, sliZF.value);
            sigl._updateProjectionMatrix();
            sliZN.value = sigl.zNear;
            f.extractFromMatrix(sigl.projectionMatrix);
            txt.text = "";
            //trace("near z", sigl.zNear);
            //trace("far z", sigl.zFar);
            //trace("planes: (a,b,c,d)");
            //for each(var p:Plane3D in f.planes) trace(p.a, p.b, p.c, p.d);
            trace("original");
            trace(["OUT", "IN", "INTERSECT"][f.classifySphere(new Vector3D(sliX.value, sliY.value, sliZ.value), sliRad.value)]);
            trace("patched");
            trace(["OUT", "IN", "INTERSECT"][f.classifySpherePatch(new Vector3D(sliX.value, sliY.value, sliZ.value), sliRad.value)]);
            trace("patched, negated Z");
            trace(["OUT", "IN", "INTERSECT"][f.classifySpherePatch(new Vector3D(sliX.value, sliY.value, -sliZ.value), sliRad.value)]);
        }
        
        private function trace(...a):void {
            txt.text += a.join(" ") + "\n";
        }
    }
}

import flash.display.*;
import flash.geom.*;
import away3d.core.geom.*;

class FrustumPatch extends Frustum {
    /**
     * Classify this sphere against this frustum
     * @return int Frustum.IN, Frustum.OUT or Frustum.INTERSECT
     */
    public function classifySpherePatch(center:Vector3D, radius:Number):int
    {
        var _plane:Plane3D, _distance:Number, intersect:Boolean = false;
        for each(_plane in planes) {
            _distance = _plane.distance(center);
                               
            if(_distance < -radius)
                return OUT;
                                
            if(Math.abs(_distance) < radius)
                intersect = true;
        }
                        
        return intersect ? INTERSECT : IN;
    }
}


/** SiGLCore provides basic matrix operations. */
class SiGLCore {
    // variables ----------------------------------------
    public var modelViewMatrix:SiGLMatrix = new SiGLMatrix(), projectionMatrix:SiGLMatrix = new SiGLMatrix();
    public var viewWidth:Number, viewHeight:Number;
    public var defaultCameraMatrix:SiGLMatrix = new SiGLMatrix(), matrix:SiGLMatrix = modelViewMatrix;
    private var _mvpMatrix:SiGLMatrix = new SiGLMatrix(), _mvpdir:Boolean, _2d:Number, _2r:Number;
    private var _mag:Number, _zNear:Number, _zFar:Number, _fieldOfView:Number, _fl:Number, _alignTopLeft:Boolean = false;
    // properties ----------------------------------------
    public function get modelViewProjectionMatrix() : SiGLMatrix {
        if (_mvpdir) {
            _mvpMatrix.copyFrom(projectionMatrix);
            _mvpMatrix.prepend(modelViewMatrix);
            _mvpdir = false;
        }
        return _mvpMatrix;
    }
    public function get focalLength() : Number { return _fl; }
    public function get zNear() : Number { return _zNear; }
    public function get zFar() : Number { return _zFar; }
    public function get align() : String { return (_alignTopLeft) ? "topLeft" : "center"; }
    public function set align(mode:String) : void { _alignTopLeft = (mode == "topLeft"); _updateProjectionMatrix(); }
    public function get matrixMode() : String { return (matrix === projectionMatrix) ? "projection" : "modelView"; }
    public function set matrixMode(mode:String) : void { matrix = (mode == "projection") ? projectionMatrix : modelViewMatrix; }
    public function get angleMode() : String { return (_2r == 1) ? "radian" : "degree"; }
    public function set angleMode(mode:String) : void { _2d = (mode == "radian") ? 57.29577951308232 : 1; _2r = (mode == "radian") ? 1 : 0.017453292519943295; }
    public function get fieldOfView() : Number { return _fieldOfView / _2r; }
    public function set fieldOfView(fov:Number) : void { _fieldOfView = fov * _2r; _updateProjectionMatrix(); }
    public function get magnification() : Number { return _mag; }
    public function set magnification(mag:Number) : void { _mag = mag; _updateProjectionMatrix(); }
    // constructor ----------------------------------------
    function SiGLCore(width:Number=1, height:Number=1) {
        viewWidth = width; viewHeight = height;
        angleMode = "degree"; _mag = 1;
        _zNear = -1000; _zFar = 200;
        modelViewMatrix.identity();
        _mvpdir = true;
        this.fieldOfView = 60;
    }
    // matrix operations ----------------------------------------
    public function forceUpdateMatrix() : SiGLCore { _mvpdir = true; return this; }
    public function setZRange(zNear:Number=-100, zFar:Number=100) : SiGLCore { _zNear = zNear; _zFar = zFar; _updateProjectionMatrix(); return this; }
    public function clear() : SiGLCore { matrix.clear(); _mvpdir = true; return this; }
    public function id() : SiGLCore { matrix.id(); _mvpdir = true; return this; }
    public function push() : SiGLCore { matrix.push(); return this; }
    public function pop() : SiGLCore { matrix.pop(); _mvpdir = true; return this; }
    public function rem() : SiGLCore { matrix.rem(); _mvpdir = true; return this; }
    public function r(a:Number, axis:Vector3D, pivot:Vector3D = null) : SiGLCore { matrix.prependRotation(a*_2d, axis, pivot); matrix._invdir = _mvpdir = true; return this; }
    public function s(x:Number, y:Number, z:Number=1) : SiGLCore { matrix.prependScale(x, y, z); matrix._invdir = _mvpdir = true; return this; }
    public function t(x:Number, y:Number, z:Number=0) : SiGLCore { matrix.prependTranslation(x, y, z); matrix._invdir = _mvpdir = true; return this; }
    public function m(mat:Matrix3D) : SiGLCore { matrix.prepend(mat); matrix._invdir = _mvpdir = true; return this; }
    public function re(x:Number, y:Number, z:Number) : SiGLCore { matrix.prependRotationXYZ(x*_2r, y*_2r, z*_2r); _mvpdir = true; return this; }
    public function setCameraMatrix(mat:Matrix3D=null) : SiGLCore { projectionMatrix.rem().prepend(mat || defaultCameraMatrix); _mvpdir = true; return this; }
    public function _updateProjectionMatrix() : void {
        var wh:Number = viewWidth / viewHeight, rev:Number = (_alignTopLeft)?-1:1;
        _fl = (viewHeight * 0.5) / Math.tan(_fieldOfView * 0.5);
        if (_zNear <= -_fl) _zNear = -_fl + 0.001;
        projectionMatrix.clear().perspectiveFieldOfView(_fieldOfView, wh, _zNear+_fl, _zFar+_fl, -1);
        projectionMatrix.push();
        defaultCameraMatrix.identity();
        defaultCameraMatrix.prependTranslation(0, 0, -_fl);
        if (_alignTopLeft) defaultCameraMatrix.prependTranslation(viewWidth* 0.5, -viewHeight * 0.5, 0);
        defaultCameraMatrix.prependScale(_mag, _mag * rev, _mag * rev);
        setCameraMatrix();
    }
    public function copyFrom(v:Vector.<Number>, i:uint = 0, t:Boolean = false) : SiGLCore { matrix.copyRawDataFrom(v, i, t); matrix._invdir = _mvpdir = true; return this; }
    public function copyTo(v:Vector.<Number>, i:uint = 0, t:Boolean = false) : SiGLCore { matrix.copyRawDataTo(v, i, t); return this; }
}


/** SiGLMatrix is extention of Matrix3D with push/pop operation */
class SiGLMatrix extends Matrix3D {
    internal var _invdir:Boolean = false, _inv:Matrix3D = new Matrix3D(), _stac:Vector.<Matrix3D> = new Vector.<Matrix3D>();
    static private var _tv:Vector.<Number> = new Vector.<Number>(16, true), _tm:Matrix3D = new Matrix3D();
    static private var _in:Vector.<Number> = new Vector.<Number>(4, true), _out:Vector.<Number> = new Vector.<Number>(4, true);
    public var sp:int = 0;
    public function get inverted() : Matrix3D { if (_invdir) { _inv.copyFrom(this); _inv.invert(); _invdir = false; } return _inv; }
    public function forceUpdateInvertedMatrix() : SiGLMatrix { _invdir=true; return this; }
    public function clear() : SiGLMatrix { sp = 0; return id(); }
    public function id() : SiGLMatrix { identity(); _inv.identity(); return this; }
    public function push() : SiGLMatrix {
        if(_stac.length == sp) _stac.push(new Matrix3D());
        _stac[sp++].copyFrom(this);
        return this; 
    }
    public function pop() : SiGLMatrix {
        this.copyFrom(_stac[--sp]);
        _invdir=true;
        return this;
    }
    public function rem() : SiGLMatrix { this.copyFrom(_stac[sp-1]); _invdir=true; return this; }
    public function prependRotationXYZ(rx:Number, ry:Number, rz:Number) : SiGLMatrix {
        var sx:Number = Math.sin(rx), sy:Number = Math.sin(ry), sz:Number = Math.sin(rz), 
        cx:Number = Math.cos(rx), cy:Number = Math.cos(ry), cz:Number = Math.cos(rz);
        _tv[0] = cz*cy; _tv[1] = sz*cy; _tv[2] = -sy; _tv[4] = -sz*cx+cz*sy*sx; _tv[5] = cz*cx+sz*sy*sx;
        _tv[6] = cy*sx; _tv[8] = sz*sx+cz*sy*cx; _tv[9] = -cz*sx+sz*sy*cx;
        _tv[10] = cy*cx; _tv[14] = _tv[13] = _tv[12] = _tv[11] = _tv[7] = _tv[3] = 0; _tv[15] = 1;
        _tm.copyRawDataFrom(_tv); prepend(_tm); _invdir=true;
        return this;
    }
    public function lookAt(cx:Number, cy:Number, cz:Number, tx:Number=0, ty:Number=0, tz:Number=0, ux:Number=0, uy:Number=1, uz:Number=0, w:Number=0) : SiGLMatrix {
        var dx:Number=tx-cx, dy:Number=ty-cy, dz:Number=tz-cz, dl:Number=-1/Math.sqrt(dx*dx+dy*dy+dz*dz), 
        rx:Number=dy*uz-dz*uy, ry:Number=dz*ux-dx*uz, rz:Number=dx*uy-dy*ux, rl:Number= 1/Math.sqrt(rx*rx+ry*ry+rz*rz);
        _tv[0]  = (rx*=rl); _tv[4]  = (ry*=rl); _tv[8]  = (rz*=rl); _tv[12] = -(cx*rx+cy*ry+cz*rz) * w;
        _tv[2]  = (dx*=dl); _tv[6]  = (dy*=dl); _tv[10] = (dz*=dl); _tv[14] = -(cx*dx+cy*dy+cz*dz) * w;
        _tv[1]  = (ux=dy*rz-dz*ry); _tv[5]  = (uy=dz*rx-dx*rz); _tv[9]  = (uz=dx*ry-dy*rx); _tv[13] = -(cx*ux+cy*uy+cz*uz) * w;
        _tv[3] = _tv[7] = _tv[11] = 0; _tv[15] = 1; copyRawDataFrom(_tv); _invdir=true;
        return this;
    }
    public function perspectiveFieldOfView(fieldOfViewY:Number, aspectRatio:Number, zNear:Number, zFar:Number, lh:Number=1.0) : void {
        var yScale:Number = 1.0 / Math.tan(fieldOfViewY * 0.5), xScale:Number = yScale / aspectRatio;
        this.copyRawDataFrom(Vector.<Number>([xScale,0,0,0,0,yScale,0,0,0,0,zFar/(zFar-zNear)*lh,lh,0,0,(zNear*zFar)/(zNear-zFar),0]));
     }
    public function transform(vector:Vector3D) : Vector3D {
        _in[0] = vector.x; _in[1] = vector.y; _in[2] = vector.z; _in[3] = vector.w;
        transformVectors(_in, _out); vector.setTo(_out[0], _out[1], _out[2]); vector.w = _out[3];
        return vector;
    }
}