KHR_draco_mesh_compression.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { DracoCompression } from "babylonjs/Meshes/Compression/dracoCompression";
  2. import { Nullable } from "babylonjs/types";
  3. import { VertexBuffer } from "babylonjs/Meshes/buffer";
  4. import { Geometry } from "babylonjs/Meshes/geometry";
  5. import { Mesh } from "babylonjs/Meshes/mesh";
  6. import { MeshPrimitiveMode, IKHRDracoMeshCompression } from "babylonjs-gltf2interface";
  7. import { IMeshPrimitive, IBufferView } from "../glTFLoaderInterfaces";
  8. import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
  9. import { GLTFLoader, ArrayItem } from "../glTFLoader";
  10. const NAME = "KHR_draco_mesh_compression";
  11. interface IBufferViewDraco extends IBufferView {
  12. _dracoBabylonGeometry?: Promise<Geometry>;
  13. }
  14. /**
  15. * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression)
  16. */
  17. export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
  18. /**
  19. * The name of this extension.
  20. */
  21. public readonly name = NAME;
  22. /**
  23. * The draco compression used to decode vertex data or DracoCompression.Default if not defined
  24. */
  25. public dracoCompression?: DracoCompression;
  26. /**
  27. * Defines whether this extension is enabled.
  28. */
  29. public enabled: boolean;
  30. private _loader: GLTFLoader;
  31. /** @hidden */
  32. constructor(loader: GLTFLoader) {
  33. this._loader = loader;
  34. this.enabled = DracoCompression.DecoderAvailable && this._loader.isExtensionUsed(NAME);
  35. }
  36. /** @hidden */
  37. public dispose(): void {
  38. delete this.dracoCompression;
  39. delete this._loader;
  40. }
  41. /** @hidden */
  42. public _loadVertexDataAsync(context: string, primitive: IMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>> {
  43. return GLTFLoader.LoadExtensionAsync<IKHRDracoMeshCompression, Geometry>(context, primitive, this.name, (extensionContext, extension) => {
  44. if (primitive.mode != undefined) {
  45. if (primitive.mode !== MeshPrimitiveMode.TRIANGLE_STRIP &&
  46. primitive.mode !== MeshPrimitiveMode.TRIANGLES) {
  47. throw new Error(`${context}: Unsupported mode ${primitive.mode}`);
  48. }
  49. // TODO: handle triangle strips
  50. if (primitive.mode === MeshPrimitiveMode.TRIANGLE_STRIP) {
  51. throw new Error(`${context}: Mode ${primitive.mode} is not currently supported`);
  52. }
  53. }
  54. const attributes: { [kind: string]: number } = {};
  55. const loadAttribute = (name: string, kind: string) => {
  56. const uniqueId = extension.attributes[name];
  57. if (uniqueId == undefined) {
  58. return;
  59. }
  60. babylonMesh._delayInfo = babylonMesh._delayInfo || [];
  61. if (babylonMesh._delayInfo.indexOf(kind) === -1) {
  62. babylonMesh._delayInfo.push(kind);
  63. }
  64. attributes[kind] = uniqueId;
  65. };
  66. loadAttribute("POSITION", VertexBuffer.PositionKind);
  67. loadAttribute("NORMAL", VertexBuffer.NormalKind);
  68. loadAttribute("TANGENT", VertexBuffer.TangentKind);
  69. loadAttribute("TEXCOORD_0", VertexBuffer.UVKind);
  70. loadAttribute("TEXCOORD_1", VertexBuffer.UV2Kind);
  71. loadAttribute("JOINTS_0", VertexBuffer.MatricesIndicesKind);
  72. loadAttribute("WEIGHTS_0", VertexBuffer.MatricesWeightsKind);
  73. loadAttribute("COLOR_0", VertexBuffer.ColorKind);
  74. var bufferView = ArrayItem.Get(extensionContext, this._loader.gltf.bufferViews, extension.bufferView) as IBufferViewDraco;
  75. if (!bufferView._dracoBabylonGeometry) {
  76. bufferView._dracoBabylonGeometry = this._loader.loadBufferViewAsync(`/bufferViews/${bufferView.index}`, bufferView).then((data) => {
  77. const dracoCompression = this.dracoCompression || DracoCompression.Default;
  78. return dracoCompression.decodeMeshAsync(data, attributes).then((babylonVertexData) => {
  79. const babylonGeometry = new Geometry(babylonMesh.name, this._loader.babylonScene);
  80. babylonVertexData.applyToGeometry(babylonGeometry);
  81. return babylonGeometry;
  82. }).catch((error) => {
  83. throw new Error(`${context}: ${error.message}`);
  84. });
  85. });
  86. }
  87. return bufferView._dracoBabylonGeometry;
  88. });
  89. }
  90. }
  91. GLTFLoader.RegisterExtension(NAME, (loader) => new KHR_draco_mesh_compression(loader));