【问题标题】:Inverting rotation in 3D, to make an object always face the camera?在 3D 中反转旋转,使对象始终面向相机?
【发布时间】:2011-07-24 22:22:24
【问题描述】:

我在 3D 空间中排列了许多精灵,并且它们的父容器应用了旋转。 如何反转精灵 3D 旋转,使它们始终面向相机(Actionscript 3)?

这里有一个代码来测试它:

package{
import flash.display.Sprite;
import flash.events.Event;
public class test extends Sprite{

var canvas:Sprite = new Sprite();
var sprites:Array = []

public function test(){
    addChild(canvas)
    for (var i:int=0;i<20;i++){
        var sp:Sprite = new Sprite();
        canvas.addChild(sp);
        sp.graphics.beginFill(0xFF0000);
        sp.graphics.drawCircle(0,0,4);
        sp.x = Math.random()*400-200;
        sp.y = Math.random()*400-200;
        sp.z = Math.random()*400-200;
        sprites.push(sp);
    }
    addEventListener(Event.ENTER_FRAME,function():void{
        canvas.rotationX++;
        canvas.rotationY = canvas.rotationY+Math.random()*2;
        canvas.rotationZ++;
        for (var i:int=0;i<20;i++){
            //this is not working...
            sprites[i].rotationX = -canvas.rotationX
            sprites[i].rotationY = -canvas.rotationY
            sprites[i].rotationZ = -canvas.rotationZ
        }
    })
}
}
}

我猜我必须对精灵的旋转 3D 矩阵做一些魔术...... 我试图实现这个脚本:http://ughzoid.wordpress.com/2011/02/03/papervision3d-sprite3d/,但是非常成功
感谢您的帮助。

【问题讨论】:

    标签: flash actionscript-3 3d


    【解决方案1】:

    最简单的方法是“清除”变换矩阵的旋转部分。您的典型同构变换如下所示

    | xx xy xz xw |
    | yx yy yz yw |
    | zx zy zz zw |
    | wx wy wz ww | 
    

    其中 wx = wy = wz = 0, ww = 1。如果仔细观察,您会发现实际上该矩阵由定义旋转的 3x3 子矩阵、用于平移的 3 子向量和齐次第 0 0 0 1 行

    | R       T |
    | (0,0,0) 1 |
    

    对于广告牌/精灵,您希望保持平移,但摆脱旋转,即 R = I。如果应用了一些缩放,则标识也需要缩放。

    这给出了以下食谱:

    d = sqrt(xx² + yx² + zx² )

    | d 0 0 T.x |
    | 0 d 0 T.y |
    | 0 0 d T.z |
    | 0 0 0   1 |
    

    加载此矩阵可让您绘制相机对齐的精灵。

    【讨论】:

    • 好的,问题是:如何获得任何特定对象的“全局”矩阵,按照您的描述对其进行操作,然后将其设置回这个精灵??? AFAIK,您不能为对象设置“全局”转换矩阵,只能设置“本地”转换矩阵! “pointAt”Matrix3D方法能解决这个问题吗?
    • @BillKotsias:跟踪场景中对象的转换矩阵是您的责任。您通常有某种转换层次结构:view · t_1 · t_2 · t_3 …。这是您的“全局”转换矩阵。现在,如果你想在这个转换链中绘制一些对象,但让它面向相机,你可以使用那个复合矩阵并按照我描述的方式改变它。实际上,这只是将对象平移到视图中的正确位置,而不会将其从“相机”中移开。
    • 我一点也不明白。它只会缩放对象并将其从相机移开一段距离,但它不会“定向”平面使其面向相机(它朝向相机,因为平面的法线平行于 a 线从相机原点到平面中心)。
    【解决方案2】:

    提前道歉,这是一个建议,而不是解决方案:

    如果您的意图是模拟 3D 球面旋转,您最简单的方法是放弃 2.5D API,而只使用简单的缩放和 sin/cos 计算来进行定位。

    一个有趣的起点:http://www.reflektions.com/miniml/template_permalink.asp?id=329

    【讨论】:

    • 我认为使用 Flashplayer 10 附带的 3D api(显示对象的 .z 属性)更容易 - 这可以轻松定位在 3D 空间中。如果我在 1-2 天内没有找到解决方案,请使用 sin/cos 计算模拟旋转,或使用 zedbox
    • 当然。这两种方法具有不同的“外观”,因为当使用“z”或任何特定于轴的旋转时,显示对象被转换为位图。查看 Matrix3D.invert() 方法。
    【解决方案3】:

    我已经使用维基百科、矩阵和黑魔法解决了这个问题。我选择实现自定义旋转而不是反转所有对象的旋转。 代码如下:

    package{
    import flash.display.Sprite;
    import flash.events.Event;
    
    public class test extends Sprite{
    
    private var canvas:Sprite = new Sprite();
    private var sprites:Array = []
    private var rotx:Number=0,roty:Number=0,rotz:Number=0;
    private var mm:Matrix3 = new Matrix3();
    public function test(){
        addChild(canvas);
        canvas.x = canvas.y = 230
        for (var i:int=0;i<30;i++){
            var sp:Sprite = new Sprite();
            canvas.addChild(sp);
            sp.graphics.beginFill(0xFF0000);
            sp.graphics.drawCircle(0,0,2);
            sp.x = Math.random()*200-100;
            sp.y = Math.random()*200-100;
            sp.z = Math.random()*200-100;
            sprites.push(sp);
            rotx=0.06; //from top to bottom
            //roty=0.1; //from right to left
            rotz=0.1; //clockwise
            mm.make3DTransformMatrix(rotx,roty,rotz);
        }
        addEventListener(Event.ENTER_FRAME,function():void{
            for (var i:int=0;i<sprites.length;i++){
                var s:Sprite = sprites[i];
                mm.rotateByAngles(s);
            }
        })
    }
    }
    }
    

    和 matrix3 类:

    public class Matrix3{
    
        private var da:Vector.<Number>; // rows
    
        public function make3DTransformMatrix(rotx:Number,roty:Number,rotz:Number):void{
            var cosx:Number = Math.cos(rotx);
            var cosy:Number = Math.cos(roty);
            var cosz:Number = Math.cos(rotz);
            var sinx:Number = Math.sin(rotx);
            var siny:Number = Math.sin(roty);
            var sinz:Number = Math.sin(rotz);
            da =    new <Number>[
                cosy*cosz, -cosx*sinz+sinx*siny*cosz,  sinx*sinz+cosx*siny*cosz,
                cosy*sinz, cosx*cosz+sinx*siny*sinz , -sinx*cosz+cosx*siny*sinz,
                -siny    ,         sinx*cosy        ,        cosx*cosy         ];
        }
    
        public function rotateByAngles(d:DisplayObject):void{
            var dx:Number,dy:Number,dz:Number;
            dx = da[0]*d.x+da[1]*d.y+da[2]*d.z;
            dy = da[3]*d.x+da[4]*d.y+da[5]*d.z;
            dz = da[6]*d.x+da[7]*d.y+da[8]*d.z;
            d.x = dx;
            d.y = dy;
            d.z = dz;
        }
    }
    }
    

    【讨论】:

      【解决方案4】:

      如上图所示,右侧的相机设置为面向四边形(左侧),因此它们的法线正好相反。当相机旋转时,为了使四边形仍然具有相反的法线,四边形必须以与相机相同的角度沿相反方向旋转。因此,我只需将四边形绕 y 轴旋转-camera.Yaw,就能产生正确的效果。

      【讨论】:

        猜你喜欢
        • 2013-03-14
        • 1970-01-01
        • 1970-01-01
        • 2020-08-16
        • 2018-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多