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.math.*;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Mesh;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.util.SafeArrayList;
|
||||
import com.jme3.util.TempVars;
|
||||
import com.jme3.util.clone.JmeCloneable;
|
||||
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
|
||||
* attachments node will follow this bone's motions.
|
||||
*
|
||||
* @param target a geometry animated by this bone, or null to indicate that
|
||||
* all geometries affected by this bone have the same global transform as
|
||||
* the attachment node's parent
|
||||
* @param boneIndex this bone's index in its skeleton (≥0)
|
||||
* @param targets a list of geometries animated by this bone's skeleton (not
|
||||
* 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) {
|
||||
attachNode = new Node(name + "_attachnode");
|
||||
attachNode.setUserData("AttachedBone", this);
|
||||
}
|
||||
targetGeometry = target;
|
||||
|
||||
return attachNode;
|
||||
}
|
||||
|
@ -70,15 +70,12 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
* The skeleton of the model.
|
||||
*/
|
||||
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);
|
||||
/**
|
||||
* Geometry with an animated mesh, for calculating attachments node
|
||||
* transforms. A null means no geometry is subject to this control.
|
||||
*/
|
||||
private Geometry targetGeometry = null;
|
||||
private SafeArrayList<Geometry> targets = new SafeArrayList<Geometry>(Geometry.class);
|
||||
|
||||
/**
|
||||
* Used to track when a mesh was updated. Meshes are only updated if they
|
||||
* are visible in at least one camera.
|
||||
@ -128,8 +125,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
for (Material m : materials) {
|
||||
m.setInt("NumberOfBones", numBones);
|
||||
}
|
||||
for (Mesh mesh : targets) {
|
||||
if (mesh.isAnimated()) {
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
mesh.prepareForAnim(false);
|
||||
}
|
||||
}
|
||||
@ -141,8 +139,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
m.clearParam("NumberOfBones");
|
||||
}
|
||||
}
|
||||
for (Mesh mesh : targets) {
|
||||
if (mesh.isAnimated()) {
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
mesh.prepareForAnim(true);
|
||||
}
|
||||
}
|
||||
@ -220,9 +219,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
*/
|
||||
private void findTargets(Geometry geometry) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh.isAnimated()) {
|
||||
targets.add(mesh);
|
||||
targetGeometry = geometry;
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
targets.add(geometry);
|
||||
materials.add(geometry.getMaterial());
|
||||
}
|
||||
}
|
||||
@ -248,10 +246,11 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
offsetMatrices = skeleton.computeSkinningMatrices();
|
||||
|
||||
for (Mesh mesh : targets) {
|
||||
// NOTE: This assumes that code higher up
|
||||
// Already ensured those targets are animated
|
||||
// otherwise a crash will happen in skin update
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
// NOTE: This assumes code higher up has
|
||||
// already ensured this mesh is animated.
|
||||
// Otherwise a crash will happen in skin update.
|
||||
softwareSkinUpdate(mesh, offsetMatrices);
|
||||
}
|
||||
}
|
||||
@ -325,8 +324,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
//only do this for software updates
|
||||
void resetToBind() {
|
||||
for (Mesh mesh : targets) {
|
||||
if (mesh.isAnimated()) {
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
Buffer bwBuff = mesh.getBuffer(Type.BoneWeight).getData();
|
||||
Buffer biBuff = mesh.getBuffer(Type.BoneIndex).getData();
|
||||
if (!biBuff.hasArray() || !bwBuff.hasArray()) {
|
||||
@ -460,7 +460,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -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() {
|
||||
return targets.toArray(new Mesh[targets.size()]);
|
||||
public Mesh[] getTargets() {
|
||||
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) {
|
||||
targets.clear();
|
||||
targetGeometry = null;
|
||||
materials.clear();
|
||||
|
||||
if (spatial instanceof Node) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param patchVertexCount
|
||||
|
Loading…
x
Reference in New Issue
Block a user