Bladeren bron

Added support for packed float data

Nehon 8 jaren geleden
bovenliggende
commit
cac51f542a

+ 29 - 22
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfLoader.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());
         }
     }
 }

+ 82 - 48
jme3-plugins/src/gltf/java/com/jme3/scene/plugins/gltf/GltfUtils.java

@@ -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();