getAttachmentNode(): move target selection from SkeletonControl to Bone
This commit is contained in:
parent
b2aa1ff9f1
commit
9905c4f011
@ -34,8 +34,10 @@ package com.jme3.animation;
|
|||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.util.SafeArrayList;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
@ -701,16 +703,27 @@ public final class Bone implements Savable, JmeCloneable {
|
|||||||
* have an attachments node, create one. Models and effects attached to the
|
* have an attachments node, create one. Models and effects attached to the
|
||||||
* attachments node will follow this bone's motions.
|
* attachments node will follow this bone's motions.
|
||||||
*
|
*
|
||||||
* @param target a geometry animated by this bone, or null to indicate that
|
* @param boneIndex this bone's index in its skeleton (≥0)
|
||||||
* all geometries affected by this bone have the same global transform as
|
* @param targets a list of geometries animated by this bone's skeleton (not
|
||||||
* the attachment node's parent
|
* null, unaffected)
|
||||||
*/
|
*/
|
||||||
Node getAttachmentsNode(Geometry target) {
|
Node getAttachmentsNode(int boneIndex, SafeArrayList<Geometry> targets) {
|
||||||
|
targetGeometry = null;
|
||||||
|
/*
|
||||||
|
* Search for a geometry animated by this particular bone.
|
||||||
|
*/
|
||||||
|
for (Geometry geometry : targets) {
|
||||||
|
Mesh mesh = geometry.getMesh();
|
||||||
|
if (mesh != null && mesh.isAnimatedByBone(boneIndex)) {
|
||||||
|
targetGeometry = geometry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (attachNode == null) {
|
if (attachNode == null) {
|
||||||
attachNode = new Node(name + "_attachnode");
|
attachNode = new Node(name + "_attachnode");
|
||||||
attachNode.setUserData("AttachedBone", this);
|
attachNode.setUserData("AttachedBone", this);
|
||||||
}
|
}
|
||||||
targetGeometry = target;
|
|
||||||
|
|
||||||
return attachNode;
|
return attachNode;
|
||||||
}
|
}
|
||||||
|
@ -70,15 +70,12 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
* The skeleton of the model.
|
* The skeleton of the model.
|
||||||
*/
|
*/
|
||||||
private Skeleton skeleton;
|
private Skeleton skeleton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of targets which this controller effects.
|
* List of geometries affected by this control.
|
||||||
*/
|
*/
|
||||||
private SafeArrayList<Mesh> targets = new SafeArrayList<Mesh>(Mesh.class);
|
private SafeArrayList<Geometry> targets = new SafeArrayList<Geometry>(Geometry.class);
|
||||||
/**
|
|
||||||
* Geometry with an animated mesh, for calculating attachments node
|
|
||||||
* transforms. A null means no geometry is subject to this control.
|
|
||||||
*/
|
|
||||||
private Geometry targetGeometry = null;
|
|
||||||
/**
|
/**
|
||||||
* Used to track when a mesh was updated. Meshes are only updated if they
|
* Used to track when a mesh was updated. Meshes are only updated if they
|
||||||
* are visible in at least one camera.
|
* are visible in at least one camera.
|
||||||
@ -128,8 +125,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
for (Material m : materials) {
|
for (Material m : materials) {
|
||||||
m.setInt("NumberOfBones", numBones);
|
m.setInt("NumberOfBones", numBones);
|
||||||
}
|
}
|
||||||
for (Mesh mesh : targets) {
|
for (Geometry geometry : targets) {
|
||||||
if (mesh.isAnimated()) {
|
Mesh mesh = geometry.getMesh();
|
||||||
|
if (mesh != null && mesh.isAnimated()) {
|
||||||
mesh.prepareForAnim(false);
|
mesh.prepareForAnim(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,8 +139,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
m.clearParam("NumberOfBones");
|
m.clearParam("NumberOfBones");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Mesh mesh : targets) {
|
for (Geometry geometry : targets) {
|
||||||
if (mesh.isAnimated()) {
|
Mesh mesh = geometry.getMesh();
|
||||||
|
if (mesh != null && mesh.isAnimated()) {
|
||||||
mesh.prepareForAnim(true);
|
mesh.prepareForAnim(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,9 +219,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
*/
|
*/
|
||||||
private void findTargets(Geometry geometry) {
|
private void findTargets(Geometry geometry) {
|
||||||
Mesh mesh = geometry.getMesh();
|
Mesh mesh = geometry.getMesh();
|
||||||
if (mesh.isAnimated()) {
|
if (mesh != null && mesh.isAnimated()) {
|
||||||
targets.add(mesh);
|
targets.add(geometry);
|
||||||
targetGeometry = geometry;
|
|
||||||
materials.add(geometry.getMaterial());
|
materials.add(geometry.getMaterial());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,10 +246,11 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
|
|
||||||
offsetMatrices = skeleton.computeSkinningMatrices();
|
offsetMatrices = skeleton.computeSkinningMatrices();
|
||||||
|
|
||||||
for (Mesh mesh : targets) {
|
for (Geometry geometry : targets) {
|
||||||
// NOTE: This assumes that code higher up
|
Mesh mesh = geometry.getMesh();
|
||||||
// Already ensured those targets are animated
|
// NOTE: This assumes code higher up has
|
||||||
// otherwise a crash will happen in skin update
|
// already ensured this mesh is animated.
|
||||||
|
// Otherwise a crash will happen in skin update.
|
||||||
softwareSkinUpdate(mesh, offsetMatrices);
|
softwareSkinUpdate(mesh, offsetMatrices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,8 +324,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
|
|
||||||
//only do this for software updates
|
//only do this for software updates
|
||||||
void resetToBind() {
|
void resetToBind() {
|
||||||
for (Mesh mesh : targets) {
|
for (Geometry geometry : targets) {
|
||||||
if (mesh.isAnimated()) {
|
Mesh mesh = geometry.getMesh();
|
||||||
|
if (mesh != null && mesh.isAnimated()) {
|
||||||
Buffer bwBuff = mesh.getBuffer(Type.BoneWeight).getData();
|
Buffer bwBuff = mesh.getBuffer(Type.BoneWeight).getData();
|
||||||
Buffer biBuff = mesh.getBuffer(Type.BoneIndex).getData();
|
Buffer biBuff = mesh.getBuffer(Type.BoneIndex).getData();
|
||||||
if (!biBuff.hasArray() || !bwBuff.hasArray()) {
|
if (!biBuff.hasArray() || !bwBuff.hasArray()) {
|
||||||
@ -460,7 +460,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateTargetsAndMaterials(spatial);
|
updateTargetsAndMaterials(spatial);
|
||||||
Node n = b.getAttachmentsNode(targetGeometry);
|
int boneIndex = skeleton.getBoneIndex(b);
|
||||||
|
Node n = b.getAttachmentsNode(boneIndex, targets);
|
||||||
/*
|
/*
|
||||||
* Select a node to parent the attachments node.
|
* Select a node to parent the attachments node.
|
||||||
*/
|
*/
|
||||||
@ -485,12 +486,20 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns a copy of array of the targets meshes of this control
|
* Enumerate the target meshes of this control.
|
||||||
*
|
*
|
||||||
* @return
|
* @return a new array
|
||||||
*/
|
*/
|
||||||
public Mesh[] getTargets() {
|
public Mesh[] getTargets() {
|
||||||
return targets.toArray(new Mesh[targets.size()]);
|
Mesh[] result = new Mesh[targets.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Geometry geometry : targets) {
|
||||||
|
Mesh mesh = geometry.getMesh();
|
||||||
|
result[i] = mesh;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -791,7 +800,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
*/
|
*/
|
||||||
private void updateTargetsAndMaterials(Spatial spatial) {
|
private void updateTargetsAndMaterials(Spatial spatial) {
|
||||||
targets.clear();
|
targets.clear();
|
||||||
targetGeometry = null;
|
|
||||||
materials.clear();
|
materials.clear();
|
||||||
|
|
||||||
if (spatial instanceof Node) {
|
if (spatial instanceof Node) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -1408,6 +1408,45 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|||||||
getBuffer(Type.HWBoneIndex) != null;
|
getBuffer(Type.HWBoneIndex) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the specified bone animates this mesh.
|
||||||
|
*
|
||||||
|
* @param boneIndex the bone's index in its skeleton
|
||||||
|
* @return true if the specified bone animates this mesh, otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isAnimatedByBone(int boneIndex) {
|
||||||
|
VertexBuffer biBuf = getBuffer(VertexBuffer.Type.BoneIndex);
|
||||||
|
VertexBuffer wBuf = getBuffer(VertexBuffer.Type.BoneWeight);
|
||||||
|
if (biBuf == null || wBuf == null) {
|
||||||
|
return false; // no bone animation data
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer boneIndexBuffer = (ByteBuffer) biBuf.getData();
|
||||||
|
boneIndexBuffer.rewind();
|
||||||
|
int numBoneIndices = boneIndexBuffer.remaining();
|
||||||
|
assert numBoneIndices % 4 == 0 : numBoneIndices;
|
||||||
|
int numVertices = boneIndexBuffer.remaining() / 4;
|
||||||
|
|
||||||
|
FloatBuffer weightBuffer = (FloatBuffer) wBuf.getData();
|
||||||
|
weightBuffer.rewind();
|
||||||
|
int numWeights = weightBuffer.remaining();
|
||||||
|
assert numWeights == numVertices * 4 : numWeights;
|
||||||
|
/*
|
||||||
|
* Test each vertex to determine whether the bone affects it.
|
||||||
|
*/
|
||||||
|
byte biByte = (byte) boneIndex; // bone indices wrap after 127
|
||||||
|
for (int vIndex = 0; vIndex < numVertices; vIndex++) {
|
||||||
|
for (int wIndex = 0; wIndex < 4; wIndex++) {
|
||||||
|
byte bIndex = boneIndexBuffer.get();
|
||||||
|
float weight = weightBuffer.get();
|
||||||
|
if (wIndex < maxNumWeights && bIndex == biByte && weight != 0f) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the count of vertices used for each tessellation patch
|
* Sets the count of vertices used for each tessellation patch
|
||||||
* @param patchVertexCount
|
* @param patchVertexCount
|
||||||
|
Loading…
x
Reference in New Issue
Block a user