aerys / minko

3D framework for web, desktop and mobile devices.
http://minko.io
Other
905 stars 210 forks source link

the bug of roationY #37

Closed lizhi525 closed 12 years ago

lizhi525 commented 12 years ago

[code lang='as3']package { import aerys.minko.example.core.cubes.NormalsShader; import aerys.minko.render.effect.Effect; import aerys.minko.render.Viewport; import aerys.minko.scene.controller.camera.ArcBallController; import aerys.minko.scene.node.Camera; import aerys.minko.scene.node.ISceneNode; import aerys.minko.scene.node.mesh.geometry.Geometry; import aerys.minko.scene.node.mesh.geometry.primitive.CubeGeometry; import aerys.minko.scene.node.mesh.Mesh; import aerys.minko.scene.node.Scene; import aerys.minko.type.math.Vector4; import flash.display.Sprite; import flash.events.Event;

public class HelloWorldMinko extends Sprite 
{
    private var view:Viewport;
    private var scene:Scene;
    private var cubes:Array = [];
    public function HelloWorldMinko():void 
    {
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }

    private function init(e:Event = null):void 
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        view = new Viewport(0, 400, 400);
        addChild(view);

        scene = new Scene;

        addEventListener(Event.ENTER_FRAME, enterFrame);

        var cam:Camera = new Camera;
        var _cameraController:ArcBallController = new ArcBallController();
        _cameraController.bindDefaultControls(stage);
        _cameraController.minDistance = 1;
        _cameraController.yaw = Math.PI * -.5;
        _cameraController.pitch = Math.PI / 2;
        _cameraController.distance = 5;
        cam.addController(_cameraController);
        scene.addChild(cam);

        var EFFECT      : Effect    = new Effect(new NormalsShader());

        var c:int = 50;
        while(c-->0){
        var cube:Mesh = new Mesh(CubeGeometry.cubeGeometry,null,EFFECT);
        scene.addChild(cube);
        cubes.push(cube);
        cube.transform
            .lock()
            .appendUniformScale(0.03).appendScale(10,10,10).appendTranslation(
                -1 + Math.random() * 2,
                -1 + Math.random() * 2,
                -1 + Math.random() * 2
            )
        .unlock(); }

        addChild(new Stats);
    }

    private function enterFrame(e:Event):void 
    {
        for each(var cube:Mesh in cubes){
            cube.transform.rotationY+=.01;
        }
        scene.render(view);
    }

}

}[/code]

the rotationY no effect

JMLX42 commented 12 years ago

That weird. I investigated this for like 30 minutes and I can't get it... Logged internally as issue 383

Stilled, using rotationY += 0.1 is a VERY bad idea. You should rather use Matrix4x4.appendRotation(0.1, Vector4.Y_AXIS), which is much much faster (plus it works :p).

lizhi525 commented 12 years ago

ok i will try this funciton.

lizhi525 commented 12 years ago

http://game-develop.net/swfs/native3d/nobug.html

http://game-develop.net/swfs/native3d/bug.html

native is mine a small 3d engine http://code.google.com/p/native3d/

package { import flash.display.; import flash.events.; import flash.geom._; import flash.text.TextField; import net.gamedevelop.native3d.controllers.; import net.gamedevelop.native3d.core.; import net.gamedevelop.native3d.materials.; import net.game_develop.native3d.primitives.*;

/**
 * ...
 * @author sliz http://game-develop.net/blog/
 */
public class Main extends Sprite 
{
    private var view:View3D;
    private var ctrl:FreeRotationController;
    private var tf:TextField = new TextField;
    private var bmd:BitmapData;
    private var ob3d:Obj3D;
    public function Main():void 
    {
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }

    private function init(e:Event = null):void 
    {
        addChild(tf);
        removeEventListener(Event.ADDED_TO_STAGE, init);
        view = new View3D(400, 400, -4000, this);
        addEventListener(Event.ENTER_FRAME, update);
        bmd = new BitmapData(200, 200,true,0x88ff0000);
        var m1:BitmapMaterial = new BitmapMaterial(bmd);
        var m2:LineMaterial = new LineMaterial(0,3);
        var m:ComposeMaterial = new ComposeMaterial([m1,m2]);
        var pm:PointMaterial = new PointMaterial;

        var c:int = 1;
        var w:Number = 800;
        while (c-->0) {
            ob3d = new Cube(pm, w, w, w);
            ob3d.culling = TriangleCulling.NONE;
            view.scene.add(ob3d);
        }
        ctrl = new FreeRotationController(ob3d);
    }

    private function update(e:Event):void 
    {
        view.render();

        ob3d.ry += .03;
        //ob3d.recompose();
        //ob3d.decompose();
        tf.text = ob3d.ry + "";
    }

}

}

if you add the code get the bug.

//ob3d.recompose(); //ob3d.decompose();

i think the rotation in the minko it is too big.

in the native3d

public function get sy():Number { return components[2].y; }

    public function set sy(value:Number):void 
    {
        changed = true;
        components[2].y = value;
    }

if (obj.changed) { obj.recompose(); }

JMLX42 commented 12 years ago

It looks like the bug is not in the Matrix4x4.rotation getter/setter but rather in the flash_proxy::getProperty() method that can't work properly with the += here.

lizhi525 commented 12 years ago

ddddd 91.6731584284725 Vector3D(1.5099580252808664e-7, 1.599998450279236, 1.5099580252808664e-7) 88.32683838425682 Vector3D(-3.141592502593994, 1.54159414768219, -3.141592502593994) ddddd 94.05641633556506 Vector3D(-3.141592502593994, 1.64159414768219, -3.141592502593994) 85.94358047716428 Vector3D(1.5099580252808664e-7, 1.4999984502792358, 1.5099580252808664e-7) ddddd 91.6731584284725 Vector3D(1.5099580252808664e-7, 1.599998450279236, 1.5099580252808664e-7) 88.32683838425682 Vector3D(-3.141592502593994, 1.54159414768219, -3.141592502593994)

package  
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Matrix3D;
    import flash.geom.Orientation3D;
    import flash.geom.Vector3D;
    /**
     * ...
     * @author lizhi
     */
    public class TestMatr extends Sprite
    {
        private var vec:Vector.;
        private var matr:Matrix3D;

        public function TestMatr() 
        {
            matr = new Matrix3D;
            vec = matr.decompose();
            vec[1].y = 1.4999984502792358;
            matr.recompose(vec);
            var vec2:Vector. = matr.decompose();
            trace(vec2[1].y);
            addEventListener(Event.ENTER_FRAME, enterFrame);
        }

        private function enterFrame(e:Event):void 
        {
            vec[1].y += .1;
            trace("ddddd");
            trace(vec[1].y*180/Math.PI,vec[1]);
            matr.recompose(vec);
            vec = matr.decompose();
            trace(vec[1].y*180/Math.PI,vec[1]);
        }

    }

}
makc commented 12 years ago

@promethe42

using rotationY += 0.1 is a VERY bad idea. You should rather use Matrix4x4.appendRotation

then why have rotationY at all?

JMLX42 commented 12 years ago

The issue is not rotationY. The issue is the dynamic flash_proxy::getProperty() that works well when you try to access (chained) sub-properties - including method calls - but not when you try to use the actual getters/setters.

// works
group.get('//mesh').transform.appendRotation(0.1, Vector4.Y_AXIS);

// works
group.get('//mesh').transform.rotationY = 0;

// doesn't work
group.get('//mesh').transform.rotationY += 0.1;

The Matrix4x4.rotationY is not the issue here. It is the fact that it is dyanmically called on a set of objects using the += operator. += operator implies to call the getter, but we're working with a set of objects in the form of a SceneIterator object here.

I think we should remove SceneIterator.flash_proxy::getProperty() and SceneIterator.flash_proxy::setProperty() and use a for each instead:

for each (var mesh : Mesh in group.get('//mesh'))
  mesh.transform.rotationY += 0.1;
makc commented 12 years ago

a ha! so you could do ube.transform.rotationY = cube.transform.rotationY + .01; and it would still work, right?

JMLX42 commented 12 years ago

If cube is a Mesh then there has never been any issue doing cube.transform.rotationY += 0.1 Again: the problem is not Matrix4x4.rotationY. The problem is dynamic getter/setters in SceneIterator. So if cube is a SceneIterator, your example still doesn't work because cube.transform.rotationY have an undefined behaviour.

JMLX42 commented 12 years ago

Ok so here is the problem: we tried to use flash_proxy::getProperty() to be able to access (sub) properties of the object set and be able to write them. And it works when you only want to write them.

If you try to read them - and reading includes operators such as += or *= or course - it just can't work. There is no way to tell whether flash_proxy::getProperty() is called to:

For example, there is no practical difference between:

group.get('//mesh').transform

and

group.get('//mesh').transform.rotationY

The first line should return a SceneIterator so that we can continue working on a set of objects and make the second line possible. But doing so, it fails at returning a Matrix4x4 object so it cannot be read as such. That's why this dynamic class stuff can write a property on a set of objects, but not read it.

As there is no fix for this, we just removed the broken feature :( So now if you want to affect a property of the whole result set, you just have to use a "for each" statement:

for each (var mesh : Mesh in group.get('//mesh'))
  mesh.transform.rotationY += 0.1;
makc commented 12 years ago

...and only now I understand that group.get('//mesh') referred to multiple objects :neutral_face:

lizhi525 commented 12 years ago

ddddd 91.6731584284725 Vector3D(1.5099580252808664e-7, 1.599998450279236, 1.5099580252808664e-7) 88.32683838425682 Vector3D(-3.141592502593994, 1.54159414768219, -3.141592502593994) ddddd 94.05641633556506 Vector3D(-3.141592502593994, 1.64159414768219, -3.141592502593994) 85.94358047716428 Vector3D(1.5099580252808664e-7, 1.4999984502792358, 1.5099580252808664e-7) ddddd 91.6731584284725 Vector3D(1.5099580252808664e-7, 1.599998450279236, 1.5099580252808664e-7) 88.32683838425682 Vector3D(-3.141592502593994, 1.54159414768219, -3.141592502593994)

package  
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Matrix3D;
    import flash.geom.Orientation3D;
    import flash.geom.Vector3D;
    /**
     * ...
     * @author lizhi
     */
    public class TestMatr extends Sprite
    {
        private var vec:Vector.;
        private var matr:Matrix3D;

        public function TestMatr() 
        {
            matr = new Matrix3D;
            vec = matr.decompose();
            vec[1].y = 1.4999984502792358;
            matr.recompose(vec);
            var vec2:Vector. = matr.decompose();
            trace(vec2[1].y);
            addEventListener(Event.ENTER_FRAME, enterFrame);
        }

        private function enterFrame(e:Event):void 
        {
            vec[1].y += .1;
            trace("ddddd");
            trace(vec[1].y*180/Math.PI,vec[1]);
            matr.recompose(vec);
            vec = matr.decompose();
            trace(vec[1].y*180/Math.PI,vec[1]);
        }

    }

}

the get set matrix3d have bug

JMLX42 commented 12 years ago

This is not the same bug at all. The bug you described originally in this issue was about updating the rotation of a set of objects fetched using a SceneIterator via Group.get().

Matrix4x4 uses Matrix3D and - as such - it has the same flaws. I'll run my own test to see what happens.