KHR_draco_mesh_compression.ts 4.6 KB

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