Search code examples
actionscript-3projectionperspectivecamera

AS3: localToGlobal with perspectiveProjection


It seems that if a display object has a perspective projection applied to it, calling localToGlobal gives you the wrong coordinates. In the following code, I draw a rectangle, rotate it slightly about its X axis, then draw an oval inside it using coordinates derived from localToGlobal. It works fine, until I try to apply a perspective projection, then the coordinates are all wrong. Anyone know how to get around this problem?

var w:uint = 300, h:uint = 150;
var s:Sprite = new Sprite();
s.graphics.beginFill(0x000000);
s.graphics.drawRect(-w/2,0,w,h);
s.graphics.endFill();
s.x = 275; s.y = 200; s.z = 600;
s.rotationX = -45;
addChild(s);

var point00:Point = new Point(0,0);
var point0h:Point = new Point(0,h);
var midL:Point = new Point(-w/2,h/2);
var midR:Point = new Point(w/2,h/2);

/*var VP:PerspectiveProjection = new PerspectiveProjection();
VP.fieldOfView = 55;
var p:Point = new Point(275,100);
VP.projectionCenter = p;
s.transform.perspectiveProjection = VP;*/

var o:Shape = new Shape();
o.graphics.beginFill(0x00ff00);
o.graphics.drawEllipse(
  s.localToGlobal(midL).x,
  s.localToGlobal(point00).y,
  s.localToGlobal(midR).x - s.localToGlobal(midL).x,
  s.localToGlobal(point0h).y - s.localToGlobal(point00).y
);
addChild(o);

Solution

  • It seems that setting perspectiveProjection does not force the player to redraw the object, and localToGlobal depends on redraw for correct results. You can wait 1 tick like you found (setTimeout for 0ms or enterFrame for 1 frame will do it) or you can force the player to redraw using BitmapData/draw():

    // ...
    
    s.transform.perspectiveProjection = VP;
    
    new BitmapData(1, 1).draw(s); // forces player to redraw the sprite
    
    var o:Shape = new Shape();
    o.graphics.beginFill(0x00ff00);
    o.graphics.drawEllipse(
      s.localToGlobal(midL).x,
      s.localToGlobal(point00).y,
      s.localToGlobal(midR).x - s.localToGlobal(midL).x,
      s.localToGlobal(point0h).y - s.localToGlobal(point00).y
    );
    addChild(o);