双曲放物面

by uwi forked from Checkmate Vol.6 Professional (diff: 160)
@gupon 氏のコードをだいぶ拝借しています。
♥2 | Line 137 | Modified 2009-12-08 11:49:45 | MIT License
play

ActionScript3 source code

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

// forked from checkmate's Checkmate Vol.6 Professional
package {
    import flash.events.*;
    import flash.geom.*;
    import flash.display.*;
    import flash.text.*;
    
    // @gupon 氏のコードをだいぶ拝借しています。
    [SWF(backgroundColor="#997777")]
    public class CheckmateProfessional extends Sprite {
        private var _matWorld : Matrix3D;
        private var _matView : Matrix3D;
        private var _proj : PerspectiveProjection;
        
        private var _viewport : Shape;
        
        private var _vertices : Vector.<Number>;
        private var _indices : Vector.<int>;
        private var _uvtData : Vector.<Number>;
        
        private var _tf : TextField;
        
        public function CheckmateProfessional() {
            _viewport = new Shape();
            _viewport.x = stage.stageWidth / 2;
            _viewport.y = stage.stageHeight / 2;
            addChild(_viewport);
            
            _proj = new PerspectiveProjection();
            _proj.fieldOfView = 60;
            _proj.focalLength = 300;
            
            _matWorld = new Matrix3D();
            _matView = new Matrix3D();
            _matView.appendRotation(0, Vector3D.X_AXIS);
            _matView.appendTranslation(0, 0, 100);
            
            init();
            
            _tf = new TextField();
            _tf.width = 465;
            addChild(_tf);
            
//            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            render();
        }
        
        private function onMouseMove(e : MouseEvent) : void
        {
            var theta : Number = (stage.mouseX - 465 / 2) * 0.003;
            var phi : Number = (stage.mouseY - 465 / 2) * 0.005;
            _matView = new Matrix3D();
            _matView.appendRotation(phi * 180 / Math.PI, Vector3D.X_AXIS);
            _matView.appendRotation(theta * 180 / Math.PI, Vector3D.Y_AXIS);
            _matView.appendTranslation(0, 0, 100);
            render();
        }
        
        private const LIM : Number = 15;
        private const STEP : Number = 0.6;
        
        private function init() : void
        {
            _vertices = new Vector.<Number>();
            _uvtData = new Vector.<Number>();
            for(var x : Number = -LIM;x <= LIM;x+=STEP){
                for(var y : Number = -LIM;y <= LIM;y+=STEP){
                    _vertices.push(x * 3, f(x, y), y * 3.5);
//                    _uvtData.push(1, 1, 1);
                }
            }
            
            _indices = new Vector.<int>();
            var nx : int = (LIM - (-LIM)) / STEP + 1;
            var ny : int = (LIM - (-LIM)) / STEP + 1;
            for(var i : int = 0;i < nx - 1;i++){
                for(var j : int = 0;j < ny - 1;j++){
//                    _indices.push(i * ny + j, i * ny + j + 1, (i + 1) * ny + j);
//                    _indices.push((i + 1) * ny + j, i * ny + j + 1, (i + 1) * ny + j + 1);
                    _indices.push(i * ny + j, (i + 1) * ny + j, i * ny + j + 1);
                    _indices.push((i + 1) * ny + j, (i + 1) * ny + j + 1, i * ny + j + 1);
                }
            }
        }
        
        private static function f(x : Number, y : Number) : Number
        {
            // x * x - y * y + 2 * z = 1
            return -0.5 * (1 - x * x + y * y);
        }
        
        private function onEnterFrame(e : Event) : void
        {
        }
        
        private function sortIndices(indices : Vector.<int>, uvtData : Vector.<Number>) : Vector.<int>
        {
            var triangles : Array = [];
            for(var i : int = indices.length/3-1;i >=0;i--){
                var i1 : int = indices[3*i];
                var i2 : int = indices[3*i+1];
                var i3 : int = indices[3*i+2];
                var t : Number = Math.min(uvtData[3*i1+2], uvtData[3*i2+2], uvtData[3*i3+2]);
                if(t < 0)continue;
                triangles[i] = [
                    t,
                    i1, i2, i3
                    ];
            }
            triangles.sortOn("0", Array.NUMERIC);
            
            var ret : Vector.<int> = new Vector.<int>(triangles.length*3);
            for(i = triangles.length-1;i >= 0;i--){
                ret[3*i] = triangles[i][1];
                ret[3*i+1] = triangles[i][2];
                ret[3*i+2] = triangles[i][3];
            }
            return ret;
        }
        
        private function render() : void
        {
            var m : Matrix3D = new Matrix3D();
//            m.append(_matWorld);
            m.append(_matView);
            m.append(_proj.toMatrix3D());
            
            var l : int = _indices.length / 3;
            var projected : Vector.<Number> = new Vector.<Number>();
            Utils3D.projectVectors(m, _vertices, projected, _uvtData);
            var sortedIndices : Vector.<int> = sortIndices(_indices, _uvtData);
            
            var g : Graphics = _viewport.graphics;
            g.clear();
            for(var i : int = 0;i < l;i++){
                var va : Vector3D = new Vector3D(
                    _vertices[3*sortedIndices[3*i]] - _vertices[3*sortedIndices[3*i+1]], 
                    _vertices[3*sortedIndices[3*i]+1] - _vertices[3*sortedIndices[3*i+1]+1], 
                    _vertices[3*sortedIndices[3*i]+2] - _vertices[3*sortedIndices[3*i+1]+2]
                    );
                var vb : Vector3D = new Vector3D(
                    _vertices[3*sortedIndices[3*i]] - _vertices[3*sortedIndices[3*i+2]], 
                    _vertices[3*sortedIndices[3*i]+1] - _vertices[3*sortedIndices[3*i+2]+1], 
                    _vertices[3*sortedIndices[3*i]+2] - _vertices[3*sortedIndices[3*i+2]+2]
                    );
                var vo : Vector3D = new Vector3D(
                    _vertices[3*sortedIndices[3*i]] - 0, 
                    _vertices[3*sortedIndices[3*i]+1] - (30), 
                    _vertices[3*sortedIndices[3*i]+2] - (-30)
                    );
                var n : Vector3D = va.crossProduct(vb);
                var light : Number = n.dotProduct(vo) / vo.length / n.length / vo.lengthSquared * 700;
                
                var d : int = 256 * light;
                if(d >= 256)d = 255;
                if(d < 0)d = 0;
                g.beginFill(d << 16 | d << 8 | d);
                g.moveTo(projected[2*sortedIndices[3*i]], projected[2*sortedIndices[3*i]+1]);
                g.lineTo(projected[2*sortedIndices[3*i+1]], projected[2*sortedIndices[3*i+1]+1]);
                g.lineTo(projected[2*sortedIndices[3*i+2]], projected[2*sortedIndices[3*i+2]+1]);
                g.lineTo(projected[2*sortedIndices[3*i]], projected[2*sortedIndices[3*i]+1]);
                g.endFill();
            }
//            g.drawTriangles(projected, _indices);
        }
    }
}