Added support for packed float data

fix-456
Nehon 7 years ago committed by Rémy Bouquet
parent 01b48e0357
commit cac51f542a
  1. 51
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.java
  2. 130
      jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java

@ -285,7 +285,8 @@ public class GltfLoader implements AssetLoader {
for (int i = 0; i < tmpArray.length; i++) {
tmpArray[i] = matrix.get(i).getAsFloat();
}
Matrix4f mat = toRowMajor(tmpArray);
//creates a row major matrix from color major data
Matrix4f mat = new Matrix4f(tmpArray);
transform.fromTransformMatrix(mat);
return transform;
}
@ -446,19 +447,18 @@ public class GltfLoader implements AssetLoader {
assertNotNull(type, "No type attribute defined for accessor " + accessorIndex);
boolean normalized = getAsBoolean(accessor, "normalized", false);
//Some float data can be packed into short buffers, "normalized" means they have to be unpacked.
//TODO support packed data
//TODO min / max
//TODO sparse
//TODO extensions?
//TODO extras?
R data = populator.populate(bufferViewIndex, componentType, type, count, byteOffset);
R data = populator.populate(bufferViewIndex, componentType, type, count, byteOffset, normalized);
data = customContentManager.readExtension(accessor, data);
return data;
}
public void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Object store, int numComponents, int componentSize) throws IOException {
public void readBuffer(Integer bufferViewIndex, int byteOffset, int bufferSize, Object store, int numComponents, VertexBuffer.Format format) throws IOException {
JsonObject bufferView = bufferViews.get(bufferViewIndex).getAsJsonObject();
Integer bufferIndex = getAsInteger(bufferView, "buffer");
@ -476,7 +476,7 @@ public class GltfLoader implements AssetLoader {
data = customContentManager.readExtension(bufferView, data);
populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents, componentSize);
populateBuffer(store, data, bufferSize, byteOffset + bvByteOffset, byteStride, numComponents, format);
//TODO extras?
@ -1219,7 +1219,7 @@ public class GltfLoader implements AssetLoader {
}
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, boolean normalized) throws IOException;
}
private class VertexBufferPopulator implements Populator<VertexBuffer> {
@ -1230,15 +1230,22 @@ public class GltfLoader implements AssetLoader {
}
@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, boolean normalized) 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.Format format = getVertexBufferFormat(componentType);
VertexBuffer.Format originalFormat = format;
if (normalized) {
//Some float data can be packed into short buffers, "normalized" means they have to be unpacked.
//In that case the buffer is a FloatBuffer
format = VertexBuffer.Format.Float;
}
int numComponents = getNumberOfComponents(type);
Buffer buff = VertexBuffer.createBuffer(format, numComponents, count);
@ -1247,7 +1254,7 @@ public class GltfLoader implements AssetLoader {
//no referenced buffer, specs says to pad the buffer with zeros.
padBuffer(buff, bufferSize);
} else {
readBuffer(bufferViewIndex, byteOffset, bufferSize, buff, numComponents, format.getComponentSize());
readBuffer(bufferViewIndex, byteOffset, bufferSize, buff, numComponents, originalFormat);
}
if (bufferType == VertexBuffer.Type.Index) {
@ -1263,7 +1270,7 @@ public class GltfLoader implements AssetLoader {
private class FloatArrayPopulator implements Populator<float[]> {
@Override
public float[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
public float[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset, boolean normalized) throws IOException {
int numComponents = getNumberOfComponents(type);
int dataSize = numComponents * count;
@ -1273,7 +1280,7 @@ public class GltfLoader implements AssetLoader {
//no referenced buffer, specs says to pad the data with zeros.
padBuffer(data, dataSize);
} else {
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType));
}
return data;
@ -1284,7 +1291,7 @@ public class GltfLoader implements AssetLoader {
private class Vector3fArrayPopulator implements Populator<Vector3f[]> {
@Override
public Vector3f[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
public Vector3f[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset, boolean normalized) throws IOException {
int numComponents = getNumberOfComponents(type);
int dataSize = numComponents * count;
@ -1294,7 +1301,7 @@ public class GltfLoader implements AssetLoader {
//no referenced buffer, specs says to pad the data with zeros.
padBuffer(data, dataSize);
} else {
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType));
}
return data;
}
@ -1303,7 +1310,7 @@ public class GltfLoader implements AssetLoader {
private class QuaternionArrayPopulator implements Populator<Quaternion[]> {
@Override
public Quaternion[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
public Quaternion[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset, boolean normalized) throws IOException {
int numComponents = getNumberOfComponents(type);
int dataSize = numComponents * count;
@ -1313,7 +1320,7 @@ public class GltfLoader implements AssetLoader {
//no referenced buffer, specs says to pad the data with zeros.
padBuffer(data, dataSize);
} else {
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType));
}
return data;
@ -1323,7 +1330,7 @@ public class GltfLoader implements AssetLoader {
private class Matrix4fArrayPopulator implements Populator<Matrix4f[]> {
@Override
public Matrix4f[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException {
public Matrix4f[] populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset, boolean normalized) throws IOException {
int numComponents = getNumberOfComponents(type);
int dataSize = numComponents * count;
@ -1333,7 +1340,7 @@ public class GltfLoader implements AssetLoader {
//no referenced buffer, specs says to pad the data with zeros.
padBuffer(data, dataSize);
} else {
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, 4);
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, getVertexBufferFormat(componentType));
}
return data;
@ -1343,14 +1350,14 @@ public class GltfLoader implements AssetLoader {
private class JointArrayPopulator implements Populator<SkinBuffers> {
@Override
public SkinBuffers 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, boolean normalized) throws IOException {
int numComponents = getNumberOfComponents(type);
//can be bytes or shorts.
int componentSize = 1;
VertexBuffer.Format format = VertexBuffer.Format.Byte;
if (componentType == 5123) {
componentSize = 2;
format = VertexBuffer.Format.Short;
}
int dataSize = numComponents * count;
@ -1360,10 +1367,10 @@ public class GltfLoader implements AssetLoader {
//no referenced buffer, specs says to pad the data with zeros.
padBuffer(data, dataSize);
} else {
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, componentSize);
readBuffer(bufferViewIndex, byteOffset, dataSize, data, numComponents, format);
}
return new SkinBuffers(data, componentSize);
return new SkinBuffers(data, format.getComponentSize());
}
}
}

@ -237,42 +237,43 @@ public class GltfUtils {
}
}
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
public static void populateBuffer(Object store, byte[] source, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
if (store instanceof Buffer) {
Buffer buffer = (Buffer) store;
buffer.clear();
if (buffer instanceof ByteBuffer) {
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents, componentSize);
populateByteBuffer((ByteBuffer) buffer, source, length, byteOffset, byteStride, numComponents, format);
return;
}
LittleEndien stream = getStream(source);
if (buffer instanceof ShortBuffer) {
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateShortBuffer((ShortBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, format);
} else if (buffer instanceof IntBuffer) {
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateIntBuffer((IntBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, format);
} else if (buffer instanceof FloatBuffer) {
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateFloatBuffer((FloatBuffer) buffer, stream, length, byteOffset, byteStride, numComponents, format);
}
buffer.rewind();
return;
}
LittleEndien stream = getStream(source);
if (store instanceof short[]) {
populateShortArray((short[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateShortArray((short[]) store, stream, length, byteOffset, byteStride, numComponents, format);
} else
if (store instanceof float[]) {
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateFloatArray((float[]) store, stream, length, byteOffset, byteStride, numComponents, format);
} else if (store instanceof Vector3f[]) {
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateVector3fArray((Vector3f[]) store, stream, length, byteOffset, byteStride, numComponents, format);
} else if (store instanceof Quaternion[]) {
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateQuaternionArray((Quaternion[]) store, stream, length, byteOffset, byteStride, numComponents, format);
} else if (store instanceof Matrix4f[]) {
populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents, componentSize);
populateMatrix4fArray((Matrix4f[]) store, stream, length, byteOffset, byteStride, numComponents, format);
}
}
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents, int componentSize) {
private static void populateByteBuffer(ByteBuffer buffer, byte[] source, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) {
int componentSize = format.getComponentSize();
int index = byteOffset;
while (index < length + byteOffset) {
for (int i = 0; i < numComponents; i++) {
@ -282,7 +283,8 @@ public class GltfUtils {
}
}
private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static void populateShortBuffer(ShortBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
@ -294,7 +296,8 @@ public class GltfUtils {
}
}
private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static void populateIntBuffer(IntBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
@ -306,19 +309,50 @@ public class GltfUtils {
}
}
private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static void populateFloatBuffer(FloatBuffer buffer, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
while (index < end) {
for (int i = 0; i < numComponents; i++) {
buffer.put(stream.readFloat());
buffer.put(readAsFloat(stream, format));
}
index += Math.max(componentSize * numComponents, byteStride);
}
}
private static void populateShortArray(short[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static float readAsFloat(LittleEndien stream, VertexBuffer.Format format) throws IOException {
//We may have packed data so depending on the format, we need to read data differently and unpack it
// Implementations must use following equations to get corresponding floating-point value f from a normalized integer c and vise-versa:
// accessor.componentType int-to-float float-to-int
// 5120 (BYTE) f = max(c / 127.0, -1.0) c = round(f * 127.0)
// 5121 (UNSIGNED_BYTE) f = c / 255.0 c = round(f * 255.0)
// 5122 (SHORT) f = max(c / 32767.0, -1.0) c = round(f * 32767.0)
// 5123 (UNSIGNED_SHORT) f = c / 65535.0 c = round(f * 65535.0)
byte b;
switch (format) {
case Byte:
b = stream.readByte();
return Math.max((float) b / 127f, -1f);
case UnsignedByte:
b = stream.readByte();
return (float) b / 255f;
case Short:
b = stream.readByte();
return Math.max((float) b / 32767f, -1f);
case UnsignedShort:
b = stream.readByte();
return (float) b / 65535f;
default:
//we have a regular float
return stream.readFloat();
}
}
private static void populateShortArray(short[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
@ -404,14 +438,15 @@ public class GltfUtils {
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 {
private static void populateFloatArray(float[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
int arrayIndex = 0;
while (index < end) {
for (int i = 0; i < numComponents; i++) {
array[arrayIndex] = stream.readFloat();
array[arrayIndex] = readAsFloat(stream, format);
arrayIndex++;
}
@ -419,16 +454,17 @@ public class GltfUtils {
}
}
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static void populateVector3fArray(Vector3f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
int arrayIndex = 0;
while (index < end) {
array[arrayIndex] = new Vector3f(
stream.readFloat(),
stream.readFloat(),
stream.readFloat()
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format)
);
arrayIndex++;
@ -437,17 +473,18 @@ public class GltfUtils {
}
}
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static void populateQuaternionArray(Quaternion[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
int arrayIndex = 0;
while (index < end) {
array[arrayIndex] = new Quaternion(
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat()
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format)
);
arrayIndex++;
@ -456,7 +493,8 @@ public class GltfUtils {
}
}
private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, int componentSize) throws IOException {
private static void populateMatrix4fArray(Matrix4f[] array, LittleEndien stream, int length, int byteOffset, int byteStride, int numComponents, VertexBuffer.Format format) throws IOException {
int componentSize = format.getComponentSize();
int index = byteOffset;
int end = length * componentSize + byteOffset;
stream.skipBytes(byteOffset);
@ -464,22 +502,22 @@ public class GltfUtils {
while (index < end) {
array[arrayIndex] = toRowMajor(
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat(),
stream.readFloat()
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format),
readAsFloat(stream, format)
);
//gltf matrix are column major, JME ones are row major.
@ -496,10 +534,6 @@ public class GltfUtils {
return new Matrix4f(m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33);
}
public static Matrix4f toRowMajor(float[] a) {
return new Matrix4f(a[0], a[4], a[8], a[12], a[1], a[5], a[9], a[13], a[2], a[5], a[10], a[14], a[3], a[7], a[11], a[15]);
}
public static GltfModelKey getKey(AssetInfo info) {
if (info.getKey() instanceof GltfModelKey) {
return (GltfModelKey) info.getKey();

Loading…
Cancel
Save