Compute the 4 more weighted bone index for skin animation when there are several Joint buffers for a mesh.
This commit is contained in:
parent
911d8d77ef
commit
225afd0f92
@ -11,6 +11,8 @@ import com.jme3.renderer.queue.RenderQueue;
|
|||||||
import com.jme3.scene.*;
|
import com.jme3.scene.*;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import com.jme3.texture.Texture2D;
|
import com.jme3.texture.Texture2D;
|
||||||
|
import com.jme3.util.BufferUtils;
|
||||||
|
import com.jme3.util.IntMap;
|
||||||
import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
|
import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -50,13 +52,12 @@ public class GltfLoader implements AssetLoader {
|
|||||||
private FloatArrayPopulator floatArrayPopulator = new FloatArrayPopulator();
|
private FloatArrayPopulator floatArrayPopulator = new FloatArrayPopulator();
|
||||||
private Vector3fArrayPopulator vector3fArrayPopulator = new Vector3fArrayPopulator();
|
private Vector3fArrayPopulator vector3fArrayPopulator = new Vector3fArrayPopulator();
|
||||||
private QuaternionArrayPopulator quaternionArrayPopulator = new QuaternionArrayPopulator();
|
private QuaternionArrayPopulator quaternionArrayPopulator = new QuaternionArrayPopulator();
|
||||||
private Matrix4fArrayPopulator matrix4fArrayPopulator = new Matrix4fArrayPopulator();
|
|
||||||
private static Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>();
|
private static Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>();
|
||||||
private boolean useNormalsFlag = false;
|
private boolean useNormalsFlag = false;
|
||||||
private Transform tmpTransforms = new Transform();
|
|
||||||
private Quaternion tmpQuat = new Quaternion();
|
private Quaternion tmpQuat = new Quaternion();
|
||||||
|
|
||||||
Map<SkinData, List<Spatial>> skinnedSpatials = new HashMap<>();
|
Map<SkinData, List<Spatial>> skinnedSpatials = new HashMap<>();
|
||||||
|
IntMap<SkinBuffers> skinBuffers = new IntMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
defaultMaterialAdapters.put("pbrMetallicRoughness", new PBRMaterialAdapter());
|
defaultMaterialAdapters.put("pbrMetallicRoughness", new PBRMaterialAdapter());
|
||||||
@ -323,9 +324,29 @@ public class GltfLoader implements AssetLoader {
|
|||||||
}
|
}
|
||||||
JsonObject attributes = meshObject.getAsJsonObject("attributes");
|
JsonObject attributes = meshObject.getAsJsonObject("attributes");
|
||||||
assertNotNull(attributes, "No attributes defined for mesh " + mesh);
|
assertNotNull(attributes, "No attributes defined for mesh " + mesh);
|
||||||
|
|
||||||
|
skinBuffers.clear();
|
||||||
|
|
||||||
for (Map.Entry<String, JsonElement> entry : attributes.entrySet()) {
|
for (Map.Entry<String, JsonElement> entry : attributes.entrySet()) {
|
||||||
mesh.setBuffer(readAccessorData(entry.getValue().getAsInt(), new VertexBufferPopulator(getVertexBufferType(entry.getKey()))));
|
//special case for joints and weights buffer. If there are more than 4 bones per vertex, there might be several of them
|
||||||
|
//we need to read them all and to keep only the 4 that have the most weight on the vertex.
|
||||||
|
String bufferType = entry.getKey();
|
||||||
|
if (bufferType.startsWith("JOINTS")) {
|
||||||
|
SkinBuffers buffs = getSkinBuffers(bufferType);
|
||||||
|
SkinBuffers buffer = readAccessorData(entry.getValue().getAsInt(), new JointArrayPopulator());
|
||||||
|
buffs.joints = buffer.joints;
|
||||||
|
buffs.componentSize = buffer.componentSize;
|
||||||
|
} else if (bufferType.startsWith("WEIGHTS")) {
|
||||||
|
SkinBuffers buffs = getSkinBuffers(bufferType);
|
||||||
|
buffs.weights = readAccessorData(entry.getValue().getAsInt(), new FloatArrayPopulator());
|
||||||
|
} else {
|
||||||
|
VertexBuffer vb = readAccessorData(entry.getValue().getAsInt(), new VertexBufferPopulator(getVertexBufferType(bufferType)));
|
||||||
|
if (vb != null) {
|
||||||
|
mesh.setBuffer(vb);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
handleSkinningBuffers(mesh, skinBuffers);
|
||||||
|
|
||||||
if (mesh.getBuffer(VertexBuffer.Type.BoneIndex) != null) {
|
if (mesh.getBuffer(VertexBuffer.Type.BoneIndex) != null) {
|
||||||
//the mesh has some skinning let's create needed buffers for HW skinning
|
//the mesh has some skinning let's create needed buffers for HW skinning
|
||||||
@ -374,6 +395,28 @@ public class GltfLoader implements AssetLoader {
|
|||||||
return geomArray;
|
return geomArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class WeightData {
|
||||||
|
float value;
|
||||||
|
short index;
|
||||||
|
int componentSize;
|
||||||
|
|
||||||
|
public WeightData(float value, short index, int componentSize) {
|
||||||
|
this.value = value;
|
||||||
|
this.index = index;
|
||||||
|
this.componentSize = componentSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SkinBuffers getSkinBuffers(String bufferType) {
|
||||||
|
int bufIndex = getIndex(bufferType);
|
||||||
|
SkinBuffers buffs = skinBuffers.get(bufIndex);
|
||||||
|
if (buffs == null) {
|
||||||
|
buffs = new SkinBuffers();
|
||||||
|
skinBuffers.put(bufIndex, buffs);
|
||||||
|
}
|
||||||
|
return buffs;
|
||||||
|
}
|
||||||
|
|
||||||
private <R> R readAccessorData(int accessorIndex, Populator<R> populator) throws IOException {
|
private <R> R readAccessorData(int accessorIndex, Populator<R> populator) throws IOException {
|
||||||
|
|
||||||
assertNotNull(accessors, "No accessor attribute in the gltf file");
|
assertNotNull(accessors, "No accessor attribute in the gltf file");
|
||||||
@ -399,8 +442,7 @@ public class GltfLoader implements AssetLoader {
|
|||||||
return populator.populate(bufferViewIndex, componentType, type, count, byteOffset);
|
return populator.populate(bufferViewIndex, componentType, type, count, byteOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Object store, int numComponents) throws IOException {
|
private void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Object store, int numComponents, int componentSize) throws IOException {
|
||||||
|
|
||||||
|
|
||||||
JsonObject bufferView = bufferViews.get(bufferViewIndex).getAsJsonObject();
|
JsonObject bufferView = bufferViews.get(bufferViewIndex).getAsJsonObject();
|
||||||
Integer bufferIndex = getAsInteger(bufferView, "buffer");
|
Integer bufferIndex = getAsInteger(bufferView, "buffer");
|
||||||
@ -415,7 +457,7 @@ public class GltfLoader implements AssetLoader {
|
|||||||
//int target = getAsInteger(bufferView, "target", 0);
|
//int target = getAsInteger(bufferView, "target", 0);
|
||||||
|
|
||||||
byte[] data = readData(bufferIndex);
|
byte[] data = readData(bufferIndex);
|
||||||
populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents);
|
populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents, componentSize);
|
||||||
|
|
||||||
//TODO extensions?
|
//TODO extensions?
|
||||||
//TODO extras?
|
//TODO extras?
|
||||||
@ -606,7 +648,15 @@ public class GltfLoader implements AssetLoader {
|
|||||||
//check if we are loading the same time array
|
//check if we are loading the same time array
|
||||||
//TODO specs actually don't forbid this...maybe remove this check and handle it.
|
//TODO specs actually don't forbid this...maybe remove this check and handle it.
|
||||||
if (animData.times != times) {
|
if (animData.times != times) {
|
||||||
throw new AssetLoadException("Channel has different input accessors for samplers");
|
logger.log(Level.WARNING, "Channel has different input accessors for samplers");
|
||||||
|
// for (float time : animData.times) {
|
||||||
|
// System.err.print(time + ", ");
|
||||||
|
// }
|
||||||
|
// System.err.println("");
|
||||||
|
// for (float time : times) {
|
||||||
|
// System.err.print(time + ", ");
|
||||||
|
// }
|
||||||
|
// System.err.println("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (animData.length == null) {
|
if (animData.length == null) {
|
||||||
@ -623,7 +673,6 @@ public class GltfLoader implements AssetLoader {
|
|||||||
Quaternion[] rotations = readAccessorData(dataIndex, quaternionArrayPopulator);
|
Quaternion[] rotations = readAccessorData(dataIndex, quaternionArrayPopulator);
|
||||||
animData.rotations = rotations;
|
animData.rotations = rotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
@ -911,6 +960,20 @@ public class GltfLoader implements AssetLoader {
|
|||||||
Transform armatureTransforms;
|
Transform armatureTransforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class SkinBuffers {
|
||||||
|
short[] joints;
|
||||||
|
float[] weights;
|
||||||
|
int componentSize;
|
||||||
|
|
||||||
|
public SkinBuffers(short[] joints, int componentSize) {
|
||||||
|
this.joints = joints;
|
||||||
|
this.componentSize = componentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkinBuffers() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private interface Populator<T> {
|
private interface Populator<T> {
|
||||||
T populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException;
|
T populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException;
|
||||||
}
|
}
|
||||||
@ -925,6 +988,11 @@ public class GltfLoader implements AssetLoader {
|
|||||||
@Override
|
@Override
|
||||||
public VertexBuffer populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
public VertexBuffer populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
||||||
|
|
||||||
|
if (bufferType == null) {
|
||||||
|
logger.log(Level.WARNING, "could not assign data to any VertexBuffer type for buffer view " + bufferViewIndex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
VertexBuffer vb = new VertexBuffer(bufferType);
|
VertexBuffer vb = new VertexBuffer(bufferType);
|
||||||
VertexBuffer.Format format = getVertexBufferFormat(componentType);
|
VertexBuffer.Format format = getVertexBufferFormat(componentType);
|
||||||
int numComponents = getNumberOfComponents(type);
|
int numComponents = getNumberOfComponents(type);
|
||||||
@ -935,7 +1003,7 @@ public class GltfLoader implements AssetLoader {
|
|||||||
//no referenced buffer, specs says to pad the buffer with zeros.
|
//no referenced buffer, specs says to pad the buffer with zeros.
|
||||||
padBuffer(buff, bufferSize);
|
padBuffer(buff, bufferSize);
|
||||||
} else {
|
} else {
|
||||||
readBuffer(bufferViewIndex, byteOffset, bufferSize, buff, numComponents);
|
readBuffer(bufferViewIndex, byteOffset, bufferSize, buff, numComponents, format.getComponentSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferType == VertexBuffer.Type.Index) {
|
if (bufferType == VertexBuffer.Type.Index) {
|
||||||
@ -955,13 +1023,13 @@ public class GltfLoader implements AssetLoader {
|
|||||||
|
|
||||||
int numComponents = getNumberOfComponents(type);
|
int numComponents = getNumberOfComponents(type);
|
||||||
int dataSize = numComponents * count;
|
int dataSize = numComponents * count;
|
||||||
float[] data = new float[count];
|
float[] data = new float[dataSize];
|
||||||
|
|
||||||
if (bufferViewIndex == null) {
|
if (bufferViewIndex == null) {
|
||||||
//no referenced buffer, specs says to pad the data with zeros.
|
//no referenced buffer, specs says to pad the data with zeros.
|
||||||
padBuffer(data, dataSize);
|
padBuffer(data, dataSize);
|
||||||
} else {
|
} else {
|
||||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -982,9 +1050,8 @@ public class GltfLoader implements AssetLoader {
|
|||||||
//no referenced buffer, specs says to pad the data with zeros.
|
//no referenced buffer, specs says to pad the data with zeros.
|
||||||
padBuffer(data, dataSize);
|
padBuffer(data, dataSize);
|
||||||
} else {
|
} else {
|
||||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1002,30 +1069,47 @@ public class GltfLoader implements AssetLoader {
|
|||||||
//no referenced buffer, specs says to pad the data with zeros.
|
//no referenced buffer, specs says to pad the data with zeros.
|
||||||
padBuffer(data, dataSize);
|
padBuffer(data, dataSize);
|
||||||
} else {
|
} else {
|
||||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Matrix4fArrayPopulator implements Populator<Matrix4f[]> {
|
private class JointData {
|
||||||
|
short[] joints;
|
||||||
|
int componentSize;
|
||||||
|
|
||||||
|
public JointData(short[] joints, int componentSize) {
|
||||||
|
this.joints = joints;
|
||||||
|
this.componentSize = componentSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JointArrayPopulator implements Populator<SkinBuffers> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Matrix4f[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
public SkinBuffers populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
|
||||||
|
|
||||||
int numComponents = getNumberOfComponents(type);
|
int numComponents = getNumberOfComponents(type);
|
||||||
|
|
||||||
|
//can be bytes or shorts.
|
||||||
|
int componentSize = 1;
|
||||||
|
if (componentType == 5123) {
|
||||||
|
componentSize = 2;
|
||||||
|
}
|
||||||
|
|
||||||
int dataSize = numComponents * count;
|
int dataSize = numComponents * count;
|
||||||
Matrix4f[] data = new Matrix4f[count];
|
short[] data = new short[dataSize];
|
||||||
|
|
||||||
if (bufferViewIndex == null) {
|
if (bufferViewIndex == null) {
|
||||||
//no referenced buffer, specs says to pad the data with zeros.
|
//no referenced buffer, specs says to pad the data with zeros.
|
||||||
padBuffer(data, dataSize);
|
padBuffer(data, dataSize);
|
||||||
} else {
|
} else {
|
||||||
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents);
|
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, componentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return new SkinBuffers(data, componentSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,20 +10,21 @@ import com.jme3.scene.Mesh;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.VertexBuffer;
|
import com.jme3.scene.VertexBuffer;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import com.jme3.util.LittleEndien;
|
import com.jme3.util.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
import java.util.logging.Level;
|
||||||
import java.util.List;
|
import java.util.logging.Logger;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Nehon on 07/08/2017.
|
* Created by Nehon on 07/08/2017.
|
||||||
*/
|
*/
|
||||||
public class GltfUtils {
|
public class GltfUtils {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(GltfUtils.class.getName());
|
||||||
|
|
||||||
public static Mesh.Mode getMeshMode(Integer mode) {
|
public static Mesh.Mode getMeshMode(Integer mode) {
|
||||||
if (mode == null) {
|
if (mode == null) {
|
||||||
return Mesh.Mode.Triangles;
|
return Mesh.Mode.Triangles;
|
||||||
@ -120,11 +121,17 @@ public class GltfUtils {
|
|||||||
case "WEIGHTS_0":
|
case "WEIGHTS_0":
|
||||||
return VertexBuffer.Type.BoneWeight;
|
return VertexBuffer.Type.BoneWeight;
|
||||||
default:
|
default:
|
||||||
throw new AssetLoadException("Unsupported buffer attribute: " + attribute);
|
logger.log(Level.WARNING, "Unsupported Vertex Buffer type " + attribute);
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getIndex(String name) {
|
||||||
|
String num = name.substring(name.lastIndexOf("_") + 1);
|
||||||
|
return Integer.parseInt(num);
|
||||||
|
}
|
||||||
|
|
||||||
public static Texture.MagFilter getMagFilter(Integer value) {
|
public static Texture.MagFilter getMagFilter(Integer value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -201,7 +208,12 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
buffer.rewind();
|
buffer.rewind();
|
||||||
}
|
}
|
||||||
if (store instanceof float[]) {
|
if (store instanceof short[]) {
|
||||||
|
short[] array = (short[]) store;
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
array[i] = 0;
|
||||||
|
}
|
||||||
|
} else if (store instanceof float[]) {
|
||||||
float[] array = (float[]) store;
|
float[] array = (float[]) store;
|
||||||
for (int i = 0; i < array.length; i++) {
|
for (int i = 0; i < array.length; i++) {
|
||||||
array[i] = 0;
|
array[i] = 0;
|
||||||
@ -224,41 +236,43 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
|
|
||||||
if (store instanceof Buffer) {
|
if (store instanceof Buffer) {
|
||||||
Buffer buffer = (Buffer) store;
|
Buffer buffer = (Buffer) store;
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
if (buffer instanceof ByteBuffer) {
|
if (buffer instanceof ByteBuffer) {
|
||||||
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents);
|
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LittleEndien stream = getStream(source);
|
LittleEndien stream = getStream(source);
|
||||||
if (buffer instanceof ShortBuffer) {
|
if (buffer instanceof ShortBuffer) {
|
||||||
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
} else if (buffer instanceof IntBuffer) {
|
} else if (buffer instanceof IntBuffer) {
|
||||||
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
} else if (buffer instanceof FloatBuffer) {
|
} else if (buffer instanceof FloatBuffer) {
|
||||||
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents);
|
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
}
|
}
|
||||||
buffer.rewind();
|
buffer.rewind();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LittleEndien stream = getStream(source);
|
LittleEndien stream = getStream(source);
|
||||||
|
if (store instanceof short[]) {
|
||||||
|
populateShortArray((short[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
|
} else
|
||||||
if (store instanceof float[]) {
|
if (store instanceof float[]) {
|
||||||
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents);
|
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
} else if (store instanceof Vector3f[]) {
|
} else if (store instanceof Vector3f[]) {
|
||||||
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents);
|
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
} else if (store instanceof Quaternion[]) {
|
} else if (store instanceof Quaternion[]) {
|
||||||
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents);
|
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
} else if (store instanceof Matrix4f[]) {
|
} else if (store instanceof Matrix4f[]) {
|
||||||
populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents);
|
populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents) {
|
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents, int componentSize) {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 1;
|
|
||||||
while (index < length + byteOffset) {
|
while (index < length + byteOffset) {
|
||||||
for (int i = 0; i < numComponents; i++) {
|
for (int i = 0; i < numComponents; i++) {
|
||||||
buffer.put(source[index + i]);
|
buffer.put(source[index + i]);
|
||||||
@ -267,9 +281,8 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 2;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
while (index < end) {
|
while (index < end) {
|
||||||
@ -280,9 +293,8 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 4;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
while (index < end) {
|
while (index < end) {
|
||||||
@ -293,9 +305,8 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 4;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
while (index < end) {
|
while (index < end) {
|
||||||
@ -306,9 +317,94 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateFloatArray(float[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateShortArray(short[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
|
int index = byteOffset;
|
||||||
|
int end = length * componentSize + byteOffset;
|
||||||
|
stream.skipBytes(byteOffset);
|
||||||
|
int arrayIndex = 0;
|
||||||
|
while (index < end) {
|
||||||
|
for (int i = 0; i < numComponents; i++) {
|
||||||
|
if (componentSize == 2) {
|
||||||
|
array[arrayIndex] = stream.readShort();
|
||||||
|
} else {
|
||||||
|
array[arrayIndex] = stream.readByte();
|
||||||
|
}
|
||||||
|
arrayIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
index += Math.max(componentSize * numComponents, byteStride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] toByteArray(short[] shortArray) {
|
||||||
|
byte[] bytes = new byte[shortArray.length];
|
||||||
|
for (int i = 0; i < shortArray.length; i++) {
|
||||||
|
bytes[i] = (byte) shortArray[i];
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSkinBuffers(mesh, jointsArray, weightsArray, componentSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void setSkinBuffers(Mesh mesh, short[] jointsArray, float[] weightsArray, int componentSize) {
|
||||||
|
if (componentSize == 1) {
|
||||||
|
mesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, BufferUtils.createByteBuffer(toByteArray(jointsArray)));
|
||||||
|
} else {
|
||||||
|
mesh.setBuffer(VertexBuffer.Type.BoneIndex, 4, BufferUtils.createShortBuffer(jointsArray));
|
||||||
|
}
|
||||||
|
mesh.setBuffer(VertexBuffer.Type.BoneWeight, 4, BufferUtils.createFloatBuffer(weightsArray));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void populateFloatArray(float[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 4;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
int arrayIndex = 0;
|
int arrayIndex = 0;
|
||||||
@ -322,9 +418,8 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 4;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
int arrayIndex = 0;
|
int arrayIndex = 0;
|
||||||
@ -341,9 +436,8 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 4;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
int arrayIndex = 0;
|
int arrayIndex = 0;
|
||||||
@ -361,9 +455,8 @@ public class GltfUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents) throws IOException {
|
private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
|
||||||
int index = byteOffset;
|
int index = byteOffset;
|
||||||
int componentSize = 4;
|
|
||||||
int end = length * componentSize + byteOffset;
|
int end = length * componentSize + byteOffset;
|
||||||
stream.skipBytes(byteOffset);
|
stream.skipBytes(byteOffset);
|
||||||
int arrayIndex = 0;
|
int arrayIndex = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user