3D Tree (Matrix3D Rotation Error?)

by greentec
Code from old book
, Chapter 2

3D rotate function from -
http://away3d.com/forum/viewthread/1288/#4228

I think there is Matrix3D Rotation Calculate Bug or Error on this site's library.
On local, I can get correct rotation!
♥0 | Line 272 | Modified 2015-12-28 16:16:34 | MIT License
play

Related images

ActionScript3 source code

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

package {
    import away3d.cameras.Camera3D;
    import away3d.containers.Scene3D;
    import away3d.containers.View3D;
    import away3d.controllers.HoverController;
    import away3d.debug.AwayStats;
    import away3d.entities.Mesh;
    import away3d.lights.PointLight;
    import away3d.materials.ColorMaterial;
    import away3d.primitives.CubeGeometry;
    import away3d.lights.DirectionalLight;
    import away3d.materials.lightpickers.StaticLightPicker;
    import com.bit101.components.PushButton;
    import com.bit101.components.Label;
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    public class FlashTest extends Sprite {
        
        private var view:View3D;
        private var scene:Scene3D;
        private var camera:Camera3D;
        private var awayStats:AwayStats;
        
        private var cameraController:HoverController;
        
        private var light:DirectionalLight;
        private var lightPicker:StaticLightPicker;
        private var pointLight:PointLight;
        private var pointLight2:PointLight;
        
        private var colorMaterial:ColorMaterial;
        
        //navigation variables
        private var move:Boolean = false;
        private var lastPanAngle:Number;
        private var lastTiltAngle:Number;
        private var lastMouseX:Number;
        private var lastMouseY:Number;
        
        public var maxStem:int = 600;
        public var stemCount:int = 0;
        
        public var stemLength:int = 150;
        public var stemRadius:int = 60;
        public var stemThick:int = 20;
        public var angleDiff:int = 90;
        public var depthMax:int = 9;
        
        public var stemPool:Array = [];
        public var _label:Label;
        public function FlashTest() {
            // write as3 code here..
            
            Wonderfl.disable_capture();
            
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            
            initEngine();
            initLight();
            initMaterial();
            initObject();
            initListener();
            
            var button:PushButton = new PushButton(this, 465 - 110, 10, "Reset", onReset);
            _label = new Label(this, button.x, 30, "");
        }
        
        private function onReset(e:Event):void
        {
            stemCount = 0;
            
            var colorArray:Array;
            colorArray = hsv(Math.random() * 360, 1, 1);
            pointLight.color = colorArray[0] << 16 | colorArray[1] << 8 | colorArray[2];
            colorArray = hsv(Math.random() * 360, 1, 1);
            pointLight2.color = colorArray[0] << 16 | colorArray[1] << 8 | colorArray[2];
            
            var i:int;
            var stem:Mesh;
            
            for (i = 0; i < maxStem; i += 1)
            {
                stem = stemPool[i];
                stem.visible = false;
                
            }
            
            initStem();
        }
        
        private function initEngine():void
        {
            view = new View3D();
            view.antiAlias = 4;
            
            scene = view.scene;
            camera = view.camera;
            camera.lens.far = 5000;
            
            cameraController = new HoverController(camera);
            cameraController.distance = 800;
            cameraController.panAngle = 45;
            cameraController.tiltAngle = 20;
            
            awayStats = new AwayStats(view);
            
        }
        
        private function initLight():void
        {
            light = new DirectionalLight( 0.5, -1, 1);
            light.color = 0xffffff;
            light.ambient = 0.4;
            //scene.addChild(light);
            
            pointLight = new PointLight();
            var colorArray:Array;
            colorArray = hsv(Math.random() * 360, 1, 1);
            
            pointLight.color = colorArray[0] << 16 | colorArray[1] << 8 | colorArray[2];
            pointLight.specular = 1;
            pointLight.diffuse = 0.8;
            
            pointLight.x = Math.random() * 200 - 100;
            pointLight.z = Math.random() * 200 - 100;
            pointLight.y = -100;
            
            pointLight2 = new PointLight();
            colorArray = hsv(Math.random() * 360, 1, 1);
            
            pointLight2.color = colorArray[0] << 16 | colorArray[1] << 8 | colorArray[2];
            pointLight2.specular = 1;
            pointLight2.diffuse = 0.8;
            
            pointLight2.x = -pointLight.x;
            pointLight2.z = -pointLight.z;
            pointLight.y = -100;
            
            lightPicker = new StaticLightPicker([light, pointLight, pointLight2]);
        }
        
        private function initMaterial():void
        {
            colorMaterial = new ColorMaterial(0x292929);
            colorMaterial.lightPicker = lightPicker;
            colorMaterial.specular = 0.3;
        }
        
        private function initObject():void
        {
            stemPool = [];
            
            var i:int;
            for (i = 0; i < maxStem; i += 1)
            {
                var stem:Mesh = new Mesh(new CubeGeometry());
                stemPool.push(stem);
                scene.addChild(stem);
                stem.visible = false;
            }
            
            initStem();
        }
        
        private function initStem():void
        {
            var stem:Mesh;
            var startX:Number = 0;
            var startY:Number = -200;
            var startZ:Number = 0;
            var angle:Number = 0;
            
            stem = stemPool[stemCount];
            stem.geometry = new CubeGeometry(stemThick, stemLength, stemThick, 1, 1, 1, false);
            stem.material = colorMaterial;
            stem.y = startY;
            stem.visible = true;
            //scene.addChild(stem);
            stemCount += 1;
            
            makeStem(startX, startY, startZ, 60, 1);
            makeStem(startX, startY, startZ, 180, 1);
            makeStem(startX, startY, startZ, 300, 1);
            
            //trace(stemCount);
        }
        
        private function makeStem(startX:Number, startY:Number, startZ:Number, angle:Number, depth:int):void
        {
            if (stemCount >= maxStem || depth >= depthMax)
            {
                return;
            }
            
            var scale:Number = (depthMax - depth + 3) / depthMax;
            var newHeight:Number = stemLength * scale;
            
            var dx:Number = Math.cos(angle * Math.PI / 180) * stemRadius * scale;
            var dy:Number = newHeight;
            var dz:Number = Math.sin(angle * Math.PI / 180) * stemRadius * scale;
            
            var newLength:Number = Math.sqrt(dx * dx + dy * dy + dz * dz);
            
            
            var stem:Mesh = stemPool[stemCount];
            stem.geometry = new CubeGeometry(stemThick * scale, 
                                             newLength, 
                                             stemThick * scale, 
                                             1, 
                                             1, 
                                             1, 
                                             false);
            stem.material = colorMaterial;
            stem.x = startX + dx;
            stem.y = startY;
            stem.z = startZ + dz;
            
            
            var theta:Number = Math.acos(dy / newLength) * 180 / Math.PI;
            var phi:Number = Math.atan2(dz, dx) * 180 / Math.PI;
            
            stem.y += Math.sin(theta / 180 * Math.PI) * newLength;
            
            stem.rotationX = 0;
            stem.rotationY = 0;
            stem.rotationZ = 0;
            
            /*
            var m:Matrix3D = new Matrix3D();
            m.prependRotation( -theta - 90, new Vector3D(1, 0, 0));
            m.prependRotation( -phi + 90, Vector3D.Y_AXIS);
            
            var vec:Vector3D = m.decompose()[1];
            
            stem.rotationX = vec.x;
            stem.rotationY = vec.y;
            stem.rotationZ = vec.z;
            */
            //stem.rotate(Vector3D.X_AXIS, -theta - 90);
            //stem.rotate(Vector3D.Y_AXIS, -phi + 90);
            //stem.rotate(new Vector3D(1, 0, 0), -theta - 90);
            //stem.rotate(Vector3D.Y_AXIS, -phi + 90);
            stem.transform.prependRotation( -theta - 90, Vector3D.X_AXIS);
            stem.transform.prependRotation( -phi + 90, Vector3D.Y_AXIS);
            
            //scene.addChild(stem);
            
            stem.visible = true;
            stemCount += 1;
            
            if (Math.random() < 0.85)
            {
                makeStem(stem.x + dx, stem.y, stem.z + dz, angle + angleDiff * Math.random(), depth + 1);
            }
            if (Math.random() < 0.85)
            {
                makeStem(stem.x + dx, stem.y, stem.z + dz, angle - angleDiff * Math.random(), depth + 1);
            }
        }
        
        private function initListener():void
        {
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            stage.addEventListener(Event.RESIZE, resizeHandler);
            addEventListener(Event.ENTER_FRAME, render);
            
            
            addChild(view);
            addChild(awayStats);
        }
        
        private function render(e:Event):void
        {
            if (move)
            {
                cameraController.panAngle = 0.3 * (stage.mouseX - lastMouseX) + lastPanAngle;
                cameraController.tiltAngle = 0.3 * (stage.mouseY - lastMouseY) + lastTiltAngle;
            }
            
            view.render();
            //view.renderer.queueSnapshot(source);
        }
        
        private function onMouseDown(e:MouseEvent):void
        {
            lastPanAngle = cameraController.panAngle;
            lastTiltAngle = cameraController.tiltAngle;
            lastMouseX = stage.mouseX;
            lastMouseY = stage.mouseY;
            move = true;
           
        }
        
        private function onMouseUp(e:MouseEvent):void
        {
            move = false;
        }
        
        private function resizeHandler(e:Event):void
        {
            view.width = stage.stageWidth;
            view.height = stage.stageHeight;
        }
        
        private function hsv(h:Number, s:Number, v:Number):Array{
            var r:Number, g:Number, b:Number;
            var i:int;
            var f:Number, p:Number, q:Number, t:Number;
             
            if (s == 0){
                r = g = b = v;
                return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
            }
           
            h /= 60;
            i  = Math.floor(h);
            f = h - i;
            p = v *  (1 - s);
            q = v * (1 - s * f);
            t = v * (1 - s * (1 - f));
           
            switch( i ) {
                case 0:
                    r = v;
                    g = t;
                    b = p;
                    break;
                case 1:
                    r = q;
                    g = v;
                    b = p;
                    break;
                case 2:
                    r = p;
                    g = v;
                    b = t;
                    break;
                case 3:
                    r = p;
                    g = q;
                    b = v;
                    break;
                case 4:
                    r = t;
                    g = p;
                    b = v;
                    break;
                default:        // case 5:
                    r = v;
                    g = p;
                    b = q;
                    break;
            }
            return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
        }
    }
}