Dynamic Parenting
March 26, 2008 – 3:32 amThis is basically step #1 of generating your own 3d art. In step #2 you simply add a new 3d object every second or so based on the current position of the target object (in this case “mainSphere”).
[source:javascript]
import caurina.transitions.Tweener;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.core.math.Matrix3D;
import org.papervision3d.core.proto.DisplayObjectContainer3D;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.objects.primitives.Sphere;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.cameras.FreeCamera3D;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
private var viewport:Viewport3D;
private var scene:Scene3D;
private var camera:FreeCamera3D;
private var renderer:BasicRenderEngine;
private var parent1:Sphere;
private var parent2:Sphere;
private var mainSphere:Sphere;
private function init():void
{
viewport = new Viewport3D(pv3dCanvas.width, pv3dCanvas.height);
pv3dCanvas.rawChildren.addChild(viewport);
scene = new Scene3D();
camera = new FreeCamera3D();
renderer = new BasicRenderEngine();
createObjects();
addEventListeners();
}
private function createObjects():void
{
parent1 = new Sphere(new WireframeMaterial(0xcc0000), 150);
parent1.x = -500;
scene.addChild(parent1);
parent2 = new Sphere(new WireframeMaterial(0x00cc00), 150);
parent2.x = 500;
scene.addChild(parent2);
mainSphere = new Sphere(new WireframeMaterial(0x0000cc), 50);
mainSphere.y = 100;
scene.addChild(mainSphere);
}
private function addEventListeners():void
{
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void
{
parent1.yaw(3);
parent2.roll(3);
mainSphere.pitch(3);
renderer.renderScene(scene, camera, viewport);
}
private function switchParent(parent:DisplayObject3D):void
{
Tweener.removeAllTweens();
//Here's the magic where you find world coordinates of the child sphere
//then transfer them to the local coordinates of the next parent
var inverse:Matrix3D = new Matrix3D();
var parentMatrix:Matrix3D = new Matrix3D();
inverse.calculateInverse(parent.world);
parentMatrix.calculateMultiply(inverse, mainSphere.world);
//remove the sphere from the previous parent
mainSphere.parent.removeChild(mainSphere);
//copy everything from your shiny new matrix3d
mainSphere.copyTransform(parentMatrix);
//add the sphere to the new parent
parent.addChild(mainSphere);
}
private function tweenToZero():void
{
Tweener.addTween(mainSphere, {x:0, y:0, z:0, time:2});
}
]]>
[/source]

10 Responses to “Dynamic Parenting”
I wish I knew what to do with this mx code!
By nikos on Mar 29, 2008
I’ve figured it out now, got flex builder and messed with tutorials
By nikos on Apr 1, 2008
really would be cool if you could eplain this in more detail
//Here’s the magic where you find world coordinates of the child sphere
//then transfer them to the local coordinates of the next parent
var inverse:Matrix3D = new Matrix3D();
var parentMatrix:Matrix3D = new Matrix3D();
inverse.calculateInverse(parent.world);
parentMatrix.calculateMultiply(inverse, mainSphere.world);
By nikos on Apr 1, 2008
A detailed explanation is that vector values in two cartesian coordinate systems (with common origin) are connected by equation vector_1 * matrix_1 = vector_2 * matrix_2, hence if you want to calculate vector_2 from vector_1, you need to multiply both sides by inverted matrix_2: vector_1 * matrix_1 * matrix_2^-1 = vector_2 * identity_matrix = vector_2. Then, folks in pv3d and alike always stuff translation into matrices too, so the formula is basically the same in general case.
By makc on Apr 2, 2008
Thanks marc, I’m impressed
vector_1 * matrix_1 = vector_2 * matrix_2
fair enough,i’ll check its proof one day
vector_1 * matrix_1 * matrix_2^-1 = vector_2
very clever.
so parent.world = matrix_2
and inverse = matrix_2^-1
and mainSphere.world = matrix_1
so
what is vector_1 and vector_2 in all this?
By nikos on Apr 3, 2008
In love with PV3D. Nice Work. xD!
By saul on Apr 23, 2008
how to run this sample application.
By ajitpal singh on Apr 30, 2008
Very good example and explanation
I’ve tried it and it almost works…
Position is ok but I get strange rotation values.
Can you please confirm me that the formula is ok? I believe it may happen because it’s not being multiplied with “vector_1″ after
parentMatrix.calculateMultiply(inverse, mainSphere.world);
Thanks in advance
@nikos vector_1 and 2 i believe that represent the position,orientation and scale of the object…
@makc thanks for the detailed explanation
By Oliver on May 1, 2008
John can you please do another dynamic parenting tutorial?
I’ve tried using this one but somehow when trying to change rotation for the reparented displayObject3D it goes crazy.
I believe this explains it:
copyTransform sets _rotationDirty flag to TRUE
public set rotationX(for example) for _rotatonDirty set to TRUE calls [updateRotation] which calls [matrix2euler].
In my theory matrix2euler returns some odd results which scrambles everything
The same issue was encountered by Sev here:
http://www.nabble.com/Reparenting-DisplayObject3D-(localToGlobal,-globalToLocal)-td16757273.html
He uses something simmilar to your method but a little bit more rudimentary:
var worldTransform : Matrix3D = Matrix3D.clone( obj3d.world );
obj3d.parent.removeChild( obj3d );
obj3d.transform = worldTransform;
scene.addChild( obj3d );
He was told by Ralph Hauwert that this is not the method to be used as it’s not copying transforms.
Ralph Hauvert also instructed him to use transformVertices.
As I see it there is a small divergence of opinion between the two of you and I really believe this should be resolved.
Also can you please publish one tutorial about transformVertices?
Thank you,
Oliver
By Oliver on May 21, 2008
@Oliver- I’ll look into it. Please make sure you have updated to the latest revision since a rotation bug somehow got into the repo a couple weeks ago.
This example is something Andy Zupko and I cooked up. I’ll have a chat with Ralph and see what he has to say about it.
By John Lindquist on May 22, 2008