Fixed an issue where loaded glTF models couldn't use software skinning
This commit is contained in:
parent
510562a62d
commit
32b947a0ac
@ -44,8 +44,7 @@ import com.jme3.scene.VertexBuffer.Type;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import com.jme3.scene.control.Control;
|
||||
import com.jme3.shader.VarType;
|
||||
import com.jme3.util.SafeArrayList;
|
||||
import com.jme3.util.TempVars;
|
||||
import com.jme3.util.*;
|
||||
import com.jme3.util.clone.Cloner;
|
||||
import com.jme3.util.clone.JmeCloneable;
|
||||
import java.io.IOException;
|
||||
@ -112,7 +111,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
* Material references used for hardware skinning
|
||||
*/
|
||||
private Set<Material> materials = new HashSet<Material>();
|
||||
|
||||
|
||||
//temp reader
|
||||
private BufferUtils.ByteShortIntBufferReader indexReader = new BufferUtils.ByteShortIntBufferReader();
|
||||
/**
|
||||
* Serialization only. Do not use.
|
||||
*/
|
||||
@ -533,7 +534,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
if (maxWeightsPerVert <= 0) {
|
||||
throw new IllegalStateException("Max weights per vert is incorrectly set!");
|
||||
}
|
||||
|
||||
int fourMinusMaxWeights = 4 - maxWeightsPerVert;
|
||||
|
||||
// NOTE: This code assumes the vertex buffer is in bind pose
|
||||
@ -547,14 +547,13 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
fnb.rewind();
|
||||
|
||||
// get boneIndexes and weights for mesh
|
||||
ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
|
||||
indexReader.setBuffer(mesh.getBuffer(Type.BoneIndex).getData());
|
||||
FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
|
||||
|
||||
ib.rewind();
|
||||
indexReader.rewind();
|
||||
wb.rewind();
|
||||
|
||||
float[] weights = wb.array();
|
||||
byte[] indices = ib.array();
|
||||
int idxWeights = 0;
|
||||
|
||||
TempVars vars = TempVars.get();
|
||||
@ -592,7 +591,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
||||
float weight = weights[idxWeights];
|
||||
Matrix4f mat = offsetMatrices[indices[idxWeights++] & 0xff];
|
||||
Matrix4f mat = offsetMatrices[indexReader.getUnsigned(idxWeights++)];
|
||||
|
||||
rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
|
||||
ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
|
||||
@ -665,14 +664,13 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
|
||||
// get boneIndexes and weights for mesh
|
||||
ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
|
||||
indexReader.setBuffer(mesh.getBuffer(Type.BoneIndex).getData());
|
||||
FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
|
||||
|
||||
ib.rewind();
|
||||
indexReader.rewind();
|
||||
wb.rewind();
|
||||
|
||||
float[] weights = wb.array();
|
||||
byte[] indices = ib.array();
|
||||
int idxWeights = 0;
|
||||
|
||||
TempVars vars = TempVars.get();
|
||||
@ -725,7 +723,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
||||
float weight = weights[idxWeights];
|
||||
Matrix4f mat = offsetMatrices[indices[idxWeights++] & 0xff];
|
||||
Matrix4f mat = offsetMatrices[indexReader.getUnsigned(idxWeights++)];
|
||||
|
||||
rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
|
||||
ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
|
||||
|
@ -1344,6 +1344,9 @@ public final class BufferUtils {
|
||||
public static class ByteShortIntBufferReader {
|
||||
Buffer buffer;
|
||||
|
||||
public ByteShortIntBufferReader() {
|
||||
}
|
||||
|
||||
public ByteShortIntBufferReader(Buffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
@ -1372,6 +1375,22 @@ public final class BufferUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public int getUnsigned(int index) {
|
||||
if (buffer instanceof ByteBuffer) {
|
||||
return ((ByteBuffer) buffer).get(index) & 0xff;
|
||||
} else if (buffer instanceof ShortBuffer) {
|
||||
return ((ShortBuffer) buffer).get(index) & 0xffff;
|
||||
} else if (buffer instanceof IntBuffer) {
|
||||
return ((IntBuffer) buffer).get(index) & 0xffffff;
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Buffer must be a ByteBuffer, a ShortBuffer or an IntBuffer");
|
||||
}
|
||||
}
|
||||
|
||||
public void setBuffer(Buffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public void rewind() {
|
||||
buffer.rewind();
|
||||
}
|
||||
|
@ -382,49 +382,58 @@ public class GltfUtils {
|
||||
|
||||
public static void handleSkinningBuffers(Mesh mesh, IntMap<GltfLoader.SkinBuffers> skinBuffers) {
|
||||
if (skinBuffers.size() > 0) {
|
||||
if (skinBuffers.size() == 1) {
|
||||
GltfLoader.SkinBuffers buffs = skinBuffers.get(0);
|
||||
setSkinBuffers(mesh, buffs.joints, skinBuffers.get(0).weights, buffs.componentSize);
|
||||
} else {
|
||||
|
||||
int length = skinBuffers.get(0).joints.length;
|
||||
short[] jointsArray = new short[length];
|
||||
float[] weightsArray = new float[length];
|
||||
List<GltfLoader.WeightData> weightData = new ArrayList<>();
|
||||
int componentSize = 1;
|
||||
|
||||
for (int i = 0; i < weightsArray.length; i += 4) {
|
||||
weightData.clear();
|
||||
for (int j = 0; j < skinBuffers.size(); j++) {
|
||||
GltfLoader.SkinBuffers buffs = skinBuffers.get(j);
|
||||
for (int k = 0; k < 4; k++) {
|
||||
weightData.add(new GltfLoader.WeightData(buffs.weights[i + k], buffs.joints[i + k], buffs.componentSize));
|
||||
}
|
||||
int length = skinBuffers.get(0).joints.length;
|
||||
short[] jointsArray = new short[length];
|
||||
float[] weightsArray = new float[length];
|
||||
List<GltfLoader.WeightData> weightData = new ArrayList<>();
|
||||
int componentSize = 1;
|
||||
|
||||
for (int i = 0; i < weightsArray.length; i += 4) {
|
||||
weightData.clear();
|
||||
for (int j = 0; j < skinBuffers.size(); j++) {
|
||||
GltfLoader.SkinBuffers buffs = skinBuffers.get(j);
|
||||
for (int k = 0; k < 4; k++) {
|
||||
weightData.add(new GltfLoader.WeightData(buffs.weights[i + k], buffs.joints[i + k], buffs.componentSize));
|
||||
}
|
||||
Collections.sort(weightData, new Comparator<GltfLoader.WeightData>() {
|
||||
@Override
|
||||
public int compare(GltfLoader.WeightData o1, GltfLoader.WeightData o2) {
|
||||
if (o1.value > o2.value) {
|
||||
return -1;
|
||||
} else if (o1.value < o2.value) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (int j = 0; j < 4; j++) {
|
||||
GltfLoader.WeightData data = weightData.get(j);
|
||||
jointsArray[i + j] = data.index;
|
||||
weightsArray[i + j] = data.value;
|
||||
if (data.componentSize > componentSize) {
|
||||
componentSize = data.componentSize;
|
||||
|
||||
}
|
||||
Collections.sort(weightData, new Comparator<GltfLoader.WeightData>() {
|
||||
@Override
|
||||
public int compare(GltfLoader.WeightData o1, GltfLoader.WeightData o2) {
|
||||
if (o1.value > o2.value) {
|
||||
return -1;
|
||||
} else if (o1.value < o2.value) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
float sum = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
GltfLoader.WeightData data = weightData.get(j);
|
||||
jointsArray[i + j] = data.index;
|
||||
weightsArray[i + j] = data.value;
|
||||
sum += data.value;
|
||||
if (data.value > 0 && (j + 1) > mesh.getMaxNumWeights()) {
|
||||
mesh.setMaxNumWeights(j + 1);
|
||||
}
|
||||
if (data.componentSize > componentSize) {
|
||||
componentSize = data.componentSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (sum != 1f) {
|
||||
// compute new vals based on sum
|
||||
float sumToB = sum == 0 ? 0 : 1f / sum;
|
||||
weightsArray[i] *= sumToB;
|
||||
weightsArray[i + 1] *= sumToB;
|
||||
weightsArray[i + 2] *= sumToB;
|
||||
weightsArray[i + 3] *= sumToB;
|
||||
}
|
||||
setSkinBuffers(mesh, jointsArray, weightsArray, componentSize);
|
||||
}
|
||||
setSkinBuffers(mesh, jointsArray, weightsArray, componentSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user