KHR_draco_mesh_compression.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { Geometry, DracoCompression, Mesh, Nullable, VertexBuffer } from "babylonjs";
  2. import { MeshPrimitiveMode } from "babylonjs-gltf2interface";
  3. import { IBufferView, IMeshPrimitive } from "../glTFLoaderInterfaces";
  4. import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
  5. import { GLTF2Loader, ArrayItem } from "../glTF2Loader";
  6. const NAME = "KHR_draco_mesh_compression";
  7. interface IKHRDracoMeshCompression {
  8. bufferView: number;
  9. attributes: { [name: string]: number };
  10. }
  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. /** The name of this extension. */
  19. public readonly name = NAME;
  20. /** Defines whether this extension is enabled. */
  21. public enabled = DracoCompression.DecoderAvailable;
  22. private _loader: GLTF2Loader;
  23. private _dracoCompression?: DracoCompression;
  24. /** @hidden */
  25. constructor(loader: GLTF2Loader) {
  26. this._loader = loader;
  27. }
  28. /** @hidden */
  29. public dispose(): void {
  30. if (this._dracoCompression) {
  31. this._dracoCompression.dispose();
  32. delete this._dracoCompression;
  33. }
  34. delete this._loader;
  35. }
  36. /** @hidden */
  37. public _loadVertexDataAsync(context: string, primitive: IMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>> {
  38. return GLTF2Loader.LoadExtensionAsync<IKHRDracoMeshCompression, Geometry>(context, primitive, this.name, (extensionContext, extension) => {
  39. if (primitive.mode != undefined) {
  40. if (primitive.mode !== MeshPrimitiveMode.TRIANGLE_STRIP &&
  41. primitive.mode !== MeshPrimitiveMode.TRIANGLES) {
  42. throw new Error(`${context}: Unsupported mode ${primitive.mode}`);
  43. }
  44. // TODO: handle triangle strips
  45. if (primitive.mode === MeshPrimitiveMode.TRIANGLE_STRIP) {
  46. throw new Error(`${context}: Mode ${primitive.mode} is not currently supported`);
  47. }
  48. }
  49. const attributes: { [kind: string]: number } = {};
  50. const loadAttribute = (name: string, kind: string) => {
  51. const uniqueId = extension.attributes[name];
  52. if (uniqueId == undefined) {
  53. return;
  54. }
  55. babylonMesh._delayInfo = babylonMesh._delayInfo || [];
  56. if (babylonMesh._delayInfo.indexOf(kind) === -1) {
  57. babylonMesh._delayInfo.push(kind);
  58. }
  59. attributes[kind] = uniqueId;
  60. };
  61. loadAttribute("POSITION", VertexBuffer.PositionKind);
  62. loadAttribute("NORMAL", VertexBuffer.NormalKind);
  63. loadAttribute("TANGENT", VertexBuffer.TangentKind);
  64. loadAttribute("TEXCOORD_0", VertexBuffer.UVKind);
  65. loadAttribute("TEXCOORD_1", VertexBuffer.UV2Kind);
  66. loadAttribute("JOINTS_0", VertexBuffer.MatricesIndicesKind);
  67. loadAttribute("WEIGHTS_0", VertexBuffer.MatricesWeightsKind);
  68. loadAttribute("COLOR_0", VertexBuffer.ColorKind);
  69. var bufferView = ArrayItem.Get(extensionContext, this._loader.gltf.bufferViews, extension.bufferView) as IBufferViewDraco;
  70. if (!bufferView._dracoBabylonGeometry) {
  71. bufferView._dracoBabylonGeometry = this._loader.loadBufferViewAsync(`#/bufferViews/${bufferView.index}`, bufferView).then((data) => {
  72. if (!this._dracoCompression) {
  73. this._dracoCompression = new DracoCompression();
  74. }
  75. return this._dracoCompression.decodeMeshAsync(data, attributes).then((babylonVertexData) => {
  76. const babylonGeometry = new Geometry(babylonMesh.name, this._loader.babylonScene);
  77. babylonVertexData.applyToGeometry(babylonGeometry);
  78. return babylonGeometry;
  79. }).catch((error) => {
  80. throw new Error(`${context}: ${error.message}`);
  81. });
  82. });
  83. }
  84. return bufferView._dracoBabylonGeometry;
  85. });
  86. }
  87. }
  88. GLTF2Loader.RegisterExtension(NAME, (loader) => new KHR_draco_mesh_compression(loader));