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.AbstractControl;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.shader.VarType;
|
import com.jme3.shader.VarType;
|
||||||
import com.jme3.util.SafeArrayList;
|
import com.jme3.util.*;
|
||||||
import com.jme3.util.TempVars;
|
|
||||||
import com.jme3.util.clone.Cloner;
|
import com.jme3.util.clone.Cloner;
|
||||||
import com.jme3.util.clone.JmeCloneable;
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -113,6 +112,8 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
*/
|
*/
|
||||||
private Set<Material> materials = new HashSet<Material>();
|
private Set<Material> materials = new HashSet<Material>();
|
||||||
|
|
||||||
|
//temp reader
|
||||||
|
private BufferUtils.ByteShortIntBufferReader indexReader = new BufferUtils.ByteShortIntBufferReader();
|
||||||
/**
|
/**
|
||||||
* Serialization only. Do not use.
|
* Serialization only. Do not use.
|
||||||
*/
|
*/
|
||||||
@ -533,7 +534,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
if (maxWeightsPerVert <= 0) {
|
if (maxWeightsPerVert <= 0) {
|
||||||
throw new IllegalStateException("Max weights per vert is incorrectly set!");
|
throw new IllegalStateException("Max weights per vert is incorrectly set!");
|
||||||
}
|
}
|
||||||
|
|
||||||
int fourMinusMaxWeights = 4 - maxWeightsPerVert;
|
int fourMinusMaxWeights = 4 - maxWeightsPerVert;
|
||||||
|
|
||||||
// NOTE: This code assumes the vertex buffer is in bind pose
|
// 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();
|
fnb.rewind();
|
||||||
|
|
||||||
// get boneIndexes and weights for mesh
|
// 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();
|
FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
|
||||||
|
|
||||||
ib.rewind();
|
indexReader.rewind();
|
||||||
wb.rewind();
|
wb.rewind();
|
||||||
|
|
||||||
float[] weights = wb.array();
|
float[] weights = wb.array();
|
||||||
byte[] indices = ib.array();
|
|
||||||
int idxWeights = 0;
|
int idxWeights = 0;
|
||||||
|
|
||||||
TempVars vars = TempVars.get();
|
TempVars vars = TempVars.get();
|
||||||
@ -592,7 +591,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
|
|
||||||
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
||||||
float weight = weights[idxWeights];
|
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;
|
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;
|
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
|
// 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();
|
FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
|
||||||
|
|
||||||
ib.rewind();
|
indexReader.rewind();
|
||||||
wb.rewind();
|
wb.rewind();
|
||||||
|
|
||||||
float[] weights = wb.array();
|
float[] weights = wb.array();
|
||||||
byte[] indices = ib.array();
|
|
||||||
int idxWeights = 0;
|
int idxWeights = 0;
|
||||||
|
|
||||||
TempVars vars = TempVars.get();
|
TempVars vars = TempVars.get();
|
||||||
@ -725,7 +723,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
|||||||
|
|
||||||
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
||||||
float weight = weights[idxWeights];
|
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;
|
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;
|
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 {
|
public static class ByteShortIntBufferReader {
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
|
public ByteShortIntBufferReader() {
|
||||||
|
}
|
||||||
|
|
||||||
public ByteShortIntBufferReader(Buffer buffer) {
|
public ByteShortIntBufferReader(Buffer buffer) {
|
||||||
this.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() {
|
public void rewind() {
|
||||||
buffer.rewind();
|
buffer.rewind();
|
||||||
}
|
}
|
||||||
|
@ -382,11 +382,6 @@ public class GltfUtils {
|
|||||||
|
|
||||||
public static void handleSkinningBuffers(Mesh mesh, IntMap<GltfLoader.SkinBuffers> skinBuffers) {
|
public static void handleSkinningBuffers(Mesh mesh, IntMap<GltfLoader.SkinBuffers> skinBuffers) {
|
||||||
if (skinBuffers.size() > 0) {
|
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;
|
int length = skinBuffers.get(0).joints.length;
|
||||||
short[] jointsArray = new short[length];
|
short[] jointsArray = new short[length];
|
||||||
float[] weightsArray = new float[length];
|
float[] weightsArray = new float[length];
|
||||||
@ -414,19 +409,33 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
float sum = 0;
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
GltfLoader.WeightData data = weightData.get(j);
|
GltfLoader.WeightData data = weightData.get(j);
|
||||||
jointsArray[i + j] = data.index;
|
jointsArray[i + j] = data.index;
|
||||||
weightsArray[i + j] = data.value;
|
weightsArray[i + j] = data.value;
|
||||||
|
sum += data.value;
|
||||||
|
if (data.value > 0 && (j + 1) > mesh.getMaxNumWeights()) {
|
||||||
|
mesh.setMaxNumWeights(j + 1);
|
||||||
|
}
|
||||||
if (data.componentSize > componentSize) {
|
if (data.componentSize > componentSize) {
|
||||||
componentSize = data.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void setSkinBuffers(Mesh mesh, short[] jointsArray, float[] weightsArray, int componentSize) {
|
public static void setSkinBuffers(Mesh mesh, short[] jointsArray, float[] weightsArray, int componentSize) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user