threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import type {BlobExt} from '../assetmanager'
  2. /**
  3. * Returns a buffer aligned to 4-byte boundary.
  4. * https://github.com/mrdoob/three.js/blob/4dbd0065f2ec29b89c250d8582f61e9f4792e077/examples/jsm/exporters/GLTFExporter.js#L381
  5. * @param arrayBuffer Buffer to pad
  6. * @param paddingByte (Optional)
  7. * @returns The same buffer if it's already aligned to 4-byte boundary or a new buffer
  8. */
  9. function getPaddedArrayBuffer(arrayBuffer: Uint8Array<ArrayBuffer>, paddingByte = 0): ArrayBuffer {
  10. const paddedLength = getPaddedBufferSize(arrayBuffer.byteLength)
  11. if (paddedLength !== arrayBuffer.byteLength) {
  12. const array = new Uint8Array(paddedLength)
  13. array.set(new Uint8Array(arrayBuffer))
  14. if (paddingByte !== 0) {
  15. for (let i = arrayBuffer.byteLength; i < paddedLength; i++) {
  16. array[ i ] = paddingByte
  17. }
  18. }
  19. return array.buffer
  20. }
  21. return arrayBuffer.buffer
  22. }
  23. /**
  24. * Get the required size + padding for a buffer, rounded to the next 4-byte boundary.
  25. * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
  26. *
  27. * @param bufferSize The size the original buffer.
  28. * @returns new buffer size with required padding.
  29. *
  30. */
  31. function getPaddedBufferSize(bufferSize: number) {
  32. return Math.ceil(bufferSize / 4) * 4
  33. }
  34. // GLB constants
  35. // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
  36. const GLB_HEADER_BYTES = 12
  37. const GLB_HEADER_MAGIC = 0x46546C67
  38. const GLB_VERSION = 2
  39. const GLB_CHUNK_PREFIX_BYTES = 8
  40. const GLB_CHUNK_TYPE_JSON = 0x4E4F534A
  41. const GLB_CHUNK_TYPE_BIN = 0x004E4942
  42. // https://github.com/mrdoob/three.js/blob/4dbd0065f2ec29b89c250d8582f61e9f4792e077/examples/jsm/exporters/GLTFExporter.js#L558
  43. export function makeGLBFile(buffers: Uint8Array<ArrayBuffer>, json: any): BlobExt {
  44. // Binary chunk.
  45. const binaryChunk = getPaddedArrayBuffer(buffers)
  46. const binaryChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES))
  47. binaryChunkPrefix.setUint32(0, binaryChunk.byteLength, true)
  48. binaryChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_BIN, true)
  49. // JSON chunk.
  50. const buffer1 = new TextEncoder().encode(JSON.stringify(json || {})) as Uint8Array<ArrayBuffer>
  51. const jsonChunk = getPaddedArrayBuffer(buffer1, 0x20)
  52. const jsonChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES))
  53. jsonChunkPrefix.setUint32(0, jsonChunk.byteLength, true)
  54. jsonChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_JSON, true)
  55. // GLB header.
  56. const header = new ArrayBuffer(GLB_HEADER_BYTES)
  57. const headerView = new DataView(header)
  58. headerView.setUint32(0, GLB_HEADER_MAGIC, true)
  59. headerView.setUint32(4, GLB_VERSION, true)
  60. const totalByteLength = GLB_HEADER_BYTES
  61. + jsonChunkPrefix.byteLength + jsonChunk.byteLength
  62. + binaryChunkPrefix.byteLength + binaryChunk.byteLength
  63. headerView.setUint32(8, totalByteLength, true)
  64. const glbBlob: BlobExt = new Blob([
  65. header,
  66. jsonChunkPrefix,
  67. jsonChunk,
  68. binaryChunkPrefix,
  69. binaryChunk,
  70. ], {type: 'model/gltf+binary'}) as any
  71. glbBlob.ext = 'glb'
  72. return glbBlob
  73. }