/** Should only be called from updateGeometricState(). In most cases should not be subclassed. */ protected void updateWorldTransforms() { if (parent == null) { worldTransform.set(localTransform); refreshFlags &= ~RF_TRANSFORM; } else { // check if transform for parent is updated assert ((parent.refreshFlags & RF_TRANSFORM) == 0); worldTransform.set(localTransform); worldTransform.combineWithParent(parent.worldTransform); refreshFlags &= ~RF_TRANSFORM; } }
@Override public Transform clone() { try { Transform tq = (Transform) super.clone(); tq.rot = rot.clone(); tq.scale = scale.clone(); tq.translation = translation.clone(); return tq; } catch (CloneNotSupportedException e) { throw new AssertionError(); } }
/** * @return A clone of this Spatial, the scene graph in its entirety is cloned and can be altered * independently of the original scene graph. * <p>Note that meshes of geometries are not cloned explicitly, they are shared if static, or * specially cloned if animated. * <p>All controls will be cloned using the Control.cloneForSpatial method on the clone. * @see Mesh#cloneForAnim() */ public Spatial clone(boolean cloneMaterial) { try { Spatial clone = (Spatial) super.clone(); if (worldBound != null) { clone.worldBound = worldBound.clone(); } clone.worldLights = worldLights.clone(); clone.localLights = localLights.clone(); // Set the new owner of the light lists clone.localLights.setOwner(clone); clone.worldLights.setOwner(clone); // No need to force cloned to update. // This node already has the refresh flags // set below so it will have to update anyway. clone.worldTransform = worldTransform.clone(); clone.localTransform = localTransform.clone(); if (clone instanceof Node) { Node node = (Node) this; Node nodeClone = (Node) clone; nodeClone.children = new SafeArrayList<Spatial>(Spatial.class); for (Spatial child : node.children) { Spatial childClone = child.clone(cloneMaterial); childClone.parent = nodeClone; nodeClone.children.add(childClone); } } clone.parent = null; clone.setBoundRefresh(); clone.setTransformRefresh(); clone.setLightListRefresh(); clone.controls = new SafeArrayList<Control>(Control.class); for (int i = 0; i < controls.size(); i++) { Control newControl = controls.get(i).cloneForSpatial(clone); newControl.setSpatial(clone); clone.controls.add(newControl); } if (userData != null) { clone.userData = (HashMap<String, Savable>) userData.clone(); } return clone; } catch (CloneNotSupportedException ex) { throw new AssertionError(); } }
/** * <code>rotateUpTo</code> is a utility function that alters the local rotation to point the Y * axis in the direction given by newUp. * * @param newUp the up vector to use - assumed to be a unit vector. */ public void rotateUpTo(Vector3f newUp) { TempVars vars = TempVars.get(); Vector3f compVecA = vars.vect1; Quaternion q = vars.quat1; // First figure out the current up vector. Vector3f upY = compVecA.set(Vector3f.UNIT_Y); Quaternion rot = localTransform.getRotation(); rot.multLocal(upY); // get angle between vectors float angle = upY.angleBetween(newUp); // figure out rotation axis by taking cross product Vector3f rotAxis = upY.crossLocal(newUp).normalizeLocal(); // Build a rotation quat and apply current local rotation. q.fromAngleNormalAxis(angle, rotAxis); q.mult(rot, rot); vars.release(); setTransformRefresh(); }
/** Computes the world transform of this Spatial in the most efficient manner possible. */ void checkDoTransformUpdate() { if ((refreshFlags & RF_TRANSFORM) == 0) { return; } if (parent == null) { worldTransform.set(localTransform); refreshFlags &= ~RF_TRANSFORM; } else { TempVars vars = TempVars.get(); Spatial[] stack = vars.spatialStack; Spatial rootNode = this; int i = 0; while (true) { Spatial hisParent = rootNode.parent; if (hisParent == null) { rootNode.worldTransform.set(rootNode.localTransform); rootNode.refreshFlags &= ~RF_TRANSFORM; i--; break; } stack[i] = rootNode; if ((hisParent.refreshFlags & RF_TRANSFORM) == 0) { break; } rootNode = hisParent; i++; } vars.release(); for (int j = i; j >= 0; j--) { rootNode = stack[j]; // rootNode.worldTransform.set(rootNode.localTransform); // rootNode.worldTransform.combineWithParent(rootNode.parent.worldTransform); // rootNode.refreshFlags &= ~RF_TRANSFORM; rootNode.updateWorldTransforms(); } } }
/** * <code>getLocalRotation</code> retrieves the local rotation of this node. * * @return the local rotation of this node. */ public Quaternion getLocalRotation() { return localTransform.getRotation(); }
/** * <code>getLocalTranslation</code> retrieves the local translation of this node. * * @return the local translation of this node. */ public Vector3f getLocalTranslation() { return localTransform.getTranslation(); }
/** * <code>setLocalScale</code> sets the local scale of this node. * * @param localScale the new local scale. */ public void setLocalScale(Vector3f localScale) { localTransform.setScale(localScale); setTransformRefresh(); }
/** <code>setLocalScale</code> sets the local scale of this node. */ public void setLocalScale(float x, float y, float z) { localTransform.setScale(x, y, z); setTransformRefresh(); }
/** * <code>setLocalScale</code> sets the local scale of this node. * * @param localScale the new local scale, applied to x, y and z */ public void setLocalScale(float localScale) { localTransform.setScale(localScale); setTransformRefresh(); }
/** * <code>getLocalScale</code> retrieves the local scale of this node. * * @return the local scale of this node. */ public Vector3f getLocalScale() { return localTransform.getScale(); }
/** * <code>setLocalRotation</code> sets the local rotation of this node. * * @param quaternion the new local rotation. */ public void setLocalRotation(Quaternion quaternion) { localTransform.setRotation(quaternion); setTransformRefresh(); }
/** * <code>setLocalRotation</code> sets the local rotation of this node by using a {@link Matrix3f}. * * @param rotation the new local rotation. */ public void setLocalRotation(Matrix3f rotation) { localTransform.getRotation().fromRotationMatrix(rotation); setTransformRefresh(); }
/** * <code>getWorldRotation</code> retrieves the absolute rotation of the Spatial. * * @return the Spatial's world rotation quaternion. */ public Quaternion getWorldRotation() { checkDoTransformUpdate(); return worldTransform.getRotation(); }
/** * Convert a vector (in) from world coordinate space to this spatials' local coordinate space. * * @param in vector to read from * @param store where to write the result * @return the result (store) */ public Vector3f worldToLocal(final Vector3f in, final Vector3f store) { checkDoTransformUpdate(); return worldTransform.transformInverseVector(in, store); }
/** * Convert a vector (in) from this spatials' local coordinate space to world coordinate space. * * @param in vector to read from * @param store where to write the result (null to create a new vector, may be same as in) * @return the result (store) */ public Vector3f localToWorld(final Vector3f in, Vector3f store) { checkDoTransformUpdate(); return worldTransform.transformVector(in, store); }
/** * <code>getWorldTranslation</code> retrieves the absolute translation of the spatial. * * @return the Spatial's world tranlsation vector. */ public Vector3f getWorldTranslation() { checkDoTransformUpdate(); return worldTransform.getTranslation(); }
/** * <code>getWorldScale</code> retrieves the absolute scale factor of the spatial. * * @return the Spatial's world scale factor. */ public Vector3f getWorldScale() { checkDoTransformUpdate(); return worldTransform.getScale(); }