瀏覽代碼

Add support for sparse accessor of indices

Gary Hsu 6 年之前
父節點
當前提交
9132b2b4be
共有 2 個文件被更改,包括 81 次插入48 次删除
  1. 74 48
      loaders/src/glTF/2.0/glTFLoader.ts
  2. 7 0
      src/Meshes/buffer.ts

+ 74 - 48
loaders/src/glTF/2.0/glTFLoader.ts

@@ -31,6 +31,16 @@ import { IGLTFLoader, GLTFFileLoader, GLTFLoaderState, IGLTFLoaderData, GLTFLoad
 import { IAnimationKey, AnimationKeyInterpolation } from 'babylonjs/Animations/animationKey';
 import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
 
+interface TypedArrayLike extends ArrayBufferView {
+    readonly length: number;
+    [n: number]: number;
+}
+
+interface TypedArrayConstructor {
+    new(length: number): TypedArrayLike;
+    new(buffer: ArrayBufferLike, byteOffset: number, length?: number): TypedArrayLike;
+}
+
 interface IFileRequestInfo extends IFileRequest {
     _lengthComputable?: boolean;
     _loaded?: number;
@@ -1403,32 +1413,9 @@ export class GLTFLoader implements IGLTFLoader {
         return bufferView._data;
     }
 
-    private _loadIndicesAccessorAsync(context: string, accessor: IAccessor): Promise<IndicesArray> {
-        if (accessor.type !== AccessorType.SCALAR) {
-            throw new Error(`${context}/type: Invalid value ${accessor.type}`);
-        }
-
-        if (accessor.componentType !== AccessorComponentType.UNSIGNED_BYTE &&
-            accessor.componentType !== AccessorComponentType.UNSIGNED_SHORT &&
-            accessor.componentType !== AccessorComponentType.UNSIGNED_INT) {
-            throw new Error(`${context}/componentType: Invalid value ${accessor.componentType}`);
-        }
-
-        if (accessor._data) {
-            return accessor._data as Promise<IndicesArray>;
-        }
-
-        const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
-        accessor._data = this.loadBufferViewAsync(`/bufferViews/${bufferView.index}`, bufferView).then((data) => {
-            return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, accessor.count);
-        });
-
-        return accessor._data as Promise<IndicesArray>;
-    }
-
-    private _loadFloatAccessorAsync(context: string, accessor: IAccessor): Promise<Float32Array> {
+    private _loadAccessorAsync(context: string, accessor: IAccessor, constructor: TypedArrayConstructor): Promise<ArrayBufferView> {
         if (accessor._data) {
-            return accessor._data as Promise<Float32Array>;
+            return accessor._data;
         }
 
         const numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
@@ -1436,7 +1423,7 @@ export class GLTFLoader implements IGLTFLoader {
         const length = numComponents * accessor.count;
 
         if (accessor.bufferView == undefined) {
-            accessor._data = Promise.resolve(new Float32Array(length));
+            accessor._data = Promise.resolve(new constructor(length));
         }
         else {
             const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
@@ -1445,19 +1432,19 @@ export class GLTFLoader implements IGLTFLoader {
                     return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, length);
                 }
                 else {
-                    const floatData = new Float32Array(length);
-                    VertexBuffer.ForEach(data, accessor.byteOffset || 0, bufferView.byteStride || byteStride, numComponents, accessor.componentType, floatData.length, accessor.normalized || false, (value, index) => {
-                        floatData[index] = value;
+                    const typedArray = new constructor(length);
+                    VertexBuffer.ForEach(data, accessor.byteOffset || 0, bufferView.byteStride || byteStride, numComponents, accessor.componentType, typedArray.length, accessor.normalized || false, (value, index) => {
+                        typedArray[index] = value;
                     });
-                    return floatData;
+                    return typedArray;
                 }
             });
         }
 
         if (accessor.sparse) {
             const sparse = accessor.sparse;
-            accessor._data = accessor._data.then((view: ArrayBufferView) => {
-                const data = view as Float32Array;
+            accessor._data = accessor._data.then((data) => {
+                const typedArray = data as TypedArrayLike;
                 const indicesBufferView = ArrayItem.Get(`${context}/sparse/indices/bufferView`, this._gltf.bufferViews, sparse.indices.bufferView);
                 const valuesBufferView = ArrayItem.Get(`${context}/sparse/values/bufferView`, this._gltf.bufferViews, sparse.values.bufferView);
                 return Promise.all([
@@ -1467,14 +1454,14 @@ export class GLTFLoader implements IGLTFLoader {
                     const indices = GLTFLoader._GetTypedArray(`${context}/sparse/indices`, sparse.indices.componentType, indicesData, sparse.indices.byteOffset, sparse.count) as IndicesArray;
 
                     const sparseLength = numComponents * sparse.count;
-                    let values: Float32Array;
+                    let values: TypedArrayLike;
 
                     if (accessor.componentType === AccessorComponentType.FLOAT && !accessor.normalized) {
-                        values = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength) as Float32Array;
+                        values = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength);
                     }
                     else {
                         const sparseData = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength);
-                        values = new Float32Array(sparseLength);
+                        values = new constructor(sparseLength);
                         VertexBuffer.ForEach(sparseData, 0, byteStride, numComponents, accessor.componentType, values.length, accessor.normalized || false, (value, index) => {
                             values[index] = value;
                         });
@@ -1484,16 +1471,49 @@ export class GLTFLoader implements IGLTFLoader {
                     for (let indicesIndex = 0; indicesIndex < indices.length; indicesIndex++) {
                         let dataIndex = indices[indicesIndex] * numComponents;
                         for (let componentIndex = 0; componentIndex < numComponents; componentIndex++) {
-                            data[dataIndex++] = values[valuesIndex++];
+                            typedArray[dataIndex++] = values[valuesIndex++];
                         }
                     }
 
-                    return data;
+                    return typedArray;
                 });
             });
         }
 
-        return accessor._data as Promise<Float32Array>;
+        return accessor._data;
+    }
+
+    private _loadFloatAccessorAsync(context: string, accessor: IAccessor): Promise<Float32Array> {
+        return this._loadAccessorAsync(context, accessor, Float32Array) as Promise<Float32Array>;
+    }
+
+    private _loadIndicesAccessorAsync(context: string, accessor: IAccessor): Promise<IndicesArray> {
+        if (accessor.type !== AccessorType.SCALAR) {
+            throw new Error(`${context}/type: Invalid value ${accessor.type}`);
+        }
+
+        if (accessor.componentType !== AccessorComponentType.UNSIGNED_BYTE &&
+            accessor.componentType !== AccessorComponentType.UNSIGNED_SHORT &&
+            accessor.componentType !== AccessorComponentType.UNSIGNED_INT) {
+            throw new Error(`${context}/componentType: Invalid value ${accessor.componentType}`);
+        }
+
+        if (accessor._data) {
+            return accessor._data as Promise<IndicesArray>;
+        }
+
+        if (accessor.sparse) {
+            const constructor = GLTFLoader._GetTypedArrayConstructor(`${context}/componentType`, accessor.componentType);
+            accessor._data = this._loadAccessorAsync(context, accessor, constructor);
+        }
+        else {
+            const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
+            accessor._data = this.loadBufferViewAsync(`/bufferViews/${bufferView.index}`, bufferView).then((data) => {
+                return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, accessor.count);
+            });
+        }
+
+        return accessor._data as Promise<IndicesArray>;
     }
 
     private _loadVertexBufferViewAsync(bufferView: IBufferView, kind: string): Promise<Buffer> {
@@ -2040,20 +2060,26 @@ export class GLTFLoader implements IGLTFLoader {
         }
     }
 
-    private static _GetTypedArray(context: string, componentType: AccessorComponentType, bufferView: ArrayBufferView, byteOffset: number | undefined, length: number): ArrayBufferView {
+    private static _GetTypedArrayConstructor(context: string, componentType: AccessorComponentType): TypedArrayConstructor {
+        switch (componentType) {
+            case AccessorComponentType.BYTE: return Int8Array;
+            case AccessorComponentType.UNSIGNED_BYTE: return Uint8Array;
+            case AccessorComponentType.SHORT: return Int16Array;
+            case AccessorComponentType.UNSIGNED_SHORT: return Uint16Array;
+            case AccessorComponentType.UNSIGNED_INT: return Uint32Array;
+            case AccessorComponentType.FLOAT: return Float32Array;
+            default: throw new Error(`${context}: Invalid component type ${componentType}`);
+        }
+}
+
+    private static _GetTypedArray(context: string, componentType: AccessorComponentType, bufferView: ArrayBufferView, byteOffset: number | undefined, length: number): TypedArrayLike {
         const buffer = bufferView.buffer;
         byteOffset = bufferView.byteOffset + (byteOffset || 0);
 
+        const constructor = GLTFLoader._GetTypedArrayConstructor(`${context}/componentType`, componentType);
+
         try {
-            switch (componentType) {
-                case AccessorComponentType.BYTE: return new Int8Array(buffer, byteOffset, length);
-                case AccessorComponentType.UNSIGNED_BYTE: return new Uint8Array(buffer, byteOffset, length);
-                case AccessorComponentType.SHORT: return new Int16Array(buffer, byteOffset, length);
-                case AccessorComponentType.UNSIGNED_SHORT: return new Uint16Array(buffer, byteOffset, length);
-                case AccessorComponentType.UNSIGNED_INT: return new Uint32Array(buffer, byteOffset, length);
-                case AccessorComponentType.FLOAT: return new Float32Array(buffer, byteOffset, length);
-                default: throw new Error(`Invalid component type ${componentType}`);
-            }
+            return new constructor(buffer, byteOffset, length);
         }
         catch (e) {
             throw new Error(`${context}: ${e}`);

+ 7 - 0
src/Meshes/buffer.ts

@@ -554,6 +554,7 @@ export class VertexBuffer {
             case VertexBuffer.UNSIGNED_SHORT:
                 return 2;
             case VertexBuffer.INT:
+            case VertexBuffer.UNSIGNED_INT:
             case VertexBuffer.FLOAT:
                 return 4;
             default:
@@ -628,6 +629,12 @@ export class VertexBuffer {
                 }
                 return value;
             }
+            case VertexBuffer.INT: {
+                return dataView.getInt32(byteOffset, true);
+            }
+            case VertexBuffer.UNSIGNED_INT: {
+                return dataView.getUint32(byteOffset, true);
+            }
             case VertexBuffer.FLOAT: {
                 return dataView.getFloat32(byteOffset, true);
             }