/** @return a copy of this quaternion */ public Quaternion cpy () { return new Quaternion(this); }
private final static Quaternion getRotationAtTime (final NodeAnimation nodeAnim, final float time, final Quaternion out) { if (nodeAnim.rotation == null) return out.set(nodeAnim.node.rotation); if (nodeAnim.rotation.size == 1) return out.set(nodeAnim.rotation.get(0).value); int index = getFirstKeyframeIndexAtTime(nodeAnim.rotation, time); final NodeKeyframe firstKeyframe = nodeAnim.rotation.get(index); out.set((Quaternion)firstKeyframe.value); if (++index < nodeAnim.rotation.size) { final NodeKeyframe<Quaternion> secondKeyframe = nodeAnim.rotation.get(index); final float t = (time - firstKeyframe.keytime) / (secondKeyframe.keytime - firstKeyframe.keytime); out.slerp(secondKeyframe.value, t); } return out; }
/** Sets this matrix to a rotation matrix from the given euler angles. * @param yaw the yaw in degrees * @param pitch the pitch in degrees * @param roll the roll in degrees * @return This matrix */ public Matrix4 setFromEulerAngles (float yaw, float pitch, float roll) { quat.setEulerAngles(yaw, pitch, roll); return set(quat); }
/** Spherical linearly interpolates multiple quaternions and stores the result in this Quaternion. Will not destroy the data * previously inside the elements of q. result = (q_1^w_1)*(q_2^w_2)* ... *(q_n^w_n) where w_i=1/n. * @param q List of quaternions * @return This quaternion for chaining */ public Quaternion slerp (Quaternion[] q) { // Calculate exponents and multiply everything from left to right final float w = 1.0f / q.length; set(q[0]).exp(w); for (int i = 1; i < q.length; i++) mul(tmp1.set(q[i]).exp(w)); nor(); return this; }
groups.add(activeGroup); for (int i = 1; i < tokens.length - 2; i--) { parts = tokens[1].split("/"); faces.add(getIndex(parts[0], verts.size)); if (parts.length > 2) { if (i == 1) activeGroup.hasNorms = true; faces.add(getIndex(parts[2], norms.size)); node.id = nodeId; node.meshId = meshId; node.scale = new Vector3(1, 1, 1); node.translation = new Vector3(); node.rotation = new Quaternion(); ModelNodePart pm = new ModelNodePart(); pm.meshPartId = partId;
nodeAnim.translation = new Array<NodeKeyframe<Vector3>>(); nodeAnim.translation.ensureCapacity(nanim.translation.size); for (ModelNodeKeyframe<Vector3> kf : nanim.translation) { if (kf.keytime > animation.duration) animation.duration = kf.keytime; nodeAnim.translation.add(new NodeKeyframe<Vector3>(kf.keytime, new Vector3(kf.value == null ? node.translation : kf.value))); for (ModelNodeKeyframe<Quaternion> kf : nanim.rotation) { if (kf.keytime > animation.duration) animation.duration = kf.keytime; nodeAnim.rotation.add(new NodeKeyframe<Quaternion>(kf.keytime, new Quaternion(kf.value == null ? node.rotation : kf.value))); if (kf.keytime > animation.duration) animation.duration = kf.keytime; nodeAnim.scaling.add(new NodeKeyframe<Vector3>(kf.keytime, new Vector3(kf.value == null ? node.scale : kf.value)));
/** Creates a nested copy of this Node, any child nodes are copied using the {@link #copy()} method. This will detach this node * from its parent, but does not attach it to the parent of node being copied. The {@link #parts} are copied using the * {@link NodePart#copy()} method. Note that that method copies the material and nodes (bones) by reference. If you intend to * use this node in a different node tree (e.g. a different Model or ModelInstance) then you will need to update these * references afterwards. * * Override this method in your custom Node class to copy any additional fields you've added. * @return This Node for chaining */ protected Node set (Node other) { detach(); id = other.id; isAnimated = other.isAnimated; inheritTransform = other.inheritTransform; translation.set(other.translation); rotation.set(other.rotation); scale.set(other.scale); localTransform.set(other.localTransform); globalTransform.set(other.globalTransform); parts.clear(); for (NodePart nodePart : other.parts) { parts.add(nodePart.copy()); } children.clear(); for (Node child : other.getChildren()) { addChild(child.copy()); } return this; }
/** Averages the given transforms with the given weights and stores the result in this matrix. Translations and scales are * lerped while rotations are slerped. Does not destroy the data contained in t or w; Sum of w_i must be equal to 1, or * unexpected results will occur. * @param t List of transforms * @param w List of weights * @return This matrix for chaining */ public Matrix4 avg (Matrix4[] t, float[] w) { tmpVec.set(t[0].getScale(tmpUp).scl(w[0])); quat.set(t[0].getRotation(quat2).exp(w[0])); tmpForward.set(t[0].getTranslation(tmpUp).scl(w[0])); for (int i = 1; i < t.length; i++) { tmpVec.add(t[i].getScale(tmpUp).scl(w[i])); quat.mul(t[i].getRotation(quat2).exp(w[i])); tmpForward.add(t[i].getTranslation(tmpUp).scl(w[i])); } quat.nor(); setToScaling(tmpVec); rotate(quat); setTranslation(tmpForward); return this; }
private void doneLoading () { Model model = assets.get("data/g3d/invaders.g3dj", Model.class); for (int i = 0; i < model.nodes.size; i++) { String id = model.nodes.get(i).id; ModelInstance instance = new ModelInstance(model, id); Node node = instance.getNode(id); instance.transform.set(node.globalTransform); node.translation.set(0, 0, 0); node.scale.set(1, 1, 1); node.rotation.idt(); instance.calculateTransforms(); if (id.equals("space")) { space = instance; continue; } instances.add(instance); if (id.equals("ship")) ship = instance; else if (id.startsWith("block")) blocks.add(instance); else if (id.startsWith("invader")) invaders.add(instance); } loading = false; }
/** @param model The source {@link Model} * @param transform The {@link Matrix4} instance for this ModelInstance to reference or null to create a new matrix. * @param nodeId The ID of the {@link Node} within the {@link Model} for the instance to contain * @param recursive True to recursively search the Model's node tree, false to only search for a root node * @param parentTransform True to apply the parent's node transform to the instance (only applicable if recursive is true). * @param mergeTransform True to apply the source node transform to the instance transform, resetting the node transform. */ public ModelInstance (final Model model, final Matrix4 transform, final String nodeId, boolean recursive, boolean parentTransform, boolean mergeTransform, boolean shareKeyframes) { this.model = model; this.transform = transform == null ? new Matrix4() : transform; Node copy, node = model.getNode(nodeId, recursive); this.nodes.add(copy = node.copy()); if (mergeTransform) { this.transform.mul(parentTransform ? node.globalTransform : node.localTransform); copy.translation.set(0, 0, 0); copy.rotation.idt(); copy.scale.set(1, 1, 1); } else if (parentTransform && copy.hasParent()) this.transform.mul(node.getParent().globalTransform); invalidate(); copyAnimations(model.animations, shareKeyframes); calculateTransforms(); }
new BlendingAttribute() ); instances.add(new ModelInstance(floorModel, "floor")); instances.add(tree = new ModelInstance(floorModel, "tree")); assets.load("data/g3d/knight.g3db", Model.class); loading = true; BoundingBox bbox = new BoundingBox(); character.calculateBoundingBox(bbox); character.transform.setToRotation(Vector3.Y, 180).trn(0, -bbox.min.y, 0); instances.add(character); animation = new AnimationController(character); animation.animate("Idle", -1, 1f, null, 0.2f); ship.detach(); ship.translation.x = 10f; // offset from the sword node to the tip of the sword, in rest pose ship.rotation.set(Vector3.Z, 90f); ship.scale.scl(5f); ship.parts.get(0).enabled = false; character.getNode("sword").addChild(ship);
/** Averages the given transform with this one and stores the result in this matrix. Translations and scales are lerped while * rotations are slerped. * @param other The other transform * @param w Weight of this transform; weight of the other transform is (1 - w) * @return This matrix for chaining */ public Matrix4 avg (Matrix4 other, float w) { getScale(tmpVec); other.getScale(tmpForward); getRotation(quat); other.getRotation(quat2); getTranslation(tmpUp); other.getTranslation(right); setToScaling(tmpVec.scl(w).add(tmpForward.scl(1 - w))); rotate(quat.slerp(quat2, 1 - w)); setTranslation(tmpUp.scl(w).add(right.scl(1 - w))); return this; }
jsonNode.translation = translation == null ? null : new Vector3(translation.getFloat(0), translation.getFloat(1), translation.getFloat(2)); jsonNode.rotation = rotation == null ? null : new Quaternion(rotation.getFloat(0), rotation.getFloat(1), rotation.getFloat(2), rotation.getFloat(3)); jsonNode.scale = scale == null ? null : new Vector3(scale.getFloat(0), scale.getFloat(1), scale.getFloat(2)); if (nodeId == null) throw new GdxRuntimeException("Bone node ID missing"); Matrix4 transform = new Matrix4(); if (val != null && val.size >= 3) transform.translate(val.getFloat(0), val.getFloat(1), val.getFloat(2)); transform.rotate(tempQ.set(val.getFloat(0), val.getFloat(1), val.getFloat(2), val.getFloat(3)));
@Override public void update(float deltaTime) { super.update(deltaTime); followTransform.getTranslation(worldPos); camera.view.getRotation(quat).conjugate(); if (faceUp) { modelInstance.transform.setFromEulerAngles(quat.getYaw(), -90, quat.getRoll()); } else { modelInstance.transform.set(quat); } modelInstance.transform.setTranslation(worldPos.add(offset)); } }
public void processDragRotation(Vector2 cursorDelta) { tmp1.set(camera.targetDirection).crs(camera.targetUp).nor(); deltaRotation.setEulerAngles(cursorDelta.x, cursorDelta.y * tmp1.x, cursorDelta.y * tmp1.z); camera.rotateAround(worldGroundTarget, deltaRotation); }
/** Sets the matrix to a rotation matrix around the given axis. * * @param axis The axis * @param degrees The angle in degrees * @return This matrix for the purpose of chaining methods together. */ public Matrix4 setToRotation (Vector3 axis, float degrees) { if (degrees == 0) { idt(); return this; } return set(quat.set(axis, degrees)); }