Hi,
I'm using local3DToGlobal with PerspectiveProjection. My problem is that when I don't use PerspectiveProjection local3DToGlobal works as expected. But when I use PerspectiveProjection local3DToGlobal appears to give a random Point that doesn't make sense to me. However, if I have the local3DToGlobal in a function that's called with the Event.ENTER_FRAME it works as expected.
It's hard for me to explain, but I have code.
The red circle is suppose to follow the black circle end of the stick graphic. The red circle is using regular x and y positions, while the stick is using x, y and z (3D). If you call the onEnterFrameMethod directly the red circle wont wrap the circle end of the stick. If you comment out the PerspectiveProjection code, then the red circle will wrap the circle end of the stick. If you uncomment the PerspectiveProjection code, and then use an event listener to call the onEnterFrameMethod, the red circle will wrap the circle end of the stick.
Can anyone explain this?
Thanks!
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.geom.PerspectiveProjection;
[SWF(width=800, height=800)]
public class LocalGlobal extends Sprite
{
private var _sprite:Sprite;
private var _tracker:Sprite;
private var _angle:Number = 0;
public function LocalGlobal()
{
var perspective:PerspectiveProjection = new PerspectiveProjection();
perspective.fieldOfView = 58;
var point:Point = new Point(400, 400);
perspective.projectionCenter = point;
transform.perspectiveProjection = perspective;
//
_sprite = new Sprite();
_sprite.graphics.lineStyle(10);
_sprite.graphics.lineTo(200, 0);
_sprite.graphics.drawCircle(200, 0, 10);
_sprite.x = 400;
_sprite.y = 400;
addChild(_sprite);
_tracker = new Sprite();
_tracker.graphics.lineStyle(2, 0xff0000);
_tracker.graphics.drawCircle(0, 0, 20);
addChild(_tracker);
//addEventListener(Event.ENTER_FRAME, onEnterFrameMethod);
onEnterFrameMethod();
}
private function onEnterFrameMethod(event:Event = null):void
{
_sprite.rotationX += 1;
_sprite.rotationY += 1.2;
_sprite.rotationZ += .5;
_sprite.x = 400 + Math.cos(_angle) * 100;
_sprite.y = 400 + Math.sin(_angle) * 100;
_sprite.z = 200 + Math.cos(_angle * .8) * 400;
_angle += .05;
var p:Point = _sprite.local3DToGlobal(new Vector3D(200, 0, 0));
_tracker.x = p.x;
_tracker.y = p.y;
}
}
}
I renew the call for an answer to this issue. I struggled for several days getting sporadic nonsensical values when calling local3DToGlobal (with ProspectiveProjection in use), and it was only when I found this post and moved my call to local3DToGlobal to within an ENTER_FRAME event handler that things started working. It is a solution, but a very unsatisfying one given that there is no explanation for this behavior and that the requirement to use an ENTER_FRAME handler is not documented by Adobe. Thanks to DJ Gecko for posting this workaround - I was just about ready to abandon the feature that required the local3DToGlobal call.
It seems that the local3DToGlobal returns erroneous data if the 3d object has yet to be rendered to the stage. I found this issue only occured for me when porting to Air for mobile devices - it worked just fine for me on desktop. If you run the call to local3DToGlobal post render (say on an EXIT_FRAME event handler, a follow-up frame, or a timer), you will find that the call will give you the correct co-ordinate data.
Co-incidentally, I lost a day and a half to this bug... cheers to DJ Gecko for the ENTER_FRAME suggestion which led to a solution to this perplexing issue.
Very, very interesting, BenLeffler. As I posted above, I got my code working, in a regular web app, by using the ENTER_FRAME hack, but when I recently ported this same code to AIR the local3DToGlobal calls again began to return nonsensical values. And the way my code is structured it indeed does not make the local3DToGlobal post render, since it stuffs the 3D coordinates into a work DisplayObject and immediately then calls local3DToGlobal. In fact the DisplayObject never gets rendered - it is used purely to translate a set of 3D coordinates to screen coordinates. So clearly the correct path for me is to forget about local3DToGlobal and just make a low level Utils3D.projectVector call instead.
Bur what is interesting is that it *was* working in the web version of the app, where the DisplayObject was also never, ever getting rendered. So the worst behavior of local3DToGlobal seems to be restricted to AIR
North America
Europe, Middle East and Africa
Asia Pacific