threepipe
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import {
  2. DataTexture,
  3. DataUtils,
  4. FileLoader,
  5. FloatType,
  6. HalfFloatType,
  7. LinearFilter,
  8. LoadingManager,
  9. RGBAFormat,
  10. SRGBColorSpace,
  11. TextureDataType,
  12. } from 'three'
  13. import {imageUrlToImageData} from 'ts-browser-helpers'
  14. /**
  15. * 8bit HDR image in png format
  16. * not properly working with files from hdrpng.js but used in {@link GLTFViewerConfigExtension}, so a slightly modified version is used here
  17. */
  18. export class RGBEPNGLoader extends FileLoader {
  19. type: TextureDataType = HalfFloatType
  20. constructor(manager?: LoadingManager) {
  21. super(manager)
  22. }
  23. async loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<any> {
  24. const image = await this.parseAsync(url, onProgress, false)
  25. const texture = new DataTexture(image.data, image.width, image.height, RGBAFormat, this.type)
  26. texture.needsUpdate = true
  27. texture.flipY = true
  28. texture.colorSpace = SRGBColorSpace
  29. texture.minFilter = LinearFilter
  30. texture.magFilter = LinearFilter
  31. texture.source.data.complete = true
  32. return texture
  33. }
  34. async parseAsync(url: string, onProgress?: (event: ProgressEvent) => void, isFloat16Data = false): Promise<any> {
  35. let created = false
  36. if (!url.startsWith('data:') && !url.startsWith('blob:')) {
  37. this.responseType = 'blob'
  38. const blob = await super.loadAsync(url, onProgress) as any as Blob
  39. // url = await blobToDataURL(blob)
  40. // console.log(url)
  41. // url = url.replace('application/octet-stream', 'image/png')
  42. url = URL.createObjectURL(blob)
  43. created = true
  44. }
  45. const imageData = await imageUrlToImageData(url)
  46. if (created) URL.revokeObjectURL(url)
  47. let aType: any = Uint8Array
  48. if (this.type === HalfFloatType) aType = Uint16Array
  49. else if (this.type === FloatType) aType = Uint32Array
  50. const buffer = rgbeToHalfFloat(imageData.data, 4, aType, isFloat16Data)
  51. return {data: buffer, width: imageData.width, height: imageData.height}
  52. }
  53. setDataType(value: TextureDataType) {
  54. this.type = value
  55. return this
  56. }
  57. }
  58. // adapted from https://github.com/enkimute/hdrpng.js/blob/3a62b3ae2940189777df9f669df5ece3e78d9c16/hdrpng.js#L253
  59. // channels = 4 for RGBA data or 3 for RGB data. res to use with THREE.DataTexture
  60. function rgbeToHalfFloat(buffer: Uint8ClampedArray, channels = 3, type = Uint16Array, float16Data = false): Uint16Array {
  61. let s
  62. const l = buffer.byteLength >> 2
  63. const res = new type(l * channels)
  64. for (let i = 0;i < l;i++) {
  65. s = Math.pow(2, buffer[i * 4 + 3] - (128 + 8))
  66. if (float16Data) {
  67. res[ i * channels ] = Math.min(buffer[i * 4] * s, 65504)
  68. res[ i * channels + 1] = Math.min(buffer[i * 4 + 1] * s, 65504)
  69. res[ i * channels + 2] = Math.min(buffer[i * 4 + 2] * s, 65504)
  70. } else {
  71. res[i * channels] = DataUtils.toHalfFloat(Math.min(buffer[i * 4] * s, 65504))
  72. res[i * channels + 1] = DataUtils.toHalfFloat(Math.min(buffer[i * 4 + 1] * s, 65504))
  73. res[i * channels + 2] = DataUtils.toHalfFloat(Math.min(buffer[i * 4 + 2] * s, 65504))
  74. }
  75. // res[i * channels] = Math.min(15360, buffer[i * 4] * s)
  76. // res[i * channels + 1] = Math.min(15360, buffer[i * 4 + 1] * s)
  77. // res[i * channels + 2] = Math.min(15360, buffer[i * 4 + 2] * s)
  78. if (channels === 4) res[i * channels + 3] = DataUtils.toHalfFloat(1) // alpha is always 1 // todo: handle for uint8 and float32
  79. }
  80. return res
  81. }