Inverting rotation in 3D, to make an object always face the camera?
Solution 1
The easiest way to do this is "clearing" the rotational part of the transform matrix. Your typical homogenous transformation looks like this
| xx xy xz xw |
| yx yy yz yw |
| zx zy zz zw |
| wx wy wz ww |
with wx = wy = wz = 0, ww = 1. If you take a closer look you'll see that in fact this matrix is composed of a 3x3 submatrix defining the rotation, a 3 subvector for the translation and a homogenous row 0 0 0 1
| R T |
| (0,0,0) 1 |
For a billboard/sprite you want to keep the translation, but get rid of the rotation, i.e. R = I. In case some scaleing was applied the identity needs to be scaled as well.
This gives the following recipie:
d = sqrt( xx² + yx² + zx² )
| d 0 0 T.x |
| 0 d 0 T.y |
| 0 0 d T.z |
| 0 0 0 1 |
Loading this matrix allows you to draw camera aligned sprites.
Solution 2
Apologies in advance for this being a suggestion, not a solution:
If your intent is simulate 3D spherical rotations, your easiest route would be to forego the 2.5D API and just use simple scaling and sin/cos calculations for the positioning.
A fun place to start: http://www.reflektions.com/miniml/template_permalink.asp?id=329
Solution 3
I've solved it using Wikipedia, matrices and black magic. I choose to implement custom rotation instead of inverting the rotation of all objects. Heres the code if anyones interested:
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);
}
})
}
}
}
and the matrix3 class:
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;
}
}
}
Solution 4
As you can see in the picture above, the camera on the right is set to face the quad (on the left), so that their normals are exactly opposite. When the camera is rotated, for the quad to still have an opposite normal, the quad would have to be rotated in the opposite direction the same angle as the camera. So, I was able to produce the right effect simply by rotating the quad by -camera.Yaw
around the y-axis.
sydd
Updated on June 24, 2022Comments
-
sydd almost 2 years
i have lots of sprites arranged in 3D space, and their parent container has rotations applied. How do i reverse the sprites 3D rotation, that they always face the camera (Actionscript 3)?
heres a code to test it:
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 } }) } } }
I am guessing i have to do some magic with the rotation3D matrices of the sprites... I've tried to implement this script: http://ughzoid.wordpress.com/2011/02/03/papervision3d-sprite3d/ , but had so success
Thanks for help. -
sydd about 13 yearsI think its easier to use the 3D api that came with Flashplayer 10 (.z property of displayobjects) - this allows easy positioning in 3D space. If i dont find a solution in 1-2 days, ill simulate the rotation with sin/cos calculations, or use zedbox
-
NickHubben about 13 yearsAbsolutely. The two methods have different 'looks' as the displayObjects are converted to bitmaps when using 'z' or any of the axis-specific rotations. Check out Matrix3D.invert() method.
-
Bill Kotsias over 11 yearsOK, the question is : how do you get the "global" matrix for any particular object, manipulate it as you describe, then set it back to this sprite??? AFAIK, you can't set a "global" transformation matrix to an object, only a "local" one! Could the "pointAt" Matrix3D method solve this problem?
-
datenwolf over 11 years@BillKotsias: It's your responsibility to track the transformation matrices of the objects in your scene. You usually have some sort of transformation hierachy:
view · t_1 · t_2 · t_3 …
. This is your "global" transformation matrix. Now if you want to draw some object in this transformation chain, but make it face the camera, you take that compound matrix and change it the way I described. Effectively this just translates the object at the right spot in the view without turning it away from the "camera". -
user18490 over 9 yearsI don't understand this at all. It would only scale the object and move it some distance away from the camera, but it wouldn't "orient" the plane so it faces the cameras (it's oriented towards the camera as in the normal of the plane is parallel to the a line from the camera origin to the centre of the plane).
-
Summit almost 2 years@datenwolf If the camera moves from its position( Position , pan , tilt) will this work ?
-
datenwolf almost 2 years@Summit – yes it will. Because there is no camera! At the end it comes all down to rotating, scaling and translating stuff in screen space. All that matrix multiplication "magic" does is figuring out, how to bring things into screen space. If you "clear out" the rotating part, things will just be upright and in the plane of screen space.