@headless-three/renderer 0.1.10 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/README.md +3 -0
  2. package/dist/gpu-output.d.ts +81 -0
  3. package/dist/gpu-output.d.ts.map +1 -0
  4. package/dist/gpu-output.js +53 -0
  5. package/dist/gpu-output.js.map +1 -0
  6. package/dist/index.d.ts +26 -770
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +30 -6226
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.part-001.d.ts +95 -0
  11. package/dist/index.part-001.d.ts.map +1 -0
  12. package/dist/index.part-001.js +273 -0
  13. package/dist/index.part-001.js.map +1 -0
  14. package/dist/index.part-002.d.ts +69 -0
  15. package/dist/index.part-002.d.ts.map +1 -0
  16. package/dist/index.part-002.js +211 -0
  17. package/dist/index.part-002.js.map +1 -0
  18. package/dist/index.part-003.d.ts +105 -0
  19. package/dist/index.part-003.d.ts.map +1 -0
  20. package/dist/index.part-003.js +270 -0
  21. package/dist/index.part-003.js.map +1 -0
  22. package/dist/index.part-004.d.ts +78 -0
  23. package/dist/index.part-004.d.ts.map +1 -0
  24. package/dist/index.part-004.js +390 -0
  25. package/dist/index.part-004.js.map +1 -0
  26. package/dist/index.part-005.d.ts +75 -0
  27. package/dist/index.part-005.d.ts.map +1 -0
  28. package/dist/index.part-005.js +236 -0
  29. package/dist/index.part-005.js.map +1 -0
  30. package/dist/index.part-006.d.ts +105 -0
  31. package/dist/index.part-006.d.ts.map +1 -0
  32. package/dist/index.part-006.js +262 -0
  33. package/dist/index.part-006.js.map +1 -0
  34. package/dist/index.part-007.d.ts +112 -0
  35. package/dist/index.part-007.d.ts.map +1 -0
  36. package/dist/index.part-007.js +358 -0
  37. package/dist/index.part-007.js.map +1 -0
  38. package/dist/index.part-008.d.ts +238 -0
  39. package/dist/index.part-008.d.ts.map +1 -0
  40. package/dist/index.part-008.js +454 -0
  41. package/dist/index.part-008.js.map +1 -0
  42. package/dist/index.part-009.d.ts +46 -0
  43. package/dist/index.part-009.d.ts.map +1 -0
  44. package/dist/index.part-009.js +379 -0
  45. package/dist/index.part-009.js.map +1 -0
  46. package/dist/index.part-010.d.ts +23 -0
  47. package/dist/index.part-010.d.ts.map +1 -0
  48. package/dist/index.part-010.js +245 -0
  49. package/dist/index.part-010.js.map +1 -0
  50. package/dist/index.part-011.d.ts +21 -0
  51. package/dist/index.part-011.d.ts.map +1 -0
  52. package/dist/index.part-011.js +361 -0
  53. package/dist/index.part-011.js.map +1 -0
  54. package/dist/index.part-012.d.ts +115 -0
  55. package/dist/index.part-012.d.ts.map +1 -0
  56. package/dist/index.part-012.js +298 -0
  57. package/dist/index.part-012.js.map +1 -0
  58. package/dist/index.part-013.d.ts +37 -0
  59. package/dist/index.part-013.d.ts.map +1 -0
  60. package/dist/index.part-013.js +341 -0
  61. package/dist/index.part-013.js.map +1 -0
  62. package/dist/index.part-014.d.ts +43 -0
  63. package/dist/index.part-014.d.ts.map +1 -0
  64. package/dist/index.part-014.js +441 -0
  65. package/dist/index.part-014.js.map +1 -0
  66. package/dist/index.part-015.d.ts +45 -0
  67. package/dist/index.part-015.d.ts.map +1 -0
  68. package/dist/index.part-015.js +432 -0
  69. package/dist/index.part-015.js.map +1 -0
  70. package/dist/index.part-016.d.ts +55 -0
  71. package/dist/index.part-016.d.ts.map +1 -0
  72. package/dist/index.part-016.js +382 -0
  73. package/dist/index.part-016.js.map +1 -0
  74. package/dist/index.part-017.d.ts +55 -0
  75. package/dist/index.part-017.d.ts.map +1 -0
  76. package/dist/index.part-017.js +436 -0
  77. package/dist/index.part-017.js.map +1 -0
  78. package/dist/index.part-018.d.ts +34 -0
  79. package/dist/index.part-018.d.ts.map +1 -0
  80. package/dist/index.part-018.js +365 -0
  81. package/dist/index.part-018.js.map +1 -0
  82. package/dist/index.part-019.d.ts +29 -0
  83. package/dist/index.part-019.d.ts.map +1 -0
  84. package/dist/index.part-019.js +261 -0
  85. package/dist/index.part-019.js.map +1 -0
  86. package/dist/index.part-020.d.ts +37 -0
  87. package/dist/index.part-020.d.ts.map +1 -0
  88. package/dist/index.part-020.js +388 -0
  89. package/dist/index.part-020.js.map +1 -0
  90. package/dist/index.part-021.d.ts +10 -0
  91. package/dist/index.part-021.d.ts.map +1 -0
  92. package/dist/index.part-021.js +142 -0
  93. package/dist/index.part-021.js.map +1 -0
  94. package/dist/loaders.d.ts +27 -91
  95. package/dist/loaders.d.ts.map +1 -1
  96. package/dist/loaders.js +22 -855
  97. package/dist/loaders.js.map +1 -1
  98. package/dist/loaders.part-001.d.ts +163 -0
  99. package/dist/loaders.part-001.d.ts.map +1 -0
  100. package/dist/loaders.part-001.js +277 -0
  101. package/dist/loaders.part-001.js.map +1 -0
  102. package/dist/loaders.part-002.d.ts +33 -0
  103. package/dist/loaders.part-002.d.ts.map +1 -0
  104. package/dist/loaders.part-002.js +511 -0
  105. package/dist/loaders.part-002.js.map +1 -0
  106. package/dist/loaders.part-003.d.ts +23 -0
  107. package/dist/loaders.part-003.d.ts.map +1 -0
  108. package/dist/loaders.part-003.js +138 -0
  109. package/dist/loaders.part-003.js.map +1 -0
  110. package/dist/materials.d.ts +33 -49
  111. package/dist/materials.d.ts.map +1 -1
  112. package/dist/materials.js +39 -4339
  113. package/dist/materials.js.map +1 -1
  114. package/dist/materials.part-001.d.ts +153 -0
  115. package/dist/materials.part-001.d.ts.map +1 -0
  116. package/dist/materials.part-001.js +347 -0
  117. package/dist/materials.part-001.js.map +1 -0
  118. package/dist/materials.part-002.d.ts +46 -0
  119. package/dist/materials.part-002.d.ts.map +1 -0
  120. package/dist/materials.part-002.js +299 -0
  121. package/dist/materials.part-002.js.map +1 -0
  122. package/dist/materials.part-003.d.ts +14 -0
  123. package/dist/materials.part-003.d.ts.map +1 -0
  124. package/dist/materials.part-003.js +438 -0
  125. package/dist/materials.part-003.js.map +1 -0
  126. package/dist/materials.part-004.d.ts +30 -0
  127. package/dist/materials.part-004.d.ts.map +1 -0
  128. package/dist/materials.part-004.js +464 -0
  129. package/dist/materials.part-004.js.map +1 -0
  130. package/dist/materials.part-005.d.ts +38 -0
  131. package/dist/materials.part-005.d.ts.map +1 -0
  132. package/dist/materials.part-005.js +366 -0
  133. package/dist/materials.part-005.js.map +1 -0
  134. package/dist/materials.part-006.d.ts +18 -0
  135. package/dist/materials.part-006.d.ts.map +1 -0
  136. package/dist/materials.part-006.js +391 -0
  137. package/dist/materials.part-006.js.map +1 -0
  138. package/dist/materials.part-007.d.ts +24 -0
  139. package/dist/materials.part-007.d.ts.map +1 -0
  140. package/dist/materials.part-007.js +467 -0
  141. package/dist/materials.part-007.js.map +1 -0
  142. package/dist/materials.part-008.d.ts +95 -0
  143. package/dist/materials.part-008.d.ts.map +1 -0
  144. package/dist/materials.part-008.js +404 -0
  145. package/dist/materials.part-008.js.map +1 -0
  146. package/dist/materials.part-009.d.ts +89 -0
  147. package/dist/materials.part-009.d.ts.map +1 -0
  148. package/dist/materials.part-009.js +412 -0
  149. package/dist/materials.part-009.js.map +1 -0
  150. package/dist/materials.part-010.d.ts +46 -0
  151. package/dist/materials.part-010.d.ts.map +1 -0
  152. package/dist/materials.part-010.js +375 -0
  153. package/dist/materials.part-010.js.map +1 -0
  154. package/dist/materials.part-011.d.ts +25 -0
  155. package/dist/materials.part-011.d.ts.map +1 -0
  156. package/dist/materials.part-011.js +435 -0
  157. package/dist/materials.part-011.js.map +1 -0
  158. package/dist/materials.part-012.d.ts +15 -0
  159. package/dist/materials.part-012.d.ts.map +1 -0
  160. package/dist/materials.part-012.js +229 -0
  161. package/dist/materials.part-012.js.map +1 -0
  162. package/dist/scene.d.ts +19 -279
  163. package/dist/scene.d.ts.map +1 -1
  164. package/dist/scene.js +21 -3931
  165. package/dist/scene.js.map +1 -1
  166. package/dist/scene.part-001.d.ts +375 -0
  167. package/dist/scene.part-001.d.ts.map +1 -0
  168. package/dist/scene.part-001.js +20 -0
  169. package/dist/scene.part-001.js.map +1 -0
  170. package/dist/scene.part-002.d.ts +28 -0
  171. package/dist/scene.part-002.d.ts.map +1 -0
  172. package/dist/scene.part-002.js +311 -0
  173. package/dist/scene.part-002.js.map +1 -0
  174. package/dist/scene.part-003.d.ts +26 -0
  175. package/dist/scene.part-003.d.ts.map +1 -0
  176. package/dist/scene.part-003.js +384 -0
  177. package/dist/scene.part-003.js.map +1 -0
  178. package/dist/scene.part-004.d.ts +24 -0
  179. package/dist/scene.part-004.d.ts.map +1 -0
  180. package/dist/scene.part-004.js +287 -0
  181. package/dist/scene.part-004.js.map +1 -0
  182. package/dist/scene.part-005.d.ts +37 -0
  183. package/dist/scene.part-005.d.ts.map +1 -0
  184. package/dist/scene.part-005.js +350 -0
  185. package/dist/scene.part-005.js.map +1 -0
  186. package/dist/scene.part-006.d.ts +25 -0
  187. package/dist/scene.part-006.d.ts.map +1 -0
  188. package/dist/scene.part-006.js +362 -0
  189. package/dist/scene.part-006.js.map +1 -0
  190. package/dist/scene.part-007.d.ts +36 -0
  191. package/dist/scene.part-007.d.ts.map +1 -0
  192. package/dist/scene.part-007.js +417 -0
  193. package/dist/scene.part-007.js.map +1 -0
  194. package/dist/scene.part-008.d.ts +78 -0
  195. package/dist/scene.part-008.d.ts.map +1 -0
  196. package/dist/scene.part-008.js +416 -0
  197. package/dist/scene.part-008.js.map +1 -0
  198. package/dist/scene.part-009.d.ts +25 -0
  199. package/dist/scene.part-009.d.ts.map +1 -0
  200. package/dist/scene.part-009.js +330 -0
  201. package/dist/scene.part-009.js.map +1 -0
  202. package/dist/scene.part-010.d.ts +32 -0
  203. package/dist/scene.part-010.d.ts.map +1 -0
  204. package/dist/scene.part-010.js +336 -0
  205. package/dist/scene.part-010.js.map +1 -0
  206. package/dist/scene.part-011.d.ts +100 -0
  207. package/dist/scene.part-011.d.ts.map +1 -0
  208. package/dist/scene.part-011.js +262 -0
  209. package/dist/scene.part-011.js.map +1 -0
  210. package/dist/scene.part-012.d.ts +48 -0
  211. package/dist/scene.part-012.d.ts.map +1 -0
  212. package/dist/scene.part-012.js +357 -0
  213. package/dist/scene.part-012.js.map +1 -0
  214. package/dist/scene.part-013.d.ts +51 -0
  215. package/dist/scene.part-013.d.ts.map +1 -0
  216. package/dist/scene.part-013.js +368 -0
  217. package/dist/scene.part-013.js.map +1 -0
  218. package/dist/scene.part-014.d.ts +16 -0
  219. package/dist/scene.part-014.d.ts.map +1 -0
  220. package/dist/scene.part-014.js +112 -0
  221. package/dist/scene.part-014.js.map +1 -0
  222. package/dist/types.d.ts +53 -1564
  223. package/dist/types.d.ts.map +1 -1
  224. package/dist/types.js +4 -1
  225. package/dist/types.js.map +1 -1
  226. package/dist/types.part-001.d.ts +386 -0
  227. package/dist/types.part-001.d.ts.map +1 -0
  228. package/dist/types.part-001.js +4 -0
  229. package/dist/types.part-001.js.map +1 -0
  230. package/dist/types.part-002.d.ts +407 -0
  231. package/dist/types.part-002.d.ts.map +1 -0
  232. package/dist/types.part-002.js +3 -0
  233. package/dist/types.part-002.js.map +1 -0
  234. package/dist/types.part-003.d.ts +427 -0
  235. package/dist/types.part-003.d.ts.map +1 -0
  236. package/dist/types.part-003.js +3 -0
  237. package/dist/types.part-003.js.map +1 -0
  238. package/dist/types.part-004.d.ts +351 -0
  239. package/dist/types.part-004.d.ts.map +1 -0
  240. package/dist/types.part-004.js +3 -0
  241. package/dist/types.part-004.js.map +1 -0
  242. package/native.d.ts +40 -0
  243. package/native.js +53 -52
  244. package/package.json +10 -8
package/dist/materials.js CHANGED
@@ -1,4342 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isCompressedTextureFormat = isCompressedTextureFormat;
4
- exports.extractEnvironmentMap = extractEnvironmentMap;
5
- exports.resolveSceneOverrideMaterial = resolveSceneOverrideMaterial;
6
- exports.resolveEnvironmentMap = resolveEnvironmentMap;
7
- exports.materialForGroup = materialForGroup;
8
- exports.assertMaterialLike = assertMaterialLike;
9
- exports.materialColor = materialColor;
10
- exports.extractPbrProperties = extractPbrProperties;
11
- exports.materialShadowSide = materialShadowSide;
12
- exports.textureUvChannel = textureUvChannel;
13
- exports.extractTextureData = extractTextureData;
14
- exports.extractBackgroundTexture = extractBackgroundTexture;
15
- exports.canvasLikeImageToRgba = canvasLikeImageToRgba;
16
- const math_1 = require("./math");
17
- const color_1 = require("./color");
18
- const objects_1 = require("./objects");
19
- // eslint-disable-next-line @typescript-eslint/no-var-requires
20
- const native = require('../native.js');
21
- // Three.js wrapping constants
22
- const RepeatWrapping = 1000;
23
- const ClampToEdgeWrapping = 1001;
24
- const MirroredRepeatWrapping = 1002;
25
- const NearestFilter = 1003;
26
- const NearestMipmapNearestFilter = 1004;
27
- const NearestMipmapLinearFilter = 1005;
28
- const LinearFilter = 1006;
29
- const LinearMipmapNearestFilter = 1007;
30
- const LinearMipmapLinearFilter = 1008;
31
- // Three.js texture mapping constants
32
- const CubeReflectionMapping = 301;
33
- const CubeRefractionMapping = 302;
34
- const EquirectangularReflectionMapping = 303;
35
- const EquirectangularRefractionMapping = 304;
36
- const CubeUVReflectionMapping = 306;
37
- // Three.js normal map type constants
38
- const TangentSpaceNormalMap = 0;
39
- const ObjectSpaceNormalMap = 1;
40
- // Three.js environment combine constants
41
- const MultiplyOperation = 0;
42
- const MixOperation = 1;
43
- const AddOperation = 2;
44
- // Three.js side constants
45
- const FrontSide = 0;
46
- const BackSide = 1;
47
- const DoubleSide = 2;
48
- // Three.js depth comparison constants
49
- const NeverDepth = 0;
50
- const AlwaysDepth = 1;
51
- const LessDepth = 2;
52
- const LessEqualDepth = 3;
53
- const EqualDepth = 4;
54
- const GreaterEqualDepth = 5;
55
- const GreaterDepth = 6;
56
- const NotEqualDepth = 7;
57
- // Three.js blending constants
58
- const NoBlending = 0;
59
- const NormalBlending = 1;
60
- const AdditiveBlending = 2;
61
- const SubtractiveBlending = 3;
62
- const MultiplyBlending = 4;
63
- const CustomBlending = 5;
64
- const AddEquation = 100;
65
- const SubtractEquation = 101;
66
- const ReverseSubtractEquation = 102;
67
- const MinEquation = 103;
68
- const MaxEquation = 104;
69
- const ZeroFactor = 200;
70
- const OneFactor = 201;
71
- const SrcColorFactor = 202;
72
- const OneMinusSrcColorFactor = 203;
73
- const SrcAlphaFactor = 204;
74
- const OneMinusSrcAlphaFactor = 205;
75
- const DstAlphaFactor = 206;
76
- const OneMinusDstAlphaFactor = 207;
77
- const DstColorFactor = 208;
78
- const OneMinusDstColorFactor = 209;
79
- const SrcAlphaSaturateFactor = 210;
80
- const ConstantColorFactor = 211;
81
- const OneMinusConstantColorFactor = 212;
82
- const ConstantAlphaFactor = 213;
83
- const OneMinusConstantAlphaFactor = 214;
84
- const NeverStencilFunc = 512;
85
- const LessStencilFunc = 513;
86
- const EqualStencilFunc = 514;
87
- const LessEqualStencilFunc = 515;
88
- const GreaterStencilFunc = 516;
89
- const NotEqualStencilFunc = 517;
90
- const GreaterEqualStencilFunc = 518;
91
- const AlwaysStencilFunc = 519;
92
- const ZeroStencilOp = 0;
93
- const KeepStencilOp = 7680;
94
- const ReplaceStencilOp = 7681;
95
- const IncrementStencilOp = 7682;
96
- const DecrementStencilOp = 7683;
97
- const IncrementWrapStencilOp = 34055;
98
- const DecrementWrapStencilOp = 34056;
99
- const InvertStencilOp = 5386;
100
- // Three.js depth-packing constants
101
- const BasicDepthPacking = 3200;
102
- const RGBADepthPacking = 3201;
103
- const RGBDepthPacking = 3202;
104
- const RGDepthPacking = 3203;
105
- // Three.js texture type constants
106
- const UnsignedByteType = 1009;
107
- const ByteType = 1010;
108
- const ShortType = 1011;
109
- const UnsignedShortType = 1012;
110
- const IntType = 1013;
111
- const UnsignedIntType = 1014;
112
- const HalfFloatType = 1016;
113
- const FloatType = 1015;
114
- const UnsignedShort4444Type = 1017;
115
- const UnsignedShort5551Type = 1018;
116
- const UnsignedInt248Type = 1020;
117
- const UnsignedInt5999Type = 35902;
118
- const UnsignedInt101111Type = 35899;
119
- const LinearEncoding = 3000;
120
- const sRGBEncoding = 3001;
121
- // Three.js texture format constants
122
- const AlphaFormat = 1021;
123
- const LuminanceAlphaFormat = 1025;
124
- const CompressedTextureFormats = new Set([
125
- 33776, // RGB_S3TC_DXT1_Format
126
- 33777, // RGBA_S3TC_DXT1_Format
127
- 33778, // RGBA_S3TC_DXT3_Format
128
- 33779, // RGBA_S3TC_DXT5_Format
129
- 35840, // RGB_PVRTC_4BPPV1_Format
130
- 35841, // RGB_PVRTC_2BPPV1_Format
131
- 35842, // RGBA_PVRTC_4BPPV1_Format
132
- 35843, // RGBA_PVRTC_2BPPV1_Format
133
- 36196, // RGB_ETC1_Format
134
- 36283, // RED_RGTC1_Format
135
- 36284, // SIGNED_RED_RGTC1_Format
136
- 36285, // RED_GREEN_RGTC2_Format
137
- 36286, // SIGNED_RED_GREEN_RGTC2_Format
138
- 36492, // RGBA_BPTC_Format
139
- 36494, // RGB_BPTC_SIGNED_Format
140
- 36495, // RGB_BPTC_UNSIGNED_Format
141
- 37488, // R11_EAC_Format
142
- 37489, // SIGNED_R11_EAC_Format
143
- 37490, // RG11_EAC_Format
144
- 37491, // SIGNED_RG11_EAC_Format
145
- 37492, // RGB_ETC2_Format
146
- 37496, // RGBA_ETC2_EAC_Format
147
- 37808, // RGBA_ASTC_4x4_Format
148
- 37809, // RGBA_ASTC_5x4_Format
149
- 37810, // RGBA_ASTC_5x5_Format
150
- 37811, // RGBA_ASTC_6x5_Format
151
- 37812, // RGBA_ASTC_6x6_Format
152
- 37813, // RGBA_ASTC_8x5_Format
153
- 37814, // RGBA_ASTC_8x6_Format
154
- 37815, // RGBA_ASTC_8x8_Format
155
- 37816, // RGBA_ASTC_10x5_Format
156
- 37817, // RGBA_ASTC_10x6_Format
157
- 37818, // RGBA_ASTC_10x8_Format
158
- 37819, // RGBA_ASTC_10x10_Format
159
- 37820, // RGBA_ASTC_12x10_Format
160
- 37821, // RGBA_ASTC_12x12_Format
161
- ]);
162
- function isCompressedTextureFormat(format) {
163
- return typeof format === 'number' && CompressedTextureFormats.has(format);
164
- }
165
- const DefaultOnBeforeCompileSource = 'onBeforeCompile( /* shaderobject, renderer */ ) {}';
166
- const MaterialNodeHookProperties = new Set([
167
- 'alphaTestNode',
168
- 'aoNode',
169
- 'attenuationColorNode',
170
- 'attenuationDistanceNode',
171
- 'backdropAlphaNode',
172
- 'backdropNode',
173
- 'castShadowNode',
174
- 'clearcoatNode',
175
- 'clearcoatRoughnessNode',
176
- 'colorNode',
177
- 'dashScaleNode',
178
- 'dashSizeNode',
179
- 'depthNode',
180
- 'dispersionNode',
181
- 'emissiveNode',
182
- 'envNode',
183
- 'fragmentNode',
184
- 'gapSizeNode',
185
- 'geometryNode',
186
- 'iorNode',
187
- 'iridescenceIORNode',
188
- 'iridescenceNode',
189
- 'iridescenceThicknessNode',
190
- 'lightMapNode',
191
- 'lightsNode',
192
- 'metalnessNode',
193
- 'mrtNode',
194
- 'normalNode',
195
- 'offsetNode',
196
- 'opacityNode',
197
- 'outputNode',
198
- 'positionNode',
199
- 'receivedShadowNode',
200
- 'rotationNode',
201
- 'roughnessNode',
202
- 'scaleNode',
203
- 'shadowPositionNode',
204
- 'sheenNode',
205
- 'sheenRoughnessNode',
206
- 'shininessNode',
207
- 'specularNode',
208
- 'thicknessNode',
209
- 'transmissionNode',
210
- 'vertexNode',
211
- ]);
212
- /**
213
- * Extract environment map data from scene.environment.
214
- * Supports DataTexture (equirectangular) with Uint8, Float16, Float32 pixel data.
215
- * Normalizes 3-channel inputs to RGBA before handing bytes to the native IBL path.
216
- */
217
- function extractEnvironmentMap(scene, intensityOverride) {
218
- if (scene.environment != null) {
219
- const envTex = requiredEnvironmentTexture(scene.environment, 'scene.environment');
220
- const intensity = intensityOverride !== undefined
221
- ? intensityOverride
222
- : optionalFiniteNumber(scene.environmentIntensity, 'scene.environmentIntensity') ?? 1.0;
223
- return extractEnvironmentMapFromTexture(envTex, 'scene.environment', intensity);
224
- }
225
- const probe = extractReflectionProbe(scene);
226
- if (!probe)
227
- return null;
228
- const intensity = intensityOverride !== undefined
229
- ? intensityOverride
230
- : optionalFiniteNumber(probe.intensity, 'reflectionProbe.intensity') ?? 1.0;
231
- return extractEnvironmentMapFromTexture(probe.texture, probe.label, intensity);
232
- }
233
- function resolveSceneOverrideMaterial(scene) {
234
- const overrideMaterial = scene.overrideMaterial;
235
- if (overrideMaterial == null)
236
- return undefined;
237
- assertMaterialLike(overrideMaterial, 'scene.overrideMaterial');
238
- return overrideMaterial;
239
- }
240
- function resolveEnvironmentMap(scene, intensityOverride, overrideMaterial) {
241
- const sceneEnvMap = extractEnvironmentMap(scene, intensityOverride);
242
- if (sceneEnvMap) {
243
- return { envMap: sceneEnvMap };
244
- }
245
- if (overrideMaterial) {
246
- const overrideEnvMap = extractOverrideMaterialEnvironmentMap(overrideMaterial);
247
- if (overrideEnvMap) {
248
- return overrideEnvMap;
249
- }
250
- return { envMap: null };
251
- }
252
- const materialEnvMap = extractMaterialEnvironmentMap(scene);
253
- if (!materialEnvMap) {
254
- return { envMap: null };
255
- }
256
- return {
257
- envMap: materialEnvMap.envMap,
258
- rotation: materialEnvMap.rotation,
259
- materialContext: {
260
- materialEnvironmentSource: 'material',
261
- materialEnvironmentMaps: materialEnvMap.materials,
262
- },
263
- };
264
- }
265
- function extractOverrideMaterialEnvironmentMap(material) {
266
- if (optionalBoolean(material.visible, 'scene.overrideMaterial.visible') === false)
267
- return null;
268
- const materialEnvMap = material.envMap;
269
- if (!materialEnvMap)
270
- return null;
271
- if (!supportsNativeMaterialEnvironmentMap(material))
272
- return null;
273
- assertSupportedMaterialEnvironmentMap(material);
274
- const usesRefraction = isRefractionEnvironmentMapping(materialEnvMap.mapping);
275
- const envMap = extractEnvironmentMapFromTexture(materialEnvMap, 'material.envMap', 1, { allowRefraction: usesRefraction });
276
- const materials = new WeakSet();
277
- materials.add(material);
278
- return {
279
- envMap,
280
- rotation: materialEnvMapRotation(material),
281
- materialContext: {
282
- materialEnvironmentSource: 'material',
283
- materialEnvironmentMaps: materials,
284
- },
285
- };
286
- }
287
- function extractMaterialEnvironmentMap(scene) {
288
- let envTex = null;
289
- let envRotation;
290
- let allowRefractionMapping = false;
291
- const materials = new WeakSet();
292
- const visit = (object) => {
293
- if (!object)
294
- return;
295
- if (optionalBoolean(object.visible, 'object.visible') === false)
296
- return;
297
- for (const material of objectMaterials(object.material)) {
298
- const materialEnvMap = material?.envMap;
299
- if (!materialEnvMap)
300
- continue;
301
- if (optionalBoolean(material.visible, 'material.visible') === false)
302
- continue;
303
- if (!supportsNativeMaterialEnvironmentMap(material))
304
- continue;
305
- assertSupportedMaterialEnvironmentMap(material);
306
- const materialEnvRotation = materialEnvMapRotation(material);
307
- if (materialEnvRotation) {
308
- if (envRotation && !sameVector3Like(envRotation, materialEnvRotation)) {
309
- throw new Error('Multiple material.envMapRotation values are not supported by @headless-three/renderer yet. Use one shared material envMapRotation, scene.environmentRotation, or render separate passes.');
310
- }
311
- envRotation = materialEnvRotation;
312
- }
313
- if (envTex && envTex !== materialEnvMap) {
314
- throw new Error('Multiple distinct material.envMap textures are not supported by @headless-three/renderer yet. Use one shared material envMap, scene.environment, or render separate passes until per-material IBL maps are supported.');
315
- }
316
- envTex = materialEnvMap;
317
- if (isRefractionEnvironmentMapping(materialEnvMap.mapping)) {
318
- allowRefractionMapping = true;
319
- }
320
- materials.add(material);
321
- }
322
- for (const child of (0, objects_1.objectChildren)(object)) {
323
- visit(child);
324
- }
325
- };
326
- visit(scene);
327
- if (!envTex)
328
- return null;
329
- const envMap = extractEnvironmentMapFromTexture(envTex, 'material.envMap', 1, { allowRefraction: allowRefractionMapping });
330
- return envMap ? { envMap, materials, rotation: envRotation } : null;
331
- }
332
- function objectMaterials(material) {
333
- if (!material)
334
- return [];
335
- if (!Array.isArray(material)) {
336
- assertMaterialLike(material, 'material');
337
- return [material];
338
- }
339
- const materials = [];
340
- for (let index = 0; index < material.length; index += 1) {
341
- const entry = material[index];
342
- if (!entry)
343
- continue;
344
- assertMaterialLike(entry, `material[${index}]`);
345
- materials.push(entry);
346
- }
347
- return materials;
348
- }
349
- function supportsNativeMaterialEnvironmentMap(material) {
350
- return material.isMeshStandardMaterial === true
351
- || material.isMeshPhysicalMaterial === true
352
- || material.isMeshBasicMaterial === true
353
- || material.isMeshPhongMaterial === true
354
- || material.isMeshLambertMaterial === true;
355
- }
356
- function supportsLegacyMaterialEnvironmentRefraction(material) {
357
- return material.isMeshBasicMaterial === true
358
- || material.isMeshPhongMaterial === true
359
- || material.isMeshLambertMaterial === true;
360
- }
361
- function assertSupportedMaterialEnvironmentMap(material) {
362
- const usesRefraction = isRefractionEnvironmentMapping(material.envMap.mapping);
363
- if (usesRefraction && !supportsLegacyMaterialEnvironmentRefraction(material)) {
364
- throw new Error('material.envMap refraction mappings are only supported for MeshBasicMaterial, MeshLambertMaterial, and MeshPhongMaterial by @headless-three/renderer yet. Use a reflection mapping, remove material.envMap, or render this material separately.');
365
- }
366
- assertSupportedEnvironmentTexture(material.envMap, 'material.envMap', { allowRefraction: usesRefraction });
367
- const combine = material.combine ?? MultiplyOperation;
368
- if (![MultiplyOperation, MixOperation, AddOperation].includes(combine)) {
369
- throw new Error('material.envMap combine must be MultiplyOperation, MixOperation, or AddOperation for @headless-three/renderer.');
370
- }
371
- }
372
- function extractEnvironmentMapFromTexture(envTex, label, intensity, options = {}) {
373
- assertSupportedEnvironmentTexture(envTex, label, options);
374
- textureUnpackAlignment(envTex, label);
375
- const premultiplyAlpha = optionalTextureBoolean(envTex.premultiplyAlpha, `${label}.premultiplyAlpha`) === true;
376
- if (isCubeEnvironmentTexture(envTex, label)) {
377
- const cube = cubeTextureToEquirectangular(envTex, label);
378
- return { data: cube.data, width: cube.width, height: cube.height, intensity, colorSpace: textureColorSpace(envTex) };
379
- }
380
- const sourceData = textureSourceData(envTex, label);
381
- const image = envTex.image ?? sourceData;
382
- if (!image)
383
- throw unsupportedTextureImageError(label, 'environment map rendering');
384
- // DataTexture: { data, width, height }
385
- if (image.data && image.width > 0 && image.height > 0) {
386
- const texType = envTex.type ?? UnsignedByteType;
387
- assertSupportedRawTextureType(texType, label, 'environment map rendering');
388
- const rawData = image.data;
389
- const texFormat = envTex.format;
390
- if (texType === HalfFloatType) {
391
- if (!(rawData instanceof Uint16Array)) {
392
- throw new Error(`${label} HalfFloatType environment maps must provide Uint16Array one-channel, two-channel, RGB, or RGBA pixel data.`);
393
- }
394
- const buf = rawHalfFloatTextureDataToRgba(rawData, image.width, image.height, label, 'environment map rendering', { premultiplyAlpha, format: texFormat });
395
- return { data: buf, width: image.width, height: image.height, intensity, colorSpace: textureColorSpace(envTex) };
396
- }
397
- if (texType === FloatType) {
398
- if (!(rawData instanceof Float32Array)) {
399
- throw new Error(`${label} FloatType environment maps must provide Float32Array one-channel, two-channel, RGB, or RGBA pixel data.`);
400
- }
401
- const buf = rawFloatTextureDataToRgba(rawData, image.width, image.height, label, 'environment map rendering', { premultiplyAlpha, format: texFormat });
402
- return { data: buf, width: image.width, height: image.height, intensity, colorSpace: textureColorSpace(envTex) };
403
- }
404
- // UnsignedByteType / default: convert to RGBA8
405
- const rgba = toRgba8(rawData, image.width, image.height, { type: texType, format: texFormat });
406
- if (rgba) {
407
- const data = premultiplyAlpha ? premultiplyRgbaAlpha(rgba) : rgba;
408
- return {
409
- data: Buffer.from(data.buffer, data.byteOffset, data.byteLength),
410
- width: image.width,
411
- height: image.height,
412
- intensity,
413
- colorSpace: textureColorSpace(envTex),
414
- };
415
- }
416
- throw unsupportedRawTextureDataError(label, 'environment map rendering');
417
- }
418
- const canvasImage = canvasLikeImageToRgba(image, label);
419
- if (canvasImage) {
420
- const data = premultiplyAlpha ? premultiplyRgbaAlpha(canvasImage.rgba) : canvasImage.rgba;
421
- return {
422
- data: Buffer.from(data.buffer, data.byteOffset, data.byteLength),
423
- width: canvasImage.width,
424
- height: canvasImage.height,
425
- intensity,
426
- colorSpace: textureColorSpace(envTex),
427
- };
428
- }
429
- // Encoded image buffer (e.g. loaded HDR encoded as PNG/EXR)
430
- if (Buffer.isBuffer(image)) {
431
- assertNoEncodedPremultiplyAlpha(envTex, label);
432
- return { data: image, width: 0, height: 0, intensity, colorSpace: textureColorSpace(envTex) };
433
- }
434
- if (image instanceof Uint8Array && !(image.width > 0)) {
435
- assertNoEncodedPremultiplyAlpha(envTex, label);
436
- return {
437
- data: Buffer.from(image.buffer, image.byteOffset, image.byteLength),
438
- width: 0,
439
- height: 0,
440
- intensity,
441
- colorSpace: textureColorSpace(envTex),
442
- };
443
- }
444
- throw unsupportedTextureImageError(label, 'environment map rendering');
445
- }
446
- function extractReflectionProbe(scene) {
447
- const hintBag = sceneRendererHints(scene);
448
- const hints = hintBag?.value ?? {};
449
- const probesKey = hints.reflectionProbes != null ? 'reflectionProbes' : 'probes';
450
- const probes = hints.reflectionProbes ?? hints.probes;
451
- if (probes != null && !Array.isArray(probes)) {
452
- const label = hintBag ? `${hintBag.label}.${probesKey}` : `scene.userData.${probesKey}`;
453
- throw new TypeError(`${label} must be an array.`);
454
- }
455
- const probe = hints.reflectionProbe ?? (Array.isArray(probes) ? probes[0] : undefined);
456
- if (probe == null)
457
- return null;
458
- const directTexture = textureLike(probe);
459
- if (directTexture) {
460
- return {
461
- texture: directTexture,
462
- intensity: undefined,
463
- label: 'reflectionProbe',
464
- };
465
- }
466
- const probeObject = probe;
467
- if (probeObject.texture != null) {
468
- return {
469
- texture: requiredEnvironmentTexture(probeObject.texture, 'reflectionProbe.texture'),
470
- intensity: probeObject.intensity,
471
- label: 'reflectionProbe.texture',
472
- };
473
- }
474
- if (probeObject.map != null) {
475
- return {
476
- texture: requiredEnvironmentTexture(probeObject.map, 'reflectionProbe.map'),
477
- intensity: probeObject.intensity,
478
- label: 'reflectionProbe.map',
479
- };
480
- }
481
- const texture = requiredEnvironmentTexture(probe, 'reflectionProbe');
482
- return {
483
- texture,
484
- intensity: probeObject.intensity,
485
- label: 'reflectionProbe',
486
- };
487
- }
488
- function sceneRendererHints(scene) {
489
- const userData = scene.userData;
490
- if (userData == null)
491
- return undefined;
492
- if (typeof userData !== 'object' || Array.isArray(userData)) {
493
- throw new TypeError('scene.userData must be an object.');
494
- }
495
- const value = userData.headlessThreeRenderer ?? userData.headlessRenderer;
496
- if (value == null)
497
- return undefined;
498
- const label = userData.headlessThreeRenderer != null
499
- ? 'scene.userData.headlessThreeRenderer'
500
- : 'scene.userData.headlessRenderer';
501
- if (typeof value !== 'object' || Array.isArray(value)) {
502
- throw new TypeError(`${label} must be an object.`);
503
- }
504
- return { value: value, label };
505
- }
506
- function materialForGroup(material, materialIndex) {
507
- if (Array.isArray(material)) {
508
- const index = material[materialIndex] != null ? materialIndex : 0;
509
- const resolved = material[index];
510
- assertMaterialLike(resolved, `material[${index}]`);
511
- return resolved;
512
- }
513
- assertMaterialLike(material, 'material');
514
- return material;
515
- }
516
- function assertMaterialLike(value, label) {
517
- if (value == null)
518
- return;
519
- if (typeof value !== 'object' || Array.isArray(value)) {
520
- throw new TypeError(`${label} must be a material-like object.`);
521
- }
522
- }
523
- function materialColor(material, context = {}) {
524
- const signature = material && context.materialColorCache
525
- ? materialColorSignature(material)
526
- : null;
527
- if (material && signature) {
528
- const cached = materialColorCacheEntry(context, material)?.base;
529
- if (cached && sameMaterialColorSignature(cached.signature, signature)) {
530
- return copyColor(cached.color);
531
- }
532
- }
533
- const copyShader = copyShaderMaterialInfo(material);
534
- const color = (0, color_1.validatedColorLikeToArray)(material?.color, 'material.color') ?? [1, 1, 1, 1];
535
- const opacity = copyShader
536
- ? optionalFiniteNumber(copyShader.opacity, 'material.uniforms.opacity.value')
537
- : optionalFiniteNumber(material?.opacity, 'material.opacity');
538
- color[3] = (0, math_1.clamp01)(opacity ?? color[3] ?? 1);
539
- if (material && signature) {
540
- materialColorCacheEntry(context, material, true).base = { signature, color: copyColor(color) };
541
- }
542
- return color;
543
- }
544
- function materialColorSignature(material) {
545
- const copyShader = copyShaderMaterialInfo(material);
546
- return materialSlotColorSignature(material.color, copyShader ? copyShader.opacity : material.opacity);
547
- }
548
- function materialSlotColor(material, slot, value, label, context) {
549
- const signature = context.materialColorCache
550
- ? materialSlotColorSignature(value)
551
- : null;
552
- if (signature) {
553
- const cached = materialColorCacheEntry(context, material)?.slots?.get(slot);
554
- if (cached && sameMaterialColorSignature(cached.signature, signature)) {
555
- return copyColor(cached.color);
556
- }
557
- }
558
- const color = (0, color_1.validatedColorLikeToArray)(value, label);
559
- if (signature && color) {
560
- const entry = materialColorCacheEntry(context, material, true);
561
- entry.slots ?? (entry.slots = new Map());
562
- entry.slots.set(slot, { signature, color: copyColor(color) });
563
- }
564
- return color;
565
- }
566
- function materialColorCacheEntry(context, material, create = false) {
567
- const cache = context.materialColorCache;
568
- if (!cache)
569
- return undefined;
570
- let entry = cache.get(material);
571
- if (!entry && create) {
572
- entry = {};
573
- cache.set(material, entry);
574
- }
575
- return entry;
576
- }
577
- function materialSlotColorSignature(color, opacity) {
578
- const signature = {
579
- color,
580
- opacity,
581
- };
582
- if (Array.isArray(color)) {
583
- signature.colorLength = color.length;
584
- signature.values = color.slice();
585
- }
586
- else if (color && typeof color === 'object') {
587
- const shaped = color;
588
- signature.r = shaped.r;
589
- signature.g = shaped.g;
590
- signature.b = shaped.b;
591
- signature.a = shaped.a;
592
- }
593
- return signature;
594
- }
595
- function copyColor(color) {
596
- return color.slice();
597
- }
598
- function sameMaterialColorSignature(a, b) {
599
- return a.color === b.color
600
- && a.colorLength === b.colorLength
601
- && a.r === b.r
602
- && a.g === b.g
603
- && a.b === b.b
604
- && a.a === b.a
605
- && a.opacity === b.opacity
606
- && sameUnknownArray(a.values, b.values);
607
- }
608
- function sameUnknownArray(a, b) {
609
- if (a === b)
610
- return true;
611
- if (!a || !b)
612
- return false;
613
- if (a.length !== b.length)
614
- return false;
615
- for (let i = 0; i < a.length; i += 1) {
616
- if (!Object.is(a[i], b[i]))
617
- return false;
618
- }
619
- return true;
620
- }
621
- function extractPbrProperties(material, context = {}) {
622
- if (!material)
623
- return {};
624
- const customFragmentShader = extractCustomFragmentShader(material);
625
- assertSupportedShaderMaterial(material, customFragmentShader);
626
- assertSupportedOnBeforeCompile(material, customFragmentShader);
627
- assertSupportedMaterialNodeHooks(material);
628
- assertSupportedMaterialClass(material, customFragmentShader);
629
- assertSupportedMaterialState(material, context);
630
- optionalBoolean(material.visible, 'material.visible');
631
- optionalBoolean(material.vertexColors, 'material.vertexColors');
632
- const props = materialScalarFeatureProperties(material, context);
633
- const sheen = (0, math_1.clamp01)(optionalFiniteNumber(material.sheen, 'material.sheen') ?? 0);
634
- const physicalMapFeatures = {
635
- clearcoat: (props.clearcoat ?? 0) > 0,
636
- sheen: sheen > 0,
637
- anisotropy: (props.anisotropy ?? 0) > 0,
638
- iridescence: (props.iridescence ?? 0) > 0,
639
- transmission: (props.transmission ?? 0) > 0,
640
- };
641
- assertCompatiblePackedPhysicalMapSamplers(material, physicalMapFeatures);
642
- const textureFromSlot = (slot, label) => extractTextureFromSlot(slot, label, context.textureCache);
643
- const colorFromSlot = (slot, value, label) => materialSlotColor(material, slot, value, label, context);
644
- const textureStateFromSlot = (prefix, slot, label, options) => assignPbrTextureSamplerState(props, prefix, slot, label, context, options);
645
- const clearcoatMapInfo = physicalMapFeatures.clearcoat
646
- ? textureFromSlot(material.clearcoatMap, 'material.clearcoatMap')
647
- : null;
648
- if (clearcoatMapInfo) {
649
- props.clearcoatMap = clearcoatMapInfo.data;
650
- props.clearcoatMapWidth = clearcoatMapInfo.width;
651
- props.clearcoatMapHeight = clearcoatMapInfo.height;
652
- textureStateFromSlot('clearcoatMap', material.clearcoatMap, 'material.clearcoatMap');
653
- }
654
- const clearcoatRoughnessMapInfo = physicalMapFeatures.clearcoat
655
- ? textureFromSlot(material.clearcoatRoughnessMap, 'material.clearcoatRoughnessMap')
656
- : null;
657
- if (clearcoatRoughnessMapInfo) {
658
- props.clearcoatRoughnessMap = clearcoatRoughnessMapInfo.data;
659
- props.clearcoatRoughnessMapWidth = clearcoatRoughnessMapInfo.width;
660
- props.clearcoatRoughnessMapHeight = clearcoatRoughnessMapInfo.height;
661
- textureStateFromSlot('clearcoatRoughnessMap', material.clearcoatRoughnessMap, 'material.clearcoatRoughnessMap');
662
- }
663
- const clearcoatNormalMapInfo = physicalMapFeatures.clearcoat
664
- ? textureFromSlot(material.clearcoatNormalMap, 'material.clearcoatNormalMap')
665
- : null;
666
- if (clearcoatNormalMapInfo) {
667
- props.clearcoatNormalMap = clearcoatNormalMapInfo.data;
668
- props.clearcoatNormalMapWidth = clearcoatNormalMapInfo.width;
669
- props.clearcoatNormalMapHeight = clearcoatNormalMapInfo.height;
670
- textureStateFromSlot('clearcoatNormalMap', material.clearcoatNormalMap, 'material.clearcoatNormalMap');
671
- }
672
- const sheenColor = colorFromSlot('sheenColor', material.sheenColor, 'material.sheenColor');
673
- if (sheenColor && sheen > 0) {
674
- props.sheenColor = [
675
- sheenColor[0] * sheen,
676
- sheenColor[1] * sheen,
677
- sheenColor[2] * sheen,
678
- ];
679
- }
680
- const sheenColorMapInfo = physicalMapFeatures.sheen
681
- ? textureFromSlot(material.sheenColorMap, 'material.sheenColorMap')
682
- : null;
683
- if (sheenColorMapInfo) {
684
- props.sheenColorMap = sheenColorMapInfo.data;
685
- props.sheenColorMapWidth = sheenColorMapInfo.width;
686
- props.sheenColorMapHeight = sheenColorMapInfo.height;
687
- textureStateFromSlot('sheenColorMap', material.sheenColorMap, 'material.sheenColorMap');
688
- }
689
- const sheenRoughnessMapInfo = physicalMapFeatures.sheen
690
- ? textureFromSlot(material.sheenRoughnessMap, 'material.sheenRoughnessMap')
691
- : null;
692
- if (sheenRoughnessMapInfo) {
693
- props.sheenRoughnessMap = sheenRoughnessMapInfo.data;
694
- props.sheenRoughnessMapWidth = sheenRoughnessMapInfo.width;
695
- props.sheenRoughnessMapHeight = sheenRoughnessMapInfo.height;
696
- textureStateFromSlot('sheenRoughnessMap', material.sheenRoughnessMap, 'material.sheenRoughnessMap');
697
- }
698
- const anisotropyMapInfo = physicalMapFeatures.anisotropy
699
- ? textureFromSlot(material.anisotropyMap, 'material.anisotropyMap')
700
- : null;
701
- if (anisotropyMapInfo) {
702
- props.anisotropyMap = anisotropyMapInfo.data;
703
- props.anisotropyMapWidth = anisotropyMapInfo.width;
704
- props.anisotropyMapHeight = anisotropyMapInfo.height;
705
- textureStateFromSlot('anisotropyMap', material.anisotropyMap, 'material.anisotropyMap');
706
- }
707
- const iridescenceMapInfo = physicalMapFeatures.iridescence
708
- ? textureFromSlot(material.iridescenceMap, 'material.iridescenceMap')
709
- : null;
710
- if (iridescenceMapInfo) {
711
- props.iridescenceMap = iridescenceMapInfo.data;
712
- props.iridescenceMapWidth = iridescenceMapInfo.width;
713
- props.iridescenceMapHeight = iridescenceMapInfo.height;
714
- textureStateFromSlot('iridescenceMap', material.iridescenceMap, 'material.iridescenceMap');
715
- }
716
- const iridescenceThicknessMapInfo = physicalMapFeatures.iridescence
717
- ? textureFromSlot(material.iridescenceThicknessMap, 'material.iridescenceThicknessMap')
718
- : null;
719
- if (iridescenceThicknessMapInfo) {
720
- props.iridescenceThicknessMap = iridescenceThicknessMapInfo.data;
721
- props.iridescenceThicknessMapWidth = iridescenceThicknessMapInfo.width;
722
- props.iridescenceThicknessMapHeight = iridescenceThicknessMapInfo.height;
723
- textureStateFromSlot('iridescenceThicknessMap', material.iridescenceThicknessMap, 'material.iridescenceThicknessMap');
724
- }
725
- const transmissionMapInfo = physicalMapFeatures.transmission
726
- ? textureFromSlot(material.transmissionMap, 'material.transmissionMap')
727
- : null;
728
- if (transmissionMapInfo) {
729
- props.transmissionMap = transmissionMapInfo.data;
730
- props.transmissionMapWidth = transmissionMapInfo.width;
731
- props.transmissionMapHeight = transmissionMapInfo.height;
732
- textureStateFromSlot('transmissionMap', material.transmissionMap, 'material.transmissionMap');
733
- }
734
- const thicknessMapInfo = physicalMapFeatures.transmission
735
- ? textureFromSlot(material.thicknessMap, 'material.thicknessMap')
736
- : null;
737
- if (thicknessMapInfo) {
738
- props.thicknessMap = thicknessMapInfo.data;
739
- props.thicknessMapWidth = thicknessMapInfo.width;
740
- props.thicknessMapHeight = thicknessMapInfo.height;
741
- textureStateFromSlot('thicknessMap', material.thicknessMap, 'material.thicknessMap');
742
- }
743
- const attenuationColor = colorFromSlot('attenuationColor', material.attenuationColor, 'material.attenuationColor');
744
- if (attenuationColor) {
745
- props.attenuationColor = [attenuationColor[0], attenuationColor[1], attenuationColor[2]];
746
- }
747
- const physicalSpecularColor = colorFromSlot('specularColor', material.specularColor, 'material.specularColor');
748
- if (physicalSpecularColor) {
749
- props.physicalSpecularColor = [
750
- physicalSpecularColor[0],
751
- physicalSpecularColor[1],
752
- physicalSpecularColor[2],
753
- ];
754
- }
755
- const specularColorMapInfo = textureFromSlot(material.specularColorMap, 'material.specularColorMap');
756
- if (specularColorMapInfo) {
757
- props.specularColorMap = specularColorMapInfo.data;
758
- props.specularColorMapWidth = specularColorMapInfo.width;
759
- props.specularColorMapHeight = specularColorMapInfo.height;
760
- textureStateFromSlot('specularColorMap', material.specularColorMap, 'material.specularColorMap');
761
- }
762
- const specularIntensityMapInfo = textureFromSlot(material.specularIntensityMap, 'material.specularIntensityMap');
763
- if (specularIntensityMapInfo) {
764
- props.specularIntensityMap = specularIntensityMapInfo.data;
765
- props.specularIntensityMapWidth = specularIntensityMapInfo.width;
766
- props.specularIntensityMapHeight = specularIntensityMapInfo.height;
767
- textureStateFromSlot('specularIntensityMap', material.specularIntensityMap, 'material.specularIntensityMap');
768
- }
769
- const specularColor = colorFromSlot('specular', material.specular, 'material.specular');
770
- if (specularColor || material.isMeshPhongMaterial) {
771
- const color = specularColor ?? [17 / 255, 17 / 255, 17 / 255, 1];
772
- props.specularColor = [color[0], color[1], color[2]];
773
- }
774
- const emissive = colorFromSlot('emissive', material.emissive, 'material.emissive');
775
- if (emissive) {
776
- props.emissive = [emissive[0], emissive[1], emissive[2]];
777
- props.emissiveIntensity = finiteNumberOrDefault(material.emissiveIntensity, 'material.emissiveIntensity', 1);
778
- }
779
- const normalMapInfo = textureFromSlot(material.normalMap, 'material.normalMap');
780
- if (normalMapInfo) {
781
- props.normalMap = normalMapInfo.data;
782
- props.normalMapWidth = normalMapInfo.width;
783
- props.normalMapHeight = normalMapInfo.height;
784
- textureStateFromSlot('normalMap', material.normalMap, 'material.normalMap');
785
- props.normalMapType = materialNormalMapType(material);
786
- }
787
- const bumpMapInfo = textureFromSlot(material.bumpMap, 'material.bumpMap');
788
- if (bumpMapInfo) {
789
- props.bumpMap = bumpMapInfo.data;
790
- props.bumpMapWidth = bumpMapInfo.width;
791
- props.bumpMapHeight = bumpMapInfo.height;
792
- textureStateFromSlot('bumpMap', material.bumpMap, 'material.bumpMap');
793
- props.bumpScale = finiteNumberOrDefault(material.bumpScale, 'material.bumpScale', 1);
794
- }
795
- if (material.isMeshMatcapMaterial) {
796
- const matcapMapInfo = textureFromSlot(material.map, 'material.map');
797
- if (matcapMapInfo) {
798
- props.matcapMap = matcapMapInfo.data;
799
- props.matcapMapWidth = matcapMapInfo.width;
800
- props.matcapMapHeight = matcapMapInfo.height;
801
- textureStateFromSlot('matcapMap', material.map, 'material.map');
802
- }
803
- }
804
- const gradientMapInfo = textureFromSlot(material.gradientMap, 'material.gradientMap');
805
- if (gradientMapInfo) {
806
- props.gradientMap = gradientMapInfo.data;
807
- props.gradientMapWidth = gradientMapInfo.width;
808
- props.gradientMapHeight = gradientMapInfo.height;
809
- textureStateFromSlot('gradientMap', material.gradientMap, 'material.gradientMap', {
810
- includeTransform: false,
811
- includeUvChannel: false,
812
- });
813
- }
814
- const displacementMapInfo = textureFromSlot(material.displacementMap, 'material.displacementMap');
815
- if (displacementMapInfo) {
816
- props.displacementMap = displacementMapInfo.data;
817
- props.displacementMapWidth = displacementMapInfo.width;
818
- props.displacementMapHeight = displacementMapInfo.height;
819
- textureStateFromSlot('displacementMap', material.displacementMap, 'material.displacementMap');
820
- props.displacementScale = finiteNumberOrDefault(material.displacementScale, 'material.displacementScale', 1);
821
- props.displacementBias = finiteNumberOrDefault(material.displacementBias, 'material.displacementBias', 0);
822
- }
823
- const mrMap = material.metalnessMap ?? material.roughnessMap;
824
- const mrMapLabel = material.metalnessMap ? 'material.metalnessMap' : 'material.roughnessMap';
825
- const mrMapInfo = textureFromSlot(mrMap, mrMapLabel);
826
- if (mrMapInfo) {
827
- props.metallicRoughnessTexture = mrMapInfo.data;
828
- props.metallicRoughnessTextureWidth = mrMapInfo.width;
829
- props.metallicRoughnessTextureHeight = mrMapInfo.height;
830
- textureStateFromSlot('metallicRoughnessTexture', mrMap, mrMapLabel);
831
- }
832
- const specularMapInfo = textureFromSlot(material.specularMap, 'material.specularMap');
833
- if (specularMapInfo) {
834
- props.specularMap = specularMapInfo.data;
835
- props.specularMapWidth = specularMapInfo.width;
836
- props.specularMapHeight = specularMapInfo.height;
837
- textureStateFromSlot('specularMap', material.specularMap, 'material.specularMap');
838
- }
839
- const emissiveMapInfo = textureFromSlot(material.emissiveMap, 'material.emissiveMap');
840
- if (emissiveMapInfo) {
841
- props.emissiveMap = emissiveMapInfo.data;
842
- props.emissiveMapWidth = emissiveMapInfo.width;
843
- props.emissiveMapHeight = emissiveMapInfo.height;
844
- textureStateFromSlot('emissiveMap', material.emissiveMap, 'material.emissiveMap');
845
- }
846
- const aoMapInfo = textureFromSlot(material.aoMap, 'material.aoMap');
847
- if (aoMapInfo) {
848
- props.aoMap = aoMapInfo.data;
849
- props.aoMapWidth = aoMapInfo.width;
850
- props.aoMapHeight = aoMapInfo.height;
851
- textureStateFromSlot('aoMap', material.aoMap, 'material.aoMap');
852
- props.aoMapIntensity = finiteNumberOrDefault(material.aoMapIntensity, 'material.aoMapIntensity', 1);
853
- }
854
- const lightMapInfo = textureFromSlot(material.lightMap, 'material.lightMap');
855
- if (lightMapInfo) {
856
- props.lightMap = lightMapInfo.data;
857
- props.lightMapWidth = lightMapInfo.width;
858
- props.lightMapHeight = lightMapInfo.height;
859
- textureStateFromSlot('lightMap', material.lightMap, 'material.lightMap');
860
- props.lightMapIntensity = finiteNumberOrDefault(material.lightMapIntensity, 'material.lightMapIntensity', 1);
861
- }
862
- const alphaMapInfo = textureFromSlot(material.alphaMap, 'material.alphaMap');
863
- if (alphaMapInfo) {
864
- props.alphaMap = alphaMapInfo.data;
865
- props.alphaMapWidth = alphaMapInfo.width;
866
- props.alphaMapHeight = alphaMapInfo.height;
867
- textureStateFromSlot('alphaMap', material.alphaMap, 'material.alphaMap');
868
- }
869
- Object.assign(props, materialRenderStateProperties(material, customFragmentShader, context));
870
- return props;
871
- }
872
- function assignPbrTextureSamplerState(props, prefix, map, label, context, options = {}) {
873
- const state = textureSamplerState(map, label, context, options);
874
- const target = props;
875
- target[`${prefix}WrapS`] = state.wrapS;
876
- target[`${prefix}WrapT`] = state.wrapT;
877
- target[`${prefix}MagFilter`] = state.magFilter;
878
- target[`${prefix}MinFilter`] = state.minFilter;
879
- target[`${prefix}Anisotropy`] = state.anisotropy;
880
- if (options.includeTransform !== false) {
881
- target[`${prefix}Transform`] = state.transform;
882
- }
883
- target[`${prefix}ColorSpace`] = state.colorSpace;
884
- if (options.includeUvChannel !== false) {
885
- target[`${prefix}UsesUv2`] = state.usesUv2;
886
- }
887
- }
888
- function materialScalarFeatureProperties(material, context) {
889
- const signature = context.materialScalarFeatureCache
890
- ? materialScalarFeatureSignature(material, context)
891
- : null;
892
- if (signature) {
893
- const cached = context.materialScalarFeatureCache?.get(material);
894
- if (cached && sameMaterialScalarFeatureSignature(cached.signature, signature)) {
895
- return copyMaterialScalarFeatureProperties(cached.props);
896
- }
897
- }
898
- const props = {};
899
- const usesMaterialEnvironmentMap = material.envMap != null
900
- && context.materialEnvironmentMaps?.has(material) === true;
901
- if (usesMaterialEnvironmentMap) {
902
- props.useEnvironmentMap = true;
903
- props.environmentMapIntensity = finiteNumberOrDefault(material.envMapIntensity, 'material.envMapIntensity', 1);
904
- props.environmentMapCombine = material.combine ?? MultiplyOperation;
905
- props.environmentMapReflectivity = finiteNumberOrDefault(material.reflectivity, 'material.reflectivity', 1);
906
- props.environmentMapRefraction = isRefractionEnvironmentMapping(material.envMap?.mapping);
907
- props.environmentMapRefractionRatio = finiteNumberOrDefault(material.refractionRatio, 'material.refractionRatio', 0.98);
908
- }
909
- else if (context.materialEnvironmentSource === 'material') {
910
- props.useEnvironmentMap = false;
911
- }
912
- const metalness = optionalFiniteNumber(material.metalness, 'material.metalness');
913
- if (metalness !== undefined) {
914
- props.metallic = (0, math_1.clamp01)(metalness);
915
- }
916
- const roughness = optionalFiniteNumber(material.roughness, 'material.roughness');
917
- if (roughness !== undefined) {
918
- props.roughness = (0, math_1.clamp01)(roughness);
919
- }
920
- const clearcoat = optionalFiniteNumber(material.clearcoat, 'material.clearcoat');
921
- if (clearcoat !== undefined) {
922
- props.clearcoat = (0, math_1.clamp01)(clearcoat);
923
- }
924
- const clearcoatRoughness = optionalFiniteNumber(material.clearcoatRoughness, 'material.clearcoatRoughness');
925
- if (clearcoatRoughness !== undefined) {
926
- props.clearcoatRoughness = (0, math_1.clamp01)(clearcoatRoughness);
927
- }
928
- if (material.clearcoatNormalScale != null) {
929
- if (typeof material.clearcoatNormalScale !== 'object') {
930
- throw new TypeError('material.clearcoatNormalScale must be a Vector2-like object.');
931
- }
932
- props.clearcoatNormalScale = [
933
- finiteNumberOrDefault(material.clearcoatNormalScale.x, 'material.clearcoatNormalScale.x', 1),
934
- finiteNumberOrDefault(material.clearcoatNormalScale.y, 'material.clearcoatNormalScale.y', 1),
935
- ];
936
- }
937
- const sheenRoughness = optionalFiniteNumber(material.sheenRoughness, 'material.sheenRoughness');
938
- if (sheenRoughness !== undefined) {
939
- props.sheenRoughness = (0, math_1.clamp01)(sheenRoughness);
940
- }
941
- const anisotropy = optionalFiniteNumber(material.anisotropy, 'material.anisotropy');
942
- if (anisotropy !== undefined) {
943
- props.anisotropy = (0, math_1.clamp01)(anisotropy);
944
- }
945
- const anisotropyRotation = optionalFiniteNumber(material.anisotropyRotation, 'material.anisotropyRotation');
946
- if (anisotropyRotation !== undefined) {
947
- props.anisotropyRotation = anisotropyRotation;
948
- }
949
- const iridescence = optionalFiniteNumber(material.iridescence, 'material.iridescence');
950
- if (iridescence !== undefined) {
951
- props.iridescence = (0, math_1.clamp01)(iridescence);
952
- }
953
- const iridescenceIor = optionalFiniteNumber(material.iridescenceIOR, 'material.iridescenceIOR');
954
- if (iridescenceIor !== undefined) {
955
- props.iridescenceIor = Math.max(1, Math.min(2.333, iridescenceIor));
956
- }
957
- const iridescenceThicknessRange = materialRangePair(material.iridescenceThicknessRange, 'material.iridescenceThicknessRange');
958
- if (iridescenceThicknessRange) {
959
- const [min, max] = iridescenceThicknessRange;
960
- props.iridescenceThicknessMin = Math.max(0, min);
961
- props.iridescenceThicknessMax = Math.max(props.iridescenceThicknessMin, max);
962
- }
963
- const transmission = optionalFiniteNumber(material.transmission, 'material.transmission');
964
- if (transmission !== undefined) {
965
- props.transmission = (0, math_1.clamp01)(transmission);
966
- }
967
- const dispersion = optionalFiniteNumber(material.dispersion, 'material.dispersion');
968
- if (dispersion !== undefined) {
969
- props.dispersion = Math.max(0, dispersion);
970
- }
971
- const ior = optionalFiniteNumber(material.ior, 'material.ior');
972
- if (ior !== undefined) {
973
- props.ior = Math.max(1, Math.min(2.333, ior));
974
- }
975
- const thickness = optionalFiniteNumber(material.thickness, 'material.thickness');
976
- if (thickness !== undefined) {
977
- props.thickness = Math.max(0, thickness);
978
- }
979
- const attenuationDistance = optionalFiniteNumberOrInfinityDefault(material.attenuationDistance, 'material.attenuationDistance');
980
- if (attenuationDistance !== undefined) {
981
- props.attenuationDistance = Math.max(0, attenuationDistance);
982
- }
983
- const specularIntensity = optionalFiniteNumber(material.specularIntensity, 'material.specularIntensity');
984
- if (specularIntensity !== undefined) {
985
- props.physicalSpecularIntensity = (0, math_1.clamp01)(specularIntensity);
986
- }
987
- const shininess = material.isMeshPhongMaterial
988
- ? finiteNumberOrDefault(material.shininess, 'material.shininess', 30)
989
- : optionalFiniteNumber(material.shininess, 'material.shininess');
990
- if (shininess !== undefined) {
991
- props.shininess = Math.max(0.0001, shininess);
992
- }
993
- if (material.normalScale != null) {
994
- if (typeof material.normalScale !== 'object') {
995
- throw new TypeError('material.normalScale must be a Vector2-like object.');
996
- }
997
- props.normalScale = [
998
- finiteNumberOrDefault(material.normalScale.x, 'material.normalScale.x', 1),
999
- finiteNumberOrDefault(material.normalScale.y, 'material.normalScale.y', 1),
1000
- ];
1001
- }
1002
- if (material.isMeshDepthMaterial) {
1003
- props.depthPacking = materialDepthPacking(material) ?? BasicDepthPacking;
1004
- }
1005
- if (material.isMeshDistanceMaterial) {
1006
- const hintBag = materialRendererHints(material.userData);
1007
- const hints = hintBag?.value ?? {};
1008
- const hintsLabel = hintBag?.label ?? 'material.userData.headlessThreeRenderer';
1009
- const referencePosition = firstOptionalVector3LikeToArray([
1010
- [material.referencePosition, 'material.referencePosition'],
1011
- [hints.referencePosition, `${hintsLabel}.referencePosition`],
1012
- [hints.distanceReferencePosition, `${hintsLabel}.distanceReferencePosition`],
1013
- ]);
1014
- if (referencePosition) {
1015
- props.distanceReferencePosition = referencePosition;
1016
- }
1017
- const nearDistance = firstOptionalFiniteNumber([
1018
- [material.nearDistance, 'material.nearDistance'],
1019
- [hints.nearDistance, `${hintsLabel}.nearDistance`],
1020
- [hints.distanceNear, `${hintsLabel}.distanceNear`],
1021
- ]);
1022
- if (nearDistance !== undefined) {
1023
- props.distanceNear = nearDistance;
1024
- }
1025
- const farDistance = firstOptionalFiniteNumber([
1026
- [material.farDistance, 'material.farDistance'],
1027
- [hints.farDistance, `${hintsLabel}.farDistance`],
1028
- [hints.distanceFar, `${hintsLabel}.distanceFar`],
1029
- ]);
1030
- if (farDistance !== undefined) {
1031
- props.distanceFar = farDistance;
1032
- }
1033
- }
1034
- if (signature) {
1035
- context.materialScalarFeatureCache?.set(material, {
1036
- signature,
1037
- props: copyMaterialScalarFeatureProperties(props),
1038
- });
1039
- }
1040
- return props;
1041
- }
1042
- function materialScalarFeatureSignature(material, context) {
1043
- const iridescenceThicknessRange = material.iridescenceThicknessRange;
1044
- const hintInfo = material.isMeshDistanceMaterial ? materialHintSignatureInfo(material.userData) : [];
1045
- return {
1046
- values: [
1047
- context.materialEnvironmentSource,
1048
- context.materialEnvironmentMaps?.has(material),
1049
- material.envMap,
1050
- material.envMap?.mapping,
1051
- material.envMapIntensity,
1052
- material.combine,
1053
- material.reflectivity,
1054
- material.refractionRatio,
1055
- material.metalness,
1056
- material.roughness,
1057
- material.clearcoat,
1058
- material.clearcoatRoughness,
1059
- ...vector2SignatureValues(material.clearcoatNormalScale),
1060
- material.sheenRoughness,
1061
- material.anisotropy,
1062
- material.anisotropyRotation,
1063
- material.iridescence,
1064
- material.iridescenceIOR,
1065
- iridescenceThicknessRange,
1066
- iridescenceThicknessRange?.length,
1067
- iridescenceThicknessRange?.[0],
1068
- iridescenceThicknessRange?.[1],
1069
- material.transmission,
1070
- material.dispersion,
1071
- material.ior,
1072
- material.thickness,
1073
- material.attenuationDistance,
1074
- material.specularIntensity,
1075
- material.isMeshPhongMaterial,
1076
- material.shininess,
1077
- ...vector2SignatureValues(material.normalScale),
1078
- material.isMeshDepthMaterial,
1079
- material.depthPacking,
1080
- material.isMeshDistanceMaterial,
1081
- material.referencePosition,
1082
- ...vector3SignatureValues(material.referencePosition),
1083
- material.nearDistance,
1084
- material.farDistance,
1085
- ...hintInfo,
1086
- ],
1087
- };
1088
- }
1089
- function materialHintSignatureInfo(userData) {
1090
- const values = [userData];
1091
- if (userData && typeof userData === 'object' && !Array.isArray(userData)) {
1092
- const hints = userData.headlessThreeRenderer ?? userData.headlessRenderer;
1093
- values.push(hints);
1094
- if (hints && typeof hints === 'object' && !Array.isArray(hints)) {
1095
- const hintRecord = hints;
1096
- values.push(hintRecord.referencePosition, ...vector3SignatureValues(hintRecord.referencePosition), hintRecord.distanceReferencePosition, ...vector3SignatureValues(hintRecord.distanceReferencePosition), hintRecord.nearDistance, hintRecord.distanceNear, hintRecord.farDistance, hintRecord.distanceFar);
1097
- }
1098
- }
1099
- return values;
1100
- }
1101
- function vector2SignatureValues(value) {
1102
- if (!value || typeof value !== 'object')
1103
- return [value];
1104
- const arrayLike = value;
1105
- return [
1106
- value,
1107
- arrayLike.length,
1108
- arrayLike[0],
1109
- arrayLike[1],
1110
- value.x,
1111
- value.y,
1112
- ];
1113
- }
1114
- function vector3SignatureValues(value) {
1115
- if (!value || typeof value !== 'object')
1116
- return [value];
1117
- const arrayLike = value;
1118
- return [
1119
- value,
1120
- arrayLike.length,
1121
- arrayLike[0],
1122
- arrayLike[1],
1123
- arrayLike[2],
1124
- value.x,
1125
- value.y,
1126
- value.z,
1127
- ];
1128
- }
1129
- function copyMaterialScalarFeatureProperties(props) {
1130
- return {
1131
- ...props,
1132
- clearcoatNormalScale: props.clearcoatNormalScale ? props.clearcoatNormalScale.slice() : undefined,
1133
- normalScale: props.normalScale ? props.normalScale.slice() : undefined,
1134
- distanceReferencePosition: props.distanceReferencePosition ? props.distanceReferencePosition.slice() : undefined,
1135
- };
1136
- }
1137
- function sameMaterialScalarFeatureSignature(a, b) {
1138
- return sameUnknownArray(a.values, b.values);
1139
- }
1140
- function materialRenderStateProperties(material, customFragmentShader, context) {
1141
- const signature = context.materialRenderStateCache
1142
- ? materialRenderStateSignature(material, customFragmentShader)
1143
- : null;
1144
- if (signature) {
1145
- const cached = context.materialRenderStateCache?.get(material);
1146
- if (cached && sameMaterialRenderStateSignature(cached.signature, signature)) {
1147
- return copyMaterialRenderStateProperties(cached.props);
1148
- }
1149
- }
1150
- const props = {};
1151
- const alphaTest = optionalFiniteNumber(material.alphaTest, 'material.alphaTest');
1152
- if (alphaTest !== undefined && alphaTest > 0) {
1153
- props.alphaTest = (0, math_1.clamp01)(alphaTest);
1154
- }
1155
- if (optionalBoolean(material.alphaHash, 'material.alphaHash') === true) {
1156
- props.alphaHash = true;
1157
- }
1158
- if (optionalBoolean(material.alphaToCoverage, 'material.alphaToCoverage') === true) {
1159
- props.alphaToCoverage = true;
1160
- }
1161
- if (optionalBoolean(material.premultipliedAlpha, 'material.premultipliedAlpha') === true) {
1162
- props.premultipliedAlpha = true;
1163
- }
1164
- if (optionalBoolean(material.toneMapped, 'material.toneMapped') === false) {
1165
- props.toneMapped = false;
1166
- }
1167
- optionalBoolean(material.dithering, 'material.dithering');
1168
- optionalMaterialPrecision(material.precision);
1169
- const transparent = optionalBoolean(material.transparent, 'material.transparent');
1170
- if (transparent !== undefined) {
1171
- props.transparent = transparent;
1172
- }
1173
- optionalBoolean(material.forceSinglePass, 'material.forceSinglePass');
1174
- const blending = materialBlending(material);
1175
- if (blending) {
1176
- props.blending = blending;
1177
- if (blending === 'custom') {
1178
- props.blendEquation = materialBlendEquationOrDefault(material.blendEquation, 'material.blendEquation', AddEquation);
1179
- props.blendSrc = materialBlendFactorOrDefault(material.blendSrc, 'material.blendSrc', SrcAlphaFactor);
1180
- props.blendDst = materialBlendFactorOrDefault(material.blendDst, 'material.blendDst', OneMinusSrcAlphaFactor);
1181
- if (material.blendEquationAlpha != null) {
1182
- props.blendEquationAlpha = materialBlendEquation(material.blendEquationAlpha, 'material.blendEquationAlpha');
1183
- }
1184
- if (material.blendSrcAlpha != null) {
1185
- props.blendSrcAlpha = materialBlendFactor(material.blendSrcAlpha, 'material.blendSrcAlpha');
1186
- }
1187
- if (material.blendDstAlpha != null) {
1188
- props.blendDstAlpha = materialBlendFactor(material.blendDstAlpha, 'material.blendDstAlpha');
1189
- }
1190
- const blendColor = materialSlotColor(material, 'blendColor', material.blendColor, 'material.blendColor', context);
1191
- if (blendColor) {
1192
- props.blendColor = [blendColor[0], blendColor[1], blendColor[2]];
1193
- }
1194
- const blendAlpha = optionalFiniteNumber(material.blendAlpha, 'material.blendAlpha');
1195
- if (blendAlpha !== undefined) {
1196
- props.blendAlpha = (0, math_1.clamp01)(blendAlpha);
1197
- }
1198
- }
1199
- }
1200
- const depthTest = optionalBoolean(material.depthTest, 'material.depthTest');
1201
- if (depthTest !== undefined) {
1202
- props.depthTest = depthTest;
1203
- }
1204
- const depthFunc = materialDepthFunc(material);
1205
- if (depthFunc) {
1206
- props.depthFunc = depthFunc;
1207
- }
1208
- const depthWrite = optionalBoolean(material.depthWrite, 'material.depthWrite');
1209
- if (depthWrite !== undefined) {
1210
- props.depthWrite = depthWrite;
1211
- }
1212
- const colorWrite = optionalBoolean(material.colorWrite, 'material.colorWrite');
1213
- if (colorWrite !== undefined) {
1214
- props.colorWrite = colorWrite;
1215
- }
1216
- const polygonOffset = optionalBoolean(material.polygonOffset, 'material.polygonOffset');
1217
- if (polygonOffset !== undefined) {
1218
- props.polygonOffset = polygonOffset;
1219
- const polygonOffsetFactor = optionalFiniteNumber(material.polygonOffsetFactor, 'material.polygonOffsetFactor');
1220
- if (polygonOffsetFactor !== undefined) {
1221
- props.polygonOffsetFactor = polygonOffsetFactor;
1222
- }
1223
- const polygonOffsetUnits = optionalFiniteNumber(material.polygonOffsetUnits, 'material.polygonOffsetUnits');
1224
- if (polygonOffsetUnits !== undefined) {
1225
- props.polygonOffsetUnits = polygonOffsetUnits;
1226
- }
1227
- }
1228
- const stencilWrite = optionalBoolean(material.stencilWrite, 'material.stencilWrite');
1229
- if (stencilWrite !== undefined) {
1230
- props.stencilWrite = stencilWrite;
1231
- }
1232
- const stencilWriteMask = optionalFiniteNumber(material.stencilWriteMask, 'material.stencilWriteMask');
1233
- if (stencilWriteMask !== undefined) {
1234
- props.stencilWriteMask = Math.trunc(stencilWriteMask);
1235
- }
1236
- if (material.stencilFunc != null) {
1237
- props.stencilFunc = materialStencilFunc(material.stencilFunc, 'material.stencilFunc');
1238
- }
1239
- const stencilRef = optionalFiniteNumber(material.stencilRef, 'material.stencilRef');
1240
- if (stencilRef !== undefined) {
1241
- props.stencilRef = Math.trunc(stencilRef);
1242
- }
1243
- const stencilFuncMask = optionalFiniteNumber(material.stencilFuncMask, 'material.stencilFuncMask');
1244
- if (stencilFuncMask !== undefined) {
1245
- props.stencilFuncMask = Math.trunc(stencilFuncMask);
1246
- }
1247
- if (material.stencilFail != null) {
1248
- props.stencilFail = materialStencilOperation(material.stencilFail, 'material.stencilFail');
1249
- }
1250
- if (material.stencilZFail != null) {
1251
- props.stencilZFail = materialStencilOperation(material.stencilZFail, 'material.stencilZFail');
1252
- }
1253
- if (material.stencilZPass != null) {
1254
- props.stencilZPass = materialStencilOperation(material.stencilZPass, 'material.stencilZPass');
1255
- }
1256
- const side = materialSide(material);
1257
- if (side) {
1258
- props.side = side;
1259
- }
1260
- const shadowSide = materialShadowSide(material);
1261
- if (shadowSide) {
1262
- props.shadowSide = shadowSide;
1263
- }
1264
- if (optionalBoolean(material.flatShading, 'material.flatShading') === true) {
1265
- props.flatShading = true;
1266
- }
1267
- if (optionalBoolean(material.fog, 'material.fog') === false) {
1268
- props.fog = false;
1269
- }
1270
- if (customFragmentShader && shaderMaterialKind(material)) {
1271
- props.shadingModel = 'basic';
1272
- }
1273
- else if (copyShaderMaterialInfo(material)) {
1274
- props.shadingModel = 'basic';
1275
- }
1276
- else if (material.isMeshBasicMaterial || material.isSpriteMaterial) {
1277
- props.shadingModel = 'basic';
1278
- }
1279
- else if (material.isMeshDepthMaterial) {
1280
- props.shadingModel = 'depth';
1281
- }
1282
- else if (material.isMeshDistanceMaterial) {
1283
- props.shadingModel = 'distance';
1284
- }
1285
- else if (material.isMeshLambertMaterial) {
1286
- props.shadingModel = 'lambert';
1287
- }
1288
- else if (material.isMeshNormalMaterial) {
1289
- props.shadingModel = 'normal';
1290
- }
1291
- else if (material.isMeshMatcapMaterial) {
1292
- props.shadingModel = 'matcap';
1293
- }
1294
- else if (material.isMeshPhongMaterial) {
1295
- props.shadingModel = 'phong';
1296
- }
1297
- else if (material.isMeshToonMaterial) {
1298
- props.shadingModel = 'toon';
1299
- }
1300
- else if (material.isShadowMaterial) {
1301
- props.shadingModel = 'shadow';
1302
- }
1303
- if (customFragmentShader) {
1304
- props.customFragmentShader = customFragmentShader;
1305
- }
1306
- if (signature) {
1307
- context.materialRenderStateCache?.set(material, {
1308
- signature,
1309
- props: copyMaterialRenderStateProperties(props),
1310
- });
1311
- }
1312
- return props;
1313
- }
1314
- function materialRenderStateSignature(material, customFragmentShader) {
1315
- return {
1316
- values: [
1317
- customFragmentShader,
1318
- material.alphaTest,
1319
- material.alphaHash,
1320
- material.alphaToCoverage,
1321
- material.premultipliedAlpha,
1322
- material.toneMapped,
1323
- material.dithering,
1324
- material.precision,
1325
- material.transparent,
1326
- material.forceSinglePass,
1327
- material.blending,
1328
- material.blendEquation,
1329
- material.blendSrc,
1330
- material.blendDst,
1331
- material.blendEquationAlpha,
1332
- material.blendSrcAlpha,
1333
- material.blendDstAlpha,
1334
- material.blendAlpha,
1335
- material.depthTest,
1336
- material.depthFunc,
1337
- material.depthWrite,
1338
- material.colorWrite,
1339
- material.polygonOffset,
1340
- material.polygonOffsetFactor,
1341
- material.polygonOffsetUnits,
1342
- material.stencilWrite,
1343
- material.stencilWriteMask,
1344
- material.stencilFunc,
1345
- material.stencilRef,
1346
- material.stencilFuncMask,
1347
- material.stencilFail,
1348
- material.stencilZFail,
1349
- material.stencilZPass,
1350
- material.side,
1351
- material.shadowSide,
1352
- material.flatShading,
1353
- material.fog,
1354
- material.type,
1355
- copyShaderMaterialInfo(material) != null,
1356
- material.isRawShaderMaterial,
1357
- material.isNodeMaterial,
1358
- material.isShaderMaterial,
1359
- material.isMeshBasicMaterial,
1360
- material.isSpriteMaterial,
1361
- material.isMeshDepthMaterial,
1362
- material.isMeshDistanceMaterial,
1363
- material.isMeshLambertMaterial,
1364
- material.isMeshNormalMaterial,
1365
- material.isMeshMatcapMaterial,
1366
- material.isMeshPhongMaterial,
1367
- material.isMeshToonMaterial,
1368
- material.isShadowMaterial,
1369
- ],
1370
- blendColor: materialSlotColorSignature(material.blendColor),
1371
- };
1372
- }
1373
- function copyMaterialRenderStateProperties(props) {
1374
- return {
1375
- ...props,
1376
- blendColor: props.blendColor ? props.blendColor.slice() : undefined,
1377
- };
1378
- }
1379
- function sameMaterialRenderStateSignature(a, b) {
1380
- return sameUnknownArray(a.values, b.values)
1381
- && sameMaterialColorSignature(a.blendColor, b.blendColor);
1382
- }
1383
- function materialBlending(material) {
1384
- switch (material.blending) {
1385
- case NoBlending:
1386
- return 'none';
1387
- case NormalBlending:
1388
- return 'normal';
1389
- case AdditiveBlending:
1390
- return 'additive';
1391
- case SubtractiveBlending:
1392
- return 'subtractive';
1393
- case MultiplyBlending:
1394
- return 'multiply';
1395
- case CustomBlending:
1396
- return 'custom';
1397
- default:
1398
- if (material.blending != null) {
1399
- throw new Error(`material.blending ${String(material.blending)} is not supported by @headless-three/renderer. Use a Three.js blending constant such as NormalBlending, AdditiveBlending, or CustomBlending.`);
1400
- }
1401
- return undefined;
1402
- }
1403
- }
1404
- function materialBlendEquationOrDefault(value, label, fallback) {
1405
- if (value == null)
1406
- return fallback;
1407
- return materialBlendEquation(value, label);
1408
- }
1409
- function materialBlendEquation(value, label) {
1410
- if (value === AddEquation ||
1411
- value === SubtractEquation ||
1412
- value === ReverseSubtractEquation ||
1413
- value === MinEquation ||
1414
- value === MaxEquation) {
1415
- return value;
1416
- }
1417
- throw new Error(`${label} ${String(value)} is not supported by @headless-three/renderer. Use a Three.js blend equation constant such as AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, or MaxEquation.`);
1418
- }
1419
- function materialBlendFactorOrDefault(value, label, fallback) {
1420
- if (value == null)
1421
- return fallback;
1422
- return materialBlendFactor(value, label);
1423
- }
1424
- function materialBlendFactor(value, label) {
1425
- if (value === ZeroFactor ||
1426
- value === OneFactor ||
1427
- value === SrcColorFactor ||
1428
- value === OneMinusSrcColorFactor ||
1429
- value === SrcAlphaFactor ||
1430
- value === OneMinusSrcAlphaFactor ||
1431
- value === DstAlphaFactor ||
1432
- value === OneMinusDstAlphaFactor ||
1433
- value === DstColorFactor ||
1434
- value === OneMinusDstColorFactor ||
1435
- value === SrcAlphaSaturateFactor ||
1436
- value === ConstantColorFactor ||
1437
- value === OneMinusConstantColorFactor ||
1438
- value === ConstantAlphaFactor ||
1439
- value === OneMinusConstantAlphaFactor) {
1440
- return value;
1441
- }
1442
- throw new Error(`${label} ${String(value)} is not supported by @headless-three/renderer. Use a Three.js blend factor constant such as SrcAlphaFactor, OneMinusSrcAlphaFactor, OneFactor, or ZeroFactor.`);
1443
- }
1444
- function materialDepthFunc(material) {
1445
- if (material.depthFunc == null)
1446
- return undefined;
1447
- switch (material.depthFunc) {
1448
- case NeverDepth:
1449
- return 'never';
1450
- case AlwaysDepth:
1451
- return 'always';
1452
- case LessDepth:
1453
- return 'less';
1454
- case LessEqualDepth:
1455
- return 'less-equal';
1456
- case EqualDepth:
1457
- return 'equal';
1458
- case GreaterEqualDepth:
1459
- return 'greater-equal';
1460
- case GreaterDepth:
1461
- return 'greater';
1462
- case NotEqualDepth:
1463
- return 'not-equal';
1464
- default:
1465
- throw new Error(`material.depthFunc ${String(material.depthFunc)} is not supported by @headless-three/renderer. Use a Three.js depth comparison constant such as LessEqualDepth, GreaterDepth, or AlwaysDepth.`);
1466
- }
1467
- }
1468
- function materialStencilFunc(value, label) {
1469
- if (value === NeverStencilFunc ||
1470
- value === LessStencilFunc ||
1471
- value === EqualStencilFunc ||
1472
- value === LessEqualStencilFunc ||
1473
- value === GreaterStencilFunc ||
1474
- value === NotEqualStencilFunc ||
1475
- value === GreaterEqualStencilFunc ||
1476
- value === AlwaysStencilFunc) {
1477
- return value;
1478
- }
1479
- throw new Error(`${label} ${String(value)} is not supported by @headless-three/renderer. Use a Three.js stencil function constant such as AlwaysStencilFunc, EqualStencilFunc, or NotEqualStencilFunc.`);
1480
- }
1481
- function materialStencilOperation(value, label) {
1482
- if (value === ZeroStencilOp ||
1483
- value === KeepStencilOp ||
1484
- value === ReplaceStencilOp ||
1485
- value === IncrementStencilOp ||
1486
- value === DecrementStencilOp ||
1487
- value === IncrementWrapStencilOp ||
1488
- value === DecrementWrapStencilOp ||
1489
- value === InvertStencilOp) {
1490
- return value;
1491
- }
1492
- throw new Error(`${label} ${String(value)} is not supported by @headless-three/renderer. Use a Three.js stencil operation constant such as KeepStencilOp, ReplaceStencilOp, or InvertStencilOp.`);
1493
- }
1494
- function materialSide(material) {
1495
- if (material.side == null)
1496
- return undefined;
1497
- switch (material.side) {
1498
- case FrontSide:
1499
- return 'front';
1500
- case BackSide:
1501
- return 'back';
1502
- case DoubleSide:
1503
- return 'double';
1504
- default:
1505
- throw new Error(`material.side ${String(material.side)} is not supported by @headless-three/renderer. Use FrontSide, BackSide, or DoubleSide.`);
1506
- }
1507
- }
1508
- function materialDepthPacking(material) {
1509
- if (material.depthPacking == null)
1510
- return undefined;
1511
- switch (material.depthPacking) {
1512
- case BasicDepthPacking:
1513
- case RGBADepthPacking:
1514
- case RGBDepthPacking:
1515
- case RGDepthPacking:
1516
- return material.depthPacking;
1517
- default:
1518
- throw new Error(`material.depthPacking ${String(material.depthPacking)} is not supported by @headless-three/renderer. Use BasicDepthPacking, RGBADepthPacking, RGBDepthPacking, or RGDepthPacking.`);
1519
- }
1520
- }
1521
- function materialNormalMapType(material) {
1522
- if (material.normalMapType == null)
1523
- return 'tangent';
1524
- switch (material.normalMapType) {
1525
- case TangentSpaceNormalMap:
1526
- return 'tangent';
1527
- case ObjectSpaceNormalMap:
1528
- return 'object';
1529
- default:
1530
- throw new Error(`material.normalMapType ${String(material.normalMapType)} is not supported by @headless-three/renderer. Use TangentSpaceNormalMap or ObjectSpaceNormalMap.`);
1531
- }
1532
- }
1533
- function materialShadowSide(material) {
1534
- if (!material || material.shadowSide == null)
1535
- return undefined;
1536
- switch (material.shadowSide) {
1537
- case FrontSide:
1538
- return 'front';
1539
- case BackSide:
1540
- return 'back';
1541
- case DoubleSide:
1542
- return 'double';
1543
- default:
1544
- throw new Error(`material.shadowSide ${String(material.shadowSide)} is not supported by @headless-three/renderer. Use FrontSide, BackSide, DoubleSide, null, or undefined.`);
1545
- }
1546
- }
1547
- function finiteIntegerOrDefault(value, fallback) {
1548
- return typeof value === 'number' && Number.isFinite(value) ? Math.trunc(value) : fallback;
1549
- }
1550
- function textureUvChannel(texture) {
1551
- if (texture?.channel == null)
1552
- return 0;
1553
- if (!Number.isInteger(texture.channel)) {
1554
- throw new TypeError('texture.channel must be an integer.');
1555
- }
1556
- const channel = texture.channel;
1557
- if (channel >= 0 && channel <= 3)
1558
- return channel;
1559
- throw new Error(`texture.channel ${channel} is not supported by @headless-three/renderer yet. Use channel 0, 1, 2, or 3 for Three.js UV attributes.`);
1560
- }
1561
- function firstOptionalFiniteNumber(entries) {
1562
- for (const [value, label] of entries) {
1563
- if (value != null)
1564
- return optionalFiniteNumber(value, label);
1565
- }
1566
- return undefined;
1567
- }
1568
- function firstOptionalVector3LikeToArray(entries) {
1569
- for (const [value, label] of entries) {
1570
- if (value != null)
1571
- return requiredFiniteVector3LikeToArray(value, label);
1572
- }
1573
- return undefined;
1574
- }
1575
- function optionalFiniteNumber(value, label) {
1576
- if (value == null)
1577
- return undefined;
1578
- if (typeof value === 'number' && Number.isFinite(value))
1579
- return value;
1580
- throw new TypeError(`${label} must be a finite number.`);
1581
- }
1582
- function optionalBoolean(value, label) {
1583
- if (value == null)
1584
- return undefined;
1585
- if (typeof value === 'boolean')
1586
- return value;
1587
- throw new TypeError(`${label} must be a boolean.`);
1588
- }
1589
- function optionalPositiveFiniteNumber(value, label) {
1590
- if (value == null)
1591
- return;
1592
- if (typeof value !== 'number' || !Number.isFinite(value)) {
1593
- throw new TypeError(`${label} must be a finite number.`);
1594
- }
1595
- if (value <= 0) {
1596
- throw new TypeError(`${label} must be positive.`);
1597
- }
1598
- }
1599
- function optionalWireframeLinecap(value) {
1600
- if (value == null)
1601
- return;
1602
- if (typeof value !== 'string') {
1603
- throw new TypeError('material.wireframeLinecap must be a string.');
1604
- }
1605
- if (value !== 'butt' && value !== 'round' && value !== 'square') {
1606
- throw new Error(`material.wireframeLinecap ${JSON.stringify(value)} is not supported by @headless-three/renderer. Use "butt", "round", "square", null, or undefined.`);
1607
- }
1608
- }
1609
- function optionalWireframeLinejoin(value) {
1610
- if (value == null)
1611
- return;
1612
- if (typeof value !== 'string') {
1613
- throw new TypeError('material.wireframeLinejoin must be a string.');
1614
- }
1615
- if (value !== 'round' && value !== 'bevel' && value !== 'miter') {
1616
- throw new Error(`material.wireframeLinejoin ${JSON.stringify(value)} is not supported by @headless-three/renderer. Use "round", "bevel", "miter", null, or undefined.`);
1617
- }
1618
- }
1619
- function optionalMaterialPrecision(value) {
1620
- if (value == null)
1621
- return;
1622
- if (typeof value !== 'string') {
1623
- throw new TypeError('material.precision must be "highp", "mediump", "lowp", null, or undefined.');
1624
- }
1625
- if (value !== 'highp' && value !== 'mediump' && value !== 'lowp') {
1626
- throw new Error(`material.precision ${JSON.stringify(value)} is not supported by @headless-three/renderer. Use "highp", "mediump", "lowp", null, or undefined.`);
1627
- }
1628
- }
1629
- function optionalFiniteNumberOrInfinityDefault(value, label) {
1630
- if (value === Number.POSITIVE_INFINITY)
1631
- return undefined;
1632
- return optionalFiniteNumber(value, label);
1633
- }
1634
- function requiredFiniteNumber(value, label) {
1635
- if (typeof value === 'number' && Number.isFinite(value))
1636
- return value;
1637
- throw new TypeError(`${label} must be a finite number.`);
1638
- }
1639
- function materialRangePair(value, label) {
1640
- if (value == null)
1641
- return undefined;
1642
- if (typeof value !== 'object') {
1643
- throw new TypeError(`${label} must be an array-like pair.`);
1644
- }
1645
- const range = value;
1646
- if (typeof range.length !== 'number' || range.length < 2) {
1647
- throw new TypeError(`${label} must contain at least two values.`);
1648
- }
1649
- return [
1650
- requiredFiniteNumber(range[0], `${label}[0]`),
1651
- requiredFiniteNumber(range[1], `${label}[1]`),
1652
- ];
1653
- }
1654
- function finiteNumberOrDefault(value, label, fallback) {
1655
- return optionalFiniteNumber(value, label) ?? fallback;
1656
- }
1657
- function vector3LikeToArray(value) {
1658
- if (!value || typeof value !== 'object')
1659
- return undefined;
1660
- const arrayLike = value;
1661
- if (typeof arrayLike.length === 'number' && arrayLike.length >= 3) {
1662
- const x = arrayLike[0];
1663
- const y = arrayLike[1];
1664
- const z = arrayLike[2];
1665
- if (typeof x === 'number' && typeof y === 'number' && typeof z === 'number'
1666
- && Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(z)) {
1667
- return [x, y, z];
1668
- }
1669
- }
1670
- const vector = value;
1671
- const { x, y, z } = vector;
1672
- if (typeof x === 'number' && typeof y === 'number' && typeof z === 'number'
1673
- && Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(z)) {
1674
- return [x, y, z];
1675
- }
1676
- return undefined;
1677
- }
1678
- function requiredFiniteVector3LikeToArray(value, label) {
1679
- if (!value || typeof value !== 'object') {
1680
- throw new TypeError(`${label} must be a finite Vector3-like value.`);
1681
- }
1682
- const arrayLike = value;
1683
- if (typeof arrayLike.length === 'number' && arrayLike.length >= 3) {
1684
- return [
1685
- requiredFiniteNumber(arrayLike[0], `${label}[0]`),
1686
- requiredFiniteNumber(arrayLike[1], `${label}[1]`),
1687
- requiredFiniteNumber(arrayLike[2], `${label}[2]`),
1688
- ];
1689
- }
1690
- const vector = value;
1691
- if ('x' in vector || 'y' in vector || 'z' in vector) {
1692
- return [
1693
- requiredFiniteNumber(vector.x, `${label}.x`),
1694
- requiredFiniteNumber(vector.y, `${label}.y`),
1695
- requiredFiniteNumber(vector.z, `${label}.z`),
1696
- ];
1697
- }
1698
- throw new TypeError(`${label} must be a finite Vector3-like value.`);
1699
- }
1700
- function materialEnvMapRotation(material) {
1701
- const value = material.envMapRotation;
1702
- if (value == null)
1703
- return undefined;
1704
- const components = requiredVector3LikeToArray(value, 'material.envMapRotation');
1705
- return components.some((component) => Math.abs(component) > 1e-12)
1706
- ? value
1707
- : undefined;
1708
- }
1709
- function requiredVector3LikeToArray(value, label) {
1710
- if (!value || typeof value !== 'object') {
1711
- throw new TypeError(`${label} must be a finite Vector3-like value.`);
1712
- }
1713
- const arrayLike = value;
1714
- if (typeof arrayLike.length === 'number' && arrayLike.length >= 3) {
1715
- validateEulerLikeOrder(arrayLike[3], `${label}[3]`);
1716
- return [
1717
- requiredFiniteNumber(arrayLike[0], `${label}[0]`),
1718
- requiredFiniteNumber(arrayLike[1], `${label}[1]`),
1719
- requiredFiniteNumber(arrayLike[2], `${label}[2]`),
1720
- ];
1721
- }
1722
- const vector = value;
1723
- if ('x' in vector || 'y' in vector || 'z' in vector) {
1724
- validateEulerLikeOrder(vector.order, `${label}.order`);
1725
- return [
1726
- requiredFiniteNumber(vector.x, `${label}.x`),
1727
- requiredFiniteNumber(vector.y, `${label}.y`),
1728
- requiredFiniteNumber(vector.z, `${label}.z`),
1729
- ];
1730
- }
1731
- throw new TypeError(`${label} must be a finite Vector3-like value.`);
1732
- }
1733
- function validateEulerLikeOrder(value, label) {
1734
- if (value == null)
1735
- return;
1736
- if (value === 'XYZ' ||
1737
- value === 'YXZ' ||
1738
- value === 'ZXY' ||
1739
- value === 'ZYX' ||
1740
- value === 'YZX' ||
1741
- value === 'XZY') {
1742
- return;
1743
- }
1744
- throw new TypeError(`${label} must be one of XYZ, YXZ, ZXY, ZYX, YZX, or XZY.`);
1745
- }
1746
- function sameVector3Like(left, right) {
1747
- const leftComponents = vector3LikeToArray(left);
1748
- const rightComponents = vector3LikeToArray(right);
1749
- if (!leftComponents || !rightComponents)
1750
- return false;
1751
- return leftComponents.every((component, index) => Math.abs(component - rightComponents[index]) <= 1e-12)
1752
- && eulerLikeOrder(left) === eulerLikeOrder(right);
1753
- }
1754
- function eulerLikeOrder(value) {
1755
- if (!value || typeof value !== 'object')
1756
- return 'XYZ';
1757
- const arrayLike = value;
1758
- if (typeof arrayLike.length === 'number' && arrayLike.length >= 4 && typeof arrayLike[3] === 'string') {
1759
- return arrayLike[3];
1760
- }
1761
- const order = value.order;
1762
- return typeof order === 'string' ? order : 'XYZ';
1763
- }
1764
- function extractCustomFragmentShader(material) {
1765
- if (!material)
1766
- return undefined;
1767
- const candidates = [
1768
- [material.customFragmentWgsl, 'material.customFragmentWgsl'],
1769
- [material.customFragmentShader, 'material.customFragmentShader'],
1770
- [material.headlessFragmentWgsl, 'material.headlessFragmentWgsl'],
1771
- [material.headlessFragmentShader, 'material.headlessFragmentShader'],
1772
- ];
1773
- const hints = customFragmentHints(material.userData);
1774
- if (hints) {
1775
- candidates.push([hints.value.fragmentWgsl, `${hints.label}.fragmentWgsl`], [hints.value.fragmentShader, `${hints.label}.fragmentShader`], [hints.value.customFragmentWgsl, `${hints.label}.customFragmentWgsl`], [hints.value.customFragmentShader, `${hints.label}.customFragmentShader`]);
1776
- }
1777
- for (const [value, label] of candidates) {
1778
- const candidate = customFragmentCandidate(value, label);
1779
- if (candidate)
1780
- return candidate;
1781
- }
1782
- return undefined;
1783
- }
1784
- function materialRendererHints(userData) {
1785
- if (userData == null)
1786
- return undefined;
1787
- if (typeof userData !== 'object' || Array.isArray(userData)) {
1788
- throw new TypeError('material.userData must be an object.');
1789
- }
1790
- const value = userData.headlessThreeRenderer ?? userData.headlessRenderer;
1791
- if (value == null)
1792
- return undefined;
1793
- const label = userData.headlessThreeRenderer != null
1794
- ? 'material.userData.headlessThreeRenderer'
1795
- : 'material.userData.headlessRenderer';
1796
- if (typeof value !== 'object' || Array.isArray(value)) {
1797
- throw new TypeError(`${label} must be an object.`);
1798
- }
1799
- return { value: value, label };
1800
- }
1801
- function customFragmentHints(userData) {
1802
- return materialRendererHints(userData);
1803
- }
1804
- function customFragmentCandidate(value, label) {
1805
- if (value == null)
1806
- return undefined;
1807
- if (typeof value !== 'string') {
1808
- throw new TypeError(`${label} must be a string.`);
1809
- }
1810
- const candidate = value.trim();
1811
- return candidate.length > 0 ? candidate : undefined;
1812
- }
1813
- function assertSupportedShaderMaterial(material, customFragmentShader) {
1814
- const kind = shaderMaterialKind(material);
1815
- if (!kind || customFragmentShader || copyShaderMaterialInfo(material))
1816
- return;
1817
- if (isThreePmremShaderMaterial(material)) {
1818
- throw new Error(`${material.name} is a Three.js PMREMGenerator internal ShaderMaterial and is not translated by @headless-three/renderer yet. Use readable scene.environment, scene.background, material.envMap, or reflection-probe textures directly so the renderer can run its native CPU IBL precompute path, or precompute PMREM/CubeUV assets before rendering.`);
1819
- }
1820
- if (isThreeAnaglyphEffectShaderMaterial(material)) {
1821
- throw new Error('THREE.AnaglyphEffect internal ShaderMaterial is not translated by @headless-three/renderer yet. Use StereoEffect or PeppersGhostEffect for covered stereo helper renders, or render the left and right eye targets separately and compose the anaglyph image outside this helper.');
1822
- }
1823
- if (isThreeParallaxBarrierEffectShaderMaterial(material)) {
1824
- throw new Error('THREE.ParallaxBarrierEffect internal ShaderMaterial is not translated by @headless-three/renderer yet. Use StereoEffect or PeppersGhostEffect for covered stereo helper renders, or render the left and right eye targets separately and compose the parallax-barrier image outside this helper.');
1825
- }
1826
- if (isThreeAfterimagePassShaderMaterial(material)) {
1827
- throw new Error('THREE.AfterimagePass internal ShaderMaterial is not translated by @headless-three/renderer yet. Use the covered CopyShader/OutputPass fullscreen helpers for simple copies, provide a custom WGSL fragment for an equivalent pass, or compose the afterimage effect outside this helper.');
1828
- }
1829
- if (isThreeBloomPassConvolutionShaderMaterial(material)) {
1830
- throw new Error("THREE.BloomPass internal convolution ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent blur/composite pass, or compose bloom outside this helper.");
1831
- }
1832
- if (isThreeFilmPassShaderMaterial(material)) {
1833
- throw new Error("THREE.FilmPass internal FilmShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent film/noise pass, or compose the film effect outside this helper.");
1834
- }
1835
- if (isThreeDotScreenPassShaderMaterial(material)) {
1836
- throw new Error("THREE.DotScreenPass internal DotScreenShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent dot-screen pass, or compose the dot-screen effect outside this helper.");
1837
- }
1838
- if (isThreeGlitchPassShaderMaterial(material)) {
1839
- throw new Error("THREE.GlitchPass internal DigitalGlitch ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent glitch pass, or compose the glitch effect outside this helper.");
1840
- }
1841
- if (isThreeHalftonePassShaderMaterial(material)) {
1842
- throw new Error("THREE.HalftonePass internal HalftoneShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent halftone pass, or compose the halftone effect outside this helper.");
1843
- }
1844
- if (isThreeLutPassShaderMaterial(material)) {
1845
- throw new Error("THREE.LUTPass internal LUTShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported color adjustments, bake color grading into input textures, provide a custom WGSL fragment for an equivalent LUT pass, or compose LUT color grading outside this helper.");
1846
- }
1847
- if (isThreeBokehPassShaderMaterial(material)) {
1848
- throw new Error("THREE.BokehPass internal BokehShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent depth-of-field pass, or compose the bokeh effect outside this helper.");
1849
- }
1850
- if (isThreeRenderPixelatedPassShaderMaterial(material)) {
1851
- throw new Error("THREE.RenderPixelatedPass internal pixelation ShaderMaterial is not translated by @headless-three/renderer yet. Use options.renderMode for supported depth/normal auxiliary outputs, provide a custom WGSL fragment for an equivalent pixelated composite pass, or compose the pixelated effect outside this helper.");
1852
- }
1853
- if (isThreeRenderTransitionPassShaderMaterial(material)) {
1854
- throw new Error("THREE.RenderTransitionPass internal transition ShaderMaterial is not translated by @headless-three/renderer yet. Render the two scenes separately and blend them outside this helper, or provide a custom WGSL fragment for an equivalent transition pass.");
1855
- }
1856
- if (isThreeCubeTexturePassShaderMaterial(material)) {
1857
- throw new Error("THREE.CubeTexturePass internal cube ShaderMaterial is not translated by @headless-three/renderer yet. Use scene.background, options.background, or a supported cube background texture directly, or provide a custom WGSL fragment for an equivalent cube-texture pass.");
1858
- }
1859
- if (isThreeSaoPassShaderMaterial(material)) {
1860
- throw new Error("THREE.SAOPass internal SAOShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent ambient-occlusion pass, or compose the SAO effect outside this helper.");
1861
- }
1862
- if (isThreeSsaoPassShaderMaterial(material)) {
1863
- throw new Error("THREE.SSAOPass internal SSAOShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent screen-space ambient-occlusion pass, or compose the SSAO effect outside this helper.");
1864
- }
1865
- if (isThreeGtaoPassShaderMaterial(material)) {
1866
- throw new Error("THREE.GTAOPass internal GTAOShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent ground-truth ambient-occlusion pass, or compose the GTAO effect outside this helper.");
1867
- }
1868
- if (isThreeUnrealBloomPassHighPassShaderMaterial(material)) {
1869
- throw new Error("THREE.UnrealBloomPass internal LuminosityHighPassShader ShaderMaterial is not translated by @headless-three/renderer yet. Use the renderer's postProcessing controls for supported image effects, provide a custom WGSL fragment for an equivalent bloom pass, or compose UnrealBloom outside this helper.");
1870
- }
1871
- if (isThreeSsrPassShaderMaterial(material)) {
1872
- throw new Error("THREE.SSRPass internal SSRShader ShaderMaterial is not translated by @headless-three/renderer yet. Render reflections through supported scene/environment/material inputs, provide a custom WGSL fragment for an equivalent screen-space reflection pass, or compose SSR outside this helper.");
1873
- }
1874
- if (isThreeSmaaPassEdgesShaderMaterial(material)) {
1875
- throw new Error("THREE.SMAAPass internal SMAAEdgesShader ShaderMaterial is not translated by @headless-three/renderer yet. Use native MSAA through render options or targets when applicable, provide a custom WGSL fragment for an equivalent antialiasing pass, or compose SMAA outside this helper.");
1876
- }
1877
- if (isThreeOutlinePassPrepareMaskShaderMaterial(material)) {
1878
- throw new Error("THREE.OutlinePass internal prepare-mask ShaderMaterial is not translated by @headless-three/renderer yet. Use options.renderMode mask/object-id outputs for supported object isolation, provide a custom WGSL fragment for an equivalent outline pass, or compose outlines outside this helper.");
1879
- }
1880
- if (isThreeOutlineEffectShaderMaterial(material)) {
1881
- throw new Error("THREE.OutlineEffect internal outline ShaderMaterial is not translated by @headless-three/renderer yet. Use options.renderMode mask/object-id outputs for supported object isolation, provide a custom WGSL fragment for an equivalent outline material, or compose outlines outside this helper.");
1882
- }
1883
- if (isThreeSkyShaderMaterial(material)) {
1884
- throw new Error("THREE.Sky internal SkyShader ShaderMaterial is not translated by @headless-three/renderer yet. Use supported scene.background/environment textures or colors, pre-render a sky texture before rendering, or provide a custom WGSL fragment for an equivalent sky material.");
1885
- }
1886
- if (isThreeWaterMirrorShaderMaterial(material)) {
1887
- throw new Error("THREE.Water internal MirrorShader ShaderMaterial is not translated by @headless-three/renderer yet. Use supported scene/environment/material inputs, render reflection targets separately, provide a custom WGSL fragment for an equivalent water material, or compose water outside this helper.");
1888
- }
1889
- if (isThreeWater2ShaderMaterial(material)) {
1890
- throw new Error("THREE.Water2 internal WaterShader ShaderMaterial is not translated by @headless-three/renderer yet. Use supported scene/environment/material inputs, render reflection/refraction targets separately, provide a custom WGSL fragment for an equivalent flow-water material, or compose water outside this helper.");
1891
- }
1892
- if (isThreeReflectorForSsrPassShaderMaterial(material)) {
1893
- throw new Error("THREE.ReflectorForSSRPass internal ReflectorShader ShaderMaterial is not translated by @headless-three/renderer yet. Use supported scene/environment/material inputs, render reflector targets separately, provide a custom WGSL fragment for an equivalent SSR reflector material, or compose SSR reflections outside this helper.");
1894
- }
1895
- if (isThreeReflectorShaderMaterial(material)) {
1896
- throw new Error("THREE.Reflector internal ReflectorShader ShaderMaterial is not translated by @headless-three/renderer yet. The helper-owned target prepass is covered, but the final projective reflection material still needs a custom WGSL fragment or an external composition step.");
1897
- }
1898
- if (isThreeRefractorShaderMaterial(material)) {
1899
- throw new Error("THREE.Refractor internal RefractorShader ShaderMaterial is not translated by @headless-three/renderer yet. The helper-owned target prepass is covered, but the final projective refraction material still needs a custom WGSL fragment or an external composition step.");
1900
- }
1901
- if (isThreeShadowMapViewerShaderMaterial(material)) {
1902
- throw new Error("THREE.ShadowMapViewer internal UnpackDepthRGBAShader ShaderMaterial is not translated by @headless-three/renderer yet. Use supported shadow/depth render-target readback paths, provide a custom WGSL fragment for an equivalent depth visualization, or compose the shadow-map preview outside this helper.");
1903
- }
1904
- if (isThreeLightProbeHelperShaderMaterial(material)) {
1905
- throw new Error('THREE.LightProbeHelper internal LightProbeHelperMaterial ShaderMaterial is not translated by @headless-three/renderer yet. Native THREE.LightProbe lighting and LightProbeGenerator cube-target readback are supported directly; use a built-in material, provide a custom WGSL fragment for an equivalent probe visualization, or inspect spherical-harmonics coefficients outside this helper.');
1906
- }
1907
- if (isThreeTextureHelperShaderMaterial(material)) {
1908
- throw new Error('THREE.TextureHelper internal TextureHelperMaterial ShaderMaterial is not translated by @headless-three/renderer yet. Use supported material, background, scene.environment, or render-target texture inputs directly, read or copy renderer-owned target pixels, or provide a custom WGSL fragment for an equivalent texture visualizer.');
1909
- }
1910
- if (isThreeLineMaterialShaderMaterial(material)) {
1911
- throw new Error('THREE.LineMaterial ShaderMaterial used by Line2, LineSegments2, and Wireframe is not translated by @headless-three/renderer yet. Use THREE.Line, THREE.LineSegments, or THREE.LineLoop with LineBasicMaterial or LineDashedMaterial for covered CPU-expanded line rendering, or provide a custom WGSL fragment for an equivalent line material.');
1912
- }
1913
- const label = namedShaderMaterialLabel(kind, material);
1914
- throw new Error(`${label} is not supported directly by @headless-three/renderer. Use a built-in Three.js material, or provide material.userData.headlessThreeRenderer.fragmentWgsl with a WGSL fragment body for the renderer's custom material path.`);
1915
- }
1916
- function isThreePmremShaderMaterial(material) {
1917
- return material.name === 'EquirectangularToCubeUV' ||
1918
- material.name === 'CubemapToCubeUV' ||
1919
- material.name === 'SphericalGaussianBlur';
1920
- }
1921
- function isThreeAnaglyphEffectShaderMaterial(material) {
1922
- const uniforms = material.uniforms;
1923
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
1924
- return false;
1925
- const values = uniforms;
1926
- if (values.mapLeft == null ||
1927
- values.mapRight == null ||
1928
- values.colorMatrixLeft == null ||
1929
- values.colorMatrixRight == null) {
1930
- return false;
1931
- }
1932
- if (typeof material.fragmentShader !== 'string')
1933
- return false;
1934
- const compact = material.fragmentShader.replace(/\s+/g, '');
1935
- return compact.includes('uniformsampler2DmapLeft;') &&
1936
- compact.includes('uniformsampler2DmapRight;') &&
1937
- compact.includes('uniformmat3colorMatrixLeft;') &&
1938
- compact.includes('uniformmat3colorMatrixRight;') &&
1939
- compact.includes('colorMatrixLeft*colorL.rgb+') &&
1940
- compact.includes('colorMatrixRight*colorR.rgb');
1941
- }
1942
- function isThreeParallaxBarrierEffectShaderMaterial(material) {
1943
- const uniforms = material.uniforms;
1944
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
1945
- return false;
1946
- const values = uniforms;
1947
- if (values.mapLeft == null || values.mapRight == null)
1948
- return false;
1949
- if (typeof material.fragmentShader !== 'string')
1950
- return false;
1951
- const compact = material.fragmentShader.replace(/\s+/g, '');
1952
- return compact.includes('uniformsampler2DmapLeft;') &&
1953
- compact.includes('uniformsampler2DmapRight;') &&
1954
- compact.includes('mod(gl_FragCoord.y,2.0)') &&
1955
- compact.includes('gl_FragColor=texture2D(mapLeft,uv);') &&
1956
- compact.includes('gl_FragColor=texture2D(mapRight,uv);');
1957
- }
1958
- function isThreeAfterimagePassShaderMaterial(material) {
1959
- const uniforms = material.uniforms;
1960
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
1961
- return false;
1962
- const values = uniforms;
1963
- if (values.damp == null || values.tOld == null || values.tNew == null)
1964
- return false;
1965
- if (typeof material.fragmentShader !== 'string')
1966
- return false;
1967
- const compact = material.fragmentShader.replace(/\s+/g, '');
1968
- return compact.includes('uniformfloatdamp;') &&
1969
- compact.includes('uniformsampler2DtOld;') &&
1970
- compact.includes('uniformsampler2DtNew;') &&
1971
- compact.includes('texelOld*=damp*when_gt(texelOld,0.1);') &&
1972
- compact.includes('gl_FragColor=max(texelNew,texelOld);');
1973
- }
1974
- function isThreeBloomPassConvolutionShaderMaterial(material) {
1975
- const uniforms = material.uniforms;
1976
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
1977
- return false;
1978
- const values = uniforms;
1979
- if (values.tDiffuse == null || values.uImageIncrement == null || values.cKernel == null)
1980
- return false;
1981
- if (typeof material.fragmentShader !== 'string')
1982
- return false;
1983
- const compact = material.fragmentShader.replace(/\s+/g, '');
1984
- return compact.includes('uniformfloatcKernel[KERNEL_SIZE_INT];') &&
1985
- compact.includes('uniformsampler2DtDiffuse;') &&
1986
- compact.includes('uniformvec2uImageIncrement;') &&
1987
- compact.includes('sum+=texture2D(tDiffuse,imageCoord)*cKernel[i];') &&
1988
- compact.includes('imageCoord+=uImageIncrement;') &&
1989
- compact.includes('gl_FragColor=sum;');
1990
- }
1991
- function isThreeFilmPassShaderMaterial(material) {
1992
- const uniforms = material.uniforms;
1993
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
1994
- return false;
1995
- const values = uniforms;
1996
- if (values.tDiffuse == null || values.time == null || values.intensity == null || values.grayscale == null) {
1997
- return false;
1998
- }
1999
- if (typeof material.fragmentShader !== 'string')
2000
- return false;
2001
- const compact = material.fragmentShader.replace(/\s+/g, '');
2002
- return compact.includes('uniformfloatintensity;') &&
2003
- compact.includes('uniformboolgrayscale;') &&
2004
- compact.includes('uniformfloattime;') &&
2005
- compact.includes('floatnoise=rand(fract(vUv+time));') &&
2006
- compact.includes('color=mix(base.rgb,color,intensity);') &&
2007
- compact.includes('gl_FragColor=vec4(color,base.a);');
2008
- }
2009
- function isThreeDotScreenPassShaderMaterial(material) {
2010
- const uniforms = material.uniforms;
2011
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2012
- return false;
2013
- const values = uniforms;
2014
- if (values.tDiffuse == null ||
2015
- values.tSize == null ||
2016
- values.center == null ||
2017
- values.angle == null ||
2018
- values.scale == null) {
2019
- return false;
2020
- }
2021
- if (typeof material.fragmentShader !== 'string')
2022
- return false;
2023
- const compact = material.fragmentShader.replace(/\s+/g, '');
2024
- return compact.includes('uniformvec2center;') &&
2025
- compact.includes('uniformfloatscale;') &&
2026
- compact.includes('uniformvec2tSize;') &&
2027
- compact.includes('floatpattern()') &&
2028
- compact.includes('vec2tex=vUv*tSize-center;') &&
2029
- compact.includes('gl_FragColor=vec4(vec3(average*10.0-5.0+pattern()),color.a);');
2030
- }
2031
- function isThreeGlitchPassShaderMaterial(material) {
2032
- const uniforms = material.uniforms;
2033
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2034
- return false;
2035
- const values = uniforms;
2036
- if (values.tDiffuse == null ||
2037
- values.tDisp == null ||
2038
- values.byp == null ||
2039
- values.amount == null ||
2040
- values.angle == null ||
2041
- values.seed == null ||
2042
- values.seed_x == null ||
2043
- values.seed_y == null ||
2044
- values.distortion_x == null ||
2045
- values.distortion_y == null ||
2046
- values.col_s == null) {
2047
- return false;
2048
- }
2049
- if (typeof material.fragmentShader !== 'string')
2050
- return false;
2051
- const compact = material.fragmentShader.replace(/\s+/g, '');
2052
- return compact.includes('uniformintbyp;') &&
2053
- compact.includes('uniformsampler2DtDisp;') &&
2054
- compact.includes('uniformfloatdistortion_x;') &&
2055
- compact.includes('floatdisp=texture2D(tDisp,p*seed*seed).r;') &&
2056
- compact.includes('vec4cr=texture2D(tDiffuse,p+offset);') &&
2057
- compact.includes('gl_FragColor=vec4(cr.r,cga.g,cb.b,cga.a);');
2058
- }
2059
- function isThreeHalftonePassShaderMaterial(material) {
2060
- const uniforms = material.uniforms;
2061
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2062
- return false;
2063
- const values = uniforms;
2064
- if (values.tDiffuse == null ||
2065
- values.shape == null ||
2066
- values.radius == null ||
2067
- values.rotateR == null ||
2068
- values.rotateG == null ||
2069
- values.rotateB == null ||
2070
- values.scatter == null ||
2071
- values.width == null ||
2072
- values.height == null ||
2073
- values.blending == null ||
2074
- values.blendingMode == null ||
2075
- values.greyscale == null ||
2076
- values.disable == null) {
2077
- return false;
2078
- }
2079
- if (typeof material.fragmentShader !== 'string')
2080
- return false;
2081
- const compact = material.fragmentShader.replace(/\s+/g, '');
2082
- return compact.includes('uniformfloatradius;') &&
2083
- compact.includes('uniformfloatrotateR;') &&
2084
- compact.includes('uniformintshape;') &&
2085
- compact.includes('structCell{') &&
2086
- compact.includes('vec4getSample(vec2point)') &&
2087
- compact.includes('CellgetReferenceCell(vec2p,vec2origin,floatgrid_angle,floatstep)') &&
2088
- compact.includes('gl_FragColor=vec4(r,g,b,1.0);');
2089
- }
2090
- function isThreeLutPassShaderMaterial(material) {
2091
- const uniforms = material.uniforms;
2092
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2093
- return false;
2094
- const values = uniforms;
2095
- if (values.lut == null || values.lutSize == null || values.tDiffuse == null || values.intensity == null) {
2096
- return false;
2097
- }
2098
- if (typeof material.fragmentShader !== 'string')
2099
- return false;
2100
- const compact = material.fragmentShader.replace(/\s+/g, '');
2101
- return compact.includes('uniformfloatlutSize;') &&
2102
- compact.includes('uniformsampler3Dlut;') &&
2103
- compact.includes('uniformfloatintensity;') &&
2104
- compact.includes('uniformsampler2DtDiffuse;') &&
2105
- compact.includes('vec4val=texture2D(tDiffuse,vUv);') &&
2106
- compact.includes('floatpixelWidth=1.0/lutSize;') &&
2107
- compact.includes('vec3uvw=vec3(halfPixelWidth)+val.rgb*(1.0-pixelWidth);') &&
2108
- compact.includes('lutVal=vec4(texture(lut,uvw).rgb,val.a);') &&
2109
- compact.includes('gl_FragColor=vec4(mix(val,lutVal,intensity));');
2110
- }
2111
- function isThreeBokehPassShaderMaterial(material) {
2112
- const uniforms = material.uniforms;
2113
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2114
- return false;
2115
- const values = uniforms;
2116
- if (values.tColor == null ||
2117
- values.tDepth == null ||
2118
- values.focus == null ||
2119
- values.aspect == null ||
2120
- values.aperture == null ||
2121
- values.maxblur == null ||
2122
- values.nearClip == null ||
2123
- values.farClip == null) {
2124
- return false;
2125
- }
2126
- if (typeof material.fragmentShader !== 'string')
2127
- return false;
2128
- const compact = material.fragmentShader.replace(/\s+/g, '');
2129
- return compact.includes('uniformsampler2DtColor;') &&
2130
- compact.includes('uniformsampler2DtDepth;') &&
2131
- compact.includes('uniformfloataperture;') &&
2132
- compact.includes('uniformfloatnearClip;') &&
2133
- compact.includes('floatviewZ=getViewZ(getDepth(vUv));') &&
2134
- compact.includes('vec2dofblur=vec2(clamp(factor*aperture,-maxblur,maxblur));') &&
2135
- compact.includes('gl_FragColor=col/41.0;');
2136
- }
2137
- function isThreeRenderPixelatedPassShaderMaterial(material) {
2138
- const uniforms = material.uniforms;
2139
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2140
- return false;
2141
- const values = uniforms;
2142
- if (values.tDiffuse == null ||
2143
- values.tDepth == null ||
2144
- values.tNormal == null ||
2145
- values.resolution == null ||
2146
- values.normalEdgeStrength == null ||
2147
- values.depthEdgeStrength == null) {
2148
- return false;
2149
- }
2150
- if (typeof material.fragmentShader !== 'string')
2151
- return false;
2152
- const compact = material.fragmentShader.replace(/\s+/g, '');
2153
- return compact.includes('uniformsampler2DtNormal;') &&
2154
- compact.includes('uniformvec4resolution;') &&
2155
- compact.includes('floatgetDepth(intx,inty)') &&
2156
- compact.includes('vec3getNormal(intx,inty)') &&
2157
- compact.includes('floatdepthEdgeIndicator(floatdepth,vec3normal)') &&
2158
- compact.includes('floatnormalEdgeIndicator(floatdepth,vec3normal)') &&
2159
- compact.includes('gl_FragColor=texel*Strength;');
2160
- }
2161
- function isThreeRenderTransitionPassShaderMaterial(material) {
2162
- const uniforms = material.uniforms;
2163
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2164
- return false;
2165
- const values = uniforms;
2166
- if (values.tDiffuse1 == null ||
2167
- values.tDiffuse2 == null ||
2168
- values.mixRatio == null ||
2169
- values.threshold == null ||
2170
- values.useTexture == null ||
2171
- values.tMixTexture == null) {
2172
- return false;
2173
- }
2174
- if (typeof material.fragmentShader !== 'string')
2175
- return false;
2176
- const compact = material.fragmentShader.replace(/\s+/g, '');
2177
- return compact.includes('uniformsampler2DtDiffuse1;') &&
2178
- compact.includes('uniformsampler2DtDiffuse2;') &&
2179
- compact.includes('uniformsampler2DtMixTexture;') &&
2180
- compact.includes('uniformfloatmixRatio;') &&
2181
- compact.includes('floatmixf=clamp((transitionTexel.r-r)*(1.0/threshold),0.0,1.0);') &&
2182
- compact.includes('gl_FragColor=mix(texel1,texel2,mixf);') &&
2183
- compact.includes('gl_FragColor=mix(texel2,texel1,mixRatio);');
2184
- }
2185
- function isThreeCubeTexturePassShaderMaterial(material) {
2186
- const uniforms = material.uniforms;
2187
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2188
- return false;
2189
- const values = uniforms;
2190
- if (values.tCube == null || values.tFlip == null || values.opacity == null)
2191
- return false;
2192
- if (typeof material.fragmentShader !== 'string')
2193
- return false;
2194
- const compact = material.fragmentShader.replace(/\s+/g, '');
2195
- return compact.includes('uniformsamplerCubetCube;') &&
2196
- compact.includes('uniformfloattFlip;') &&
2197
- compact.includes('uniformfloatopacity;') &&
2198
- compact.includes('textureCube(tCube,vec3(tFlip*vWorldDirection.x,vWorldDirection.yz))') &&
2199
- compact.includes('gl_FragColor.a*=opacity;');
2200
- }
2201
- function isThreeSaoPassShaderMaterial(material) {
2202
- const uniforms = material.uniforms;
2203
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2204
- return false;
2205
- const values = uniforms;
2206
- if (values.tDepth == null ||
2207
- values.tNormal == null ||
2208
- values.size == null ||
2209
- values.cameraNear == null ||
2210
- values.cameraFar == null ||
2211
- values.cameraProjectionMatrix == null ||
2212
- values.cameraInverseProjectionMatrix == null ||
2213
- values.scale == null ||
2214
- values.intensity == null ||
2215
- values.bias == null ||
2216
- values.minResolution == null ||
2217
- values.kernelRadius == null ||
2218
- values.randomSeed == null) {
2219
- return false;
2220
- }
2221
- if (typeof material.fragmentShader !== 'string')
2222
- return false;
2223
- const compact = material.fragmentShader.replace(/\s+/g, '');
2224
- return compact.includes('uniformhighpsampler2DtDepth;') &&
2225
- compact.includes('uniformhighpsampler2DtNormal;') &&
2226
- compact.includes('uniformfloatkernelRadius;') &&
2227
- compact.includes('floatgetAmbientOcclusion(constinvec3centerViewPosition)') &&
2228
- compact.includes('scaleDividedByCameraFar=scale/cameraFar;') &&
2229
- compact.includes('occlusionSum+=getOcclusion(centerViewPosition,centerViewNormal,sampleViewPosition);') &&
2230
- compact.includes('gl_FragColor.xyz*=1.0-ambientOcclusion;');
2231
- }
2232
- function isThreeSsaoPassShaderMaterial(material) {
2233
- const uniforms = material.uniforms;
2234
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2235
- return false;
2236
- const values = uniforms;
2237
- if (values.tNormal == null ||
2238
- values.tDepth == null ||
2239
- values.tNoise == null ||
2240
- values.kernel == null ||
2241
- values.cameraNear == null ||
2242
- values.cameraFar == null ||
2243
- values.resolution == null ||
2244
- values.cameraProjectionMatrix == null ||
2245
- values.cameraInverseProjectionMatrix == null ||
2246
- values.kernelRadius == null ||
2247
- values.minDistance == null ||
2248
- values.maxDistance == null) {
2249
- return false;
2250
- }
2251
- if (typeof material.fragmentShader !== 'string')
2252
- return false;
2253
- const compact = material.fragmentShader.replace(/\s+/g, '');
2254
- return compact.includes('uniformhighpsampler2DtNormal;') &&
2255
- compact.includes('uniformhighpsampler2DtDepth;') &&
2256
- compact.includes('uniformsampler2DtNoise;') &&
2257
- compact.includes('uniformvec3kernel[KERNEL_SIZE];') &&
2258
- compact.includes('vec2noiseScale=vec2(resolution.x/4.0,resolution.y/4.0);') &&
2259
- compact.includes('vec3sampleVector=kernelMatrix*kernel[i];') &&
2260
- compact.includes('if(delta>minDistance&&delta<maxDistance)') &&
2261
- compact.includes('gl_FragColor=vec4(vec3(1.0-occlusion),1.0);');
2262
- }
2263
- function isThreeGtaoPassShaderMaterial(material) {
2264
- const uniforms = material.uniforms;
2265
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2266
- return false;
2267
- const values = uniforms;
2268
- if (values.tNormal == null ||
2269
- values.tDepth == null ||
2270
- values.tNoise == null ||
2271
- values.resolution == null ||
2272
- values.cameraNear == null ||
2273
- values.cameraFar == null ||
2274
- values.cameraProjectionMatrix == null ||
2275
- values.cameraProjectionMatrixInverse == null ||
2276
- values.cameraWorldMatrix == null ||
2277
- values.radius == null ||
2278
- values.distanceExponent == null ||
2279
- values.thickness == null ||
2280
- values.distanceFallOff == null ||
2281
- values.scale == null) {
2282
- return false;
2283
- }
2284
- if (typeof material.fragmentShader !== 'string')
2285
- return false;
2286
- const compact = material.fragmentShader.replace(/\s+/g, '');
2287
- return compact.includes('uniformhighpsampler2DtNormal;') &&
2288
- compact.includes('uniformhighpsampler2DtDepth;') &&
2289
- compact.includes('uniformsampler2DtNoise;') &&
2290
- compact.includes('uniformmat4cameraProjectionMatrixInverse;') &&
2291
- compact.includes('floatgetDepth(constvec2uv)') &&
2292
- compact.includes('returntextureLod(tDepth,uv.xy,0.0).DEPTH_SWIZZLING;') &&
2293
- compact.includes('constintDIRECTIONS=SAMPLES<30?3:5;') &&
2294
- compact.includes('gl_FragColor=FRAGMENT_OUTPUT;');
2295
- }
2296
- function isThreeUnrealBloomPassHighPassShaderMaterial(material) {
2297
- const uniforms = material.uniforms;
2298
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2299
- return false;
2300
- const values = uniforms;
2301
- if (values.tDiffuse == null ||
2302
- values.luminosityThreshold == null ||
2303
- values.smoothWidth == null ||
2304
- values.defaultColor == null ||
2305
- values.defaultOpacity == null) {
2306
- return false;
2307
- }
2308
- if (typeof material.fragmentShader !== 'string')
2309
- return false;
2310
- const compact = material.fragmentShader.replace(/\s+/g, '');
2311
- return compact.includes('uniformvec3defaultColor;') &&
2312
- compact.includes('uniformfloatdefaultOpacity;') &&
2313
- compact.includes('uniformfloatluminosityThreshold;') &&
2314
- compact.includes('floatv=luminance(texel.xyz);') &&
2315
- compact.includes('vec4outputColor=vec4(defaultColor.rgb,defaultOpacity);') &&
2316
- compact.includes('floatalpha=smoothstep(luminosityThreshold,luminosityThreshold+smoothWidth,v);') &&
2317
- compact.includes('gl_FragColor=mix(outputColor,texel,alpha);');
2318
- }
2319
- function isThreeSsrPassShaderMaterial(material) {
2320
- const uniforms = material.uniforms;
2321
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2322
- return false;
2323
- const values = uniforms;
2324
- if (values.tDiffuse == null ||
2325
- values.tNormal == null ||
2326
- values.tMetalness == null ||
2327
- values.tDepth == null ||
2328
- values.cameraNear == null ||
2329
- values.cameraFar == null ||
2330
- values.resolution == null ||
2331
- values.cameraProjectionMatrix == null ||
2332
- values.cameraInverseProjectionMatrix == null ||
2333
- values.opacity == null ||
2334
- values.maxDistance == null ||
2335
- values.cameraRange == null ||
2336
- values.thickness == null) {
2337
- return false;
2338
- }
2339
- if (typeof material.fragmentShader !== 'string')
2340
- return false;
2341
- const compact = material.fragmentShader.replace(/\s+/g, '');
2342
- return compact.includes('precisionhighpsampler2D;') &&
2343
- compact.includes('uniformsampler2DtMetalness;') &&
2344
- compact.includes('uniformfloatmaxDistance;') &&
2345
- compact.includes('floatpointToLineDistance(vec3x0,vec3x1,vec3x2)') &&
2346
- compact.includes('vec2viewPositionToXY(vec3viewPosition)') &&
2347
- compact.includes('vec3viewReflectDir=reflect(viewIncidentDir,viewNormal);') &&
2348
- compact.includes('vec4reflectColor=texture2D(tDiffuse,uv);') &&
2349
- compact.includes('gl_FragColor.xyz=reflectColor.xyz;');
2350
- }
2351
- function isThreeSmaaPassEdgesShaderMaterial(material) {
2352
- const uniforms = material.uniforms;
2353
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2354
- return false;
2355
- const values = uniforms;
2356
- if (values.tDiffuse == null || values.resolution == null)
2357
- return false;
2358
- if (typeof material.fragmentShader !== 'string')
2359
- return false;
2360
- const compact = material.fragmentShader.replace(/\s+/g, '');
2361
- return compact.includes('varyingvec4vOffset[3];') &&
2362
- compact.includes('vec4SMAAColorEdgeDetectionPS(vec2texcoord,vec4offset[3],sampler2DcolorTex)') &&
2363
- compact.includes('vec2threshold=vec2(SMAA_THRESHOLD,SMAA_THRESHOLD);') &&
2364
- compact.includes('vec2edges=step(threshold,delta.xy);') &&
2365
- compact.includes('edges.xy*=step(0.5*maxDelta,delta.xy);') &&
2366
- compact.includes('gl_FragColor=SMAAColorEdgeDetectionPS(vUv,vOffset,tDiffuse);');
2367
- }
2368
- function isThreeOutlinePassPrepareMaskShaderMaterial(material) {
2369
- const uniforms = material.uniforms;
2370
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2371
- return false;
2372
- const values = uniforms;
2373
- if (values.depthTexture == null || values.cameraNearFar == null || values.textureMatrix == null)
2374
- return false;
2375
- if (typeof material.fragmentShader !== 'string')
2376
- return false;
2377
- const compact = material.fragmentShader.replace(/\s+/g, '');
2378
- return compact.includes('uniformsampler2DdepthTexture;') &&
2379
- compact.includes('uniformvec2cameraNearFar;') &&
2380
- compact.includes('floatdepth=unpackRGBAToDepth(texture2DProj(depthTexture,projTexCoord));') &&
2381
- compact.includes('DepthToViewZ(depth,cameraNearFar.x,cameraNearFar.y);') &&
2382
- compact.includes('floatdepthTest=(-vPosition.z>viewZ)?1.0:0.0;') &&
2383
- compact.includes('gl_FragColor=vec4(0.0,depthTest,1.0,1.0);');
2384
- }
2385
- function isThreeOutlineEffectShaderMaterial(material) {
2386
- if (material.type !== 'OutlineEffect')
2387
- return false;
2388
- const uniforms = material.uniforms;
2389
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2390
- return false;
2391
- const values = uniforms;
2392
- if (values.outlineThickness == null || values.outlineColor == null || values.outlineAlpha == null)
2393
- return false;
2394
- if (typeof material.vertexShader !== 'string' || typeof material.fragmentShader !== 'string')
2395
- return false;
2396
- const vertexCompact = material.vertexShader.replace(/\s+/g, '');
2397
- const fragmentCompact = material.fragmentShader.replace(/\s+/g, '');
2398
- return vertexCompact.includes('vec4calculateOutline(vec4pos,vec3normal,vec4skinned)') &&
2399
- vertexCompact.includes('gl_Position=calculateOutline(gl_Position,outlineNormal,vec4(transformed,1.0));') &&
2400
- fragmentCompact.includes('uniformvec3outlineColor;') &&
2401
- fragmentCompact.includes('uniformfloatoutlineAlpha;') &&
2402
- fragmentCompact.includes('gl_FragColor=vec4(outlineColor,outlineAlpha);');
2403
- }
2404
- function isThreeSkyShaderMaterial(material) {
2405
- const uniforms = material.uniforms;
2406
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2407
- return false;
2408
- const values = uniforms;
2409
- if (material.name !== 'SkyShader' ||
2410
- values.turbidity == null ||
2411
- values.rayleigh == null ||
2412
- values.mieCoefficient == null ||
2413
- values.mieDirectionalG == null ||
2414
- values.sunPosition == null ||
2415
- values.up == null) {
2416
- return false;
2417
- }
2418
- if (typeof material.fragmentShader !== 'string')
2419
- return false;
2420
- const compact = material.fragmentShader.replace(/\s+/g, '');
2421
- return compact.includes('uniformfloatmieDirectionalG;') &&
2422
- compact.includes('constfloatrayleighZenithLength=8.4E3;') &&
2423
- compact.includes('floatsundisk=smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);') &&
2424
- compact.includes('vec3retColor=pow(texColor,vec3(1.0/(1.2+(1.2*vSunfade))));') &&
2425
- compact.includes('gl_FragColor=vec4(retColor,1.0);');
2426
- }
2427
- function isThreeWaterMirrorShaderMaterial(material) {
2428
- const uniforms = material.uniforms;
2429
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2430
- return false;
2431
- const values = uniforms;
2432
- if (material.name !== 'MirrorShader' ||
2433
- values.normalSampler == null ||
2434
- values.mirrorSampler == null ||
2435
- values.alpha == null ||
2436
- values.time == null ||
2437
- values.size == null ||
2438
- values.distortionScale == null ||
2439
- values.textureMatrix == null ||
2440
- values.sunColor == null ||
2441
- values.sunDirection == null ||
2442
- values.eye == null ||
2443
- values.waterColor == null) {
2444
- return false;
2445
- }
2446
- if (typeof material.fragmentShader !== 'string')
2447
- return false;
2448
- const compact = material.fragmentShader.replace(/\s+/g, '');
2449
- return compact.includes('uniformsampler2DmirrorSampler;') &&
2450
- compact.includes('uniformsampler2DnormalSampler;') &&
2451
- compact.includes('vec4getNoise(vec2uv)') &&
2452
- compact.includes('voidsunLight(constvec3surfaceNormal,constvec3eyeDirection,floatshiny,floatspec,floatdiffuse,inoutvec3diffuseColor,inoutvec3specularColor)') &&
2453
- compact.includes('vec3reflectionSample=vec3(texture2D(mirrorSampler,mirrorCoord.xy/mirrorCoord.w+distortion));') &&
2454
- compact.includes('gl_FragColor=vec4(outgoingLight,alpha);');
2455
- }
2456
- function isThreeWater2ShaderMaterial(material) {
2457
- const uniforms = material.uniforms;
2458
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2459
- return false;
2460
- const values = uniforms;
2461
- if (material.name !== 'WaterShader' ||
2462
- values.color == null ||
2463
- values.reflectivity == null ||
2464
- values.tReflectionMap == null ||
2465
- values.tRefractionMap == null ||
2466
- values.tNormalMap0 == null ||
2467
- values.tNormalMap1 == null ||
2468
- values.textureMatrix == null ||
2469
- values.config == null) {
2470
- return false;
2471
- }
2472
- if (typeof material.fragmentShader !== 'string')
2473
- return false;
2474
- const compact = material.fragmentShader.replace(/\s+/g, '');
2475
- return compact.includes('uniformsampler2DtReflectionMap;') &&
2476
- compact.includes('uniformsampler2DtRefractionMap;') &&
2477
- compact.includes('uniformsampler2DtNormalMap0;') &&
2478
- compact.includes('floatflowMapOffset0=config.x;') &&
2479
- compact.includes('vec4normalColor0=texture2D(tNormalMap0,(vUv*scale)+flow*flowMapOffset0);') &&
2480
- compact.includes('vec4reflectColor=texture2D(tReflectionMap,vec2(1.0-uv.x,uv.y));') &&
2481
- compact.includes('gl_FragColor=vec4(color,1.0)*mix(refractColor,reflectColor,reflectance);');
2482
- }
2483
- function isThreeReflectorForSsrPassShaderMaterial(material) {
2484
- const uniforms = material.uniforms;
2485
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2486
- return false;
2487
- const values = uniforms;
2488
- if (material.name !== 'ReflectorShader' ||
2489
- values.color == null ||
2490
- values.tDiffuse == null ||
2491
- values.tDepth == null ||
2492
- values.textureMatrix == null ||
2493
- values.maxDistance == null ||
2494
- values.opacity == null ||
2495
- values.fresnelCoe == null ||
2496
- values.virtualCameraNear == null ||
2497
- values.virtualCameraFar == null ||
2498
- values.virtualCameraProjectionMatrix == null ||
2499
- values.virtualCameraMatrixWorld == null ||
2500
- values.virtualCameraProjectionMatrixInverse == null ||
2501
- values.resolution == null) {
2502
- return false;
2503
- }
2504
- if (typeof material.fragmentShader !== 'string')
2505
- return false;
2506
- const compact = material.fragmentShader.replace(/\s+/g, '');
2507
- return compact.includes('uniformsampler2DtDepth;') &&
2508
- compact.includes('uniformfloatmaxDistance;') &&
2509
- compact.includes('floatgetViewZ(constinfloatdepth)') &&
2510
- compact.includes('returnperspectiveDepthToViewZ(depth,virtualCameraNear,virtualCameraFar);') &&
2511
- compact.includes('vec3worldPosition=(virtualCameraMatrixWorld*vec4(viewPosition,1)).xyz;') &&
2512
- compact.includes('gl_FragColor=vec4(blendOverlay(base.rgb,color),op);');
2513
- }
2514
- function isThreeReflectorShaderMaterial(material) {
2515
- const uniforms = material.uniforms;
2516
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2517
- return false;
2518
- const values = uniforms;
2519
- if (material.name !== 'ReflectorShader' ||
2520
- values.color == null ||
2521
- values.tDiffuse == null ||
2522
- values.textureMatrix == null ||
2523
- values.tDepth != null) {
2524
- return false;
2525
- }
2526
- if (typeof material.fragmentShader !== 'string')
2527
- return false;
2528
- const compact = material.fragmentShader.replace(/\s+/g, '');
2529
- return compact.includes('uniformsampler2DtDiffuse;') &&
2530
- compact.includes('floatblendOverlay(floatbase,floatblend)') &&
2531
- compact.includes('vec3blendOverlay(vec3base,vec3blend)') &&
2532
- compact.includes('vec4base=texture2DProj(tDiffuse,vUv);') &&
2533
- compact.includes('gl_FragColor=vec4(blendOverlay(base.rgb,color),1.0);');
2534
- }
2535
- function isThreeRefractorShaderMaterial(material) {
2536
- const uniforms = material.uniforms;
2537
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2538
- return false;
2539
- const values = uniforms;
2540
- if (material.name !== 'RefractorShader' ||
2541
- values.color == null ||
2542
- values.tDiffuse == null ||
2543
- values.textureMatrix == null) {
2544
- return false;
2545
- }
2546
- if (typeof material.fragmentShader !== 'string')
2547
- return false;
2548
- const compact = material.fragmentShader.replace(/\s+/g, '');
2549
- return compact.includes('uniformsampler2DtDiffuse;') &&
2550
- compact.includes('floatblendOverlay(floatbase,floatblend)') &&
2551
- compact.includes('vec3blendOverlay(vec3base,vec3blend)') &&
2552
- compact.includes('vec4base=texture2DProj(tDiffuse,vUv);') &&
2553
- compact.includes('gl_FragColor=vec4(blendOverlay(base.rgb,color),1.0);');
2554
- }
2555
- function isThreeShadowMapViewerShaderMaterial(material) {
2556
- const uniforms = material.uniforms;
2557
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2558
- return false;
2559
- const values = uniforms;
2560
- if (values.tDiffuse == null || values.opacity == null)
2561
- return false;
2562
- if (typeof material.fragmentShader !== 'string')
2563
- return false;
2564
- const compact = material.fragmentShader.replace(/\s+/g, '');
2565
- return compact.includes('uniformfloatopacity;') &&
2566
- compact.includes('uniformsampler2DtDiffuse;') &&
2567
- compact.includes('floatdepth=1.0-unpackRGBAToDepth(texture2D(tDiffuse,vUv));') &&
2568
- compact.includes('gl_FragColor=vec4(vec3(depth),opacity);');
2569
- }
2570
- function isThreeLightProbeHelperShaderMaterial(material) {
2571
- if (material.type === 'LightProbeHelperMaterial')
2572
- return true;
2573
- const uniforms = material.uniforms;
2574
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2575
- return false;
2576
- const values = uniforms;
2577
- if (values.sh == null || values.intensity == null)
2578
- return false;
2579
- if (typeof material.fragmentShader !== 'string')
2580
- return false;
2581
- const compact = material.fragmentShader.replace(/\s+/g, '');
2582
- return compact.includes('uniformvec3sh[9];') &&
2583
- compact.includes('vec3shGetIrradianceAt(invec3normal,invec3shCoefficients[9])') &&
2584
- compact.includes('vec3outgoingLight=RECIPROCAL_PI*irradiance*intensity;');
2585
- }
2586
- function isThreeTextureHelperShaderMaterial(material) {
2587
- if (material.type === 'TextureHelperMaterial')
2588
- return true;
2589
- const uniforms = material.uniforms;
2590
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2591
- return false;
2592
- const values = uniforms;
2593
- if (values.map == null || values.alpha == null)
2594
- return false;
2595
- if (typeof material.fragmentShader !== 'string')
2596
- return false;
2597
- const compact = material.fragmentShader.replace(/\s+/g, '');
2598
- return compact.includes('uniformfloatalpha;') &&
2599
- compact.includes('varyingvec3vUvw;') &&
2600
- compact.includes('vec4textureHelper(insampler2Dmap){returntexture(map,vUvw.xy);}') &&
2601
- compact.includes('gl_FragColor=linearToOutputTexel(vec4(textureHelper(map).xyz,alpha));');
2602
- }
2603
- function isThreeLineMaterialShaderMaterial(material) {
2604
- return material.isLineMaterial === true ||
2605
- material.type === 'LineMaterial';
2606
- }
2607
- function namedShaderMaterialLabel(kind, material) {
2608
- return typeof material.name === 'string' && material.name.trim().length > 0
2609
- ? `${kind} "${material.name}"`
2610
- : kind;
2611
- }
2612
- function assertSupportedOnBeforeCompile(material, customFragmentShader) {
2613
- if (customFragmentShader || !hasCustomOnBeforeCompile(material))
2614
- return;
2615
- if (isThreeCsmPatchedMaterial(material)) {
2616
- throw new Error('THREE.CSM material onBeforeCompile customization is not translated by @headless-three/renderer yet. Use regular supported native lights and shadows, pre-bake cascaded shadowing into textures, or provide material.userData.headlessThreeRenderer.fragmentWgsl with a WGSL fragment body for the renderer custom material path.');
2617
- }
2618
- throw new Error('material.onBeforeCompile customizations are not translated by @headless-three/renderer yet. Provide material.userData.headlessThreeRenderer.fragmentWgsl with a WGSL fragment body for the renderer custom material path.');
2619
- }
2620
- function assertSupportedMaterialNodeHooks(material) {
2621
- const nodeHooks = activeMaterialNodeHooks(material);
2622
- if (nodeHooks.length === 0)
2623
- return;
2624
- throw new Error(`material node hooks (${nodeHooks.join(', ')}) are not translated by @headless-three/renderer yet. Use a supported built-in material without Three.js TSL node hooks, bake the effect into geometry/textures, or provide equivalent fragment output through material.userData.headlessThreeRenderer.fragmentWgsl when only fragment color needs customization.`);
2625
- }
2626
- function activeMaterialNodeHooks(material) {
2627
- const materialRecord = material;
2628
- const hookNames = new Set(MaterialNodeHookProperties);
2629
- for (const name of Object.keys(materialRecord)) {
2630
- if (name.endsWith('Node'))
2631
- hookNames.add(name);
2632
- }
2633
- const active = [];
2634
- for (const name of hookNames) {
2635
- const value = materialRecord[name];
2636
- if (value == null)
2637
- continue;
2638
- if (MaterialNodeHookProperties.has(name) || materialNodeHookValue(value))
2639
- active.push(name);
2640
- }
2641
- return active;
2642
- }
2643
- function materialNodeHookValue(value) {
2644
- if (typeof value === 'function')
2645
- return true;
2646
- if (typeof value !== 'object')
2647
- return false;
2648
- return value.isNode === true ||
2649
- value.isMRTNode === true;
2650
- }
2651
- function isThreeCsmPatchedMaterial(material) {
2652
- const defines = material.defines;
2653
- return defines != null &&
2654
- typeof defines === 'object' &&
2655
- !Array.isArray(defines) &&
2656
- defines.USE_CSM != null &&
2657
- defines.CSM_CASCADES != null;
2658
- }
2659
- function assertSupportedMaterialState(material, context) {
2660
- optionalBoolean(material.wireframe, 'material.wireframe');
2661
- optionalPositiveFiniteNumber(material.wireframeLinewidth, 'material.wireframeLinewidth');
2662
- optionalWireframeLinecap(material.wireframeLinecap);
2663
- optionalWireframeLinejoin(material.wireframeLinejoin);
2664
- if (material.envMap != null &&
2665
- supportsNativeMaterialEnvironmentMap(material) &&
2666
- context.materialEnvironmentMaps?.has(material) !== true) {
2667
- throw new Error('material.envMap on MeshBasicMaterial, MeshStandardMaterial, MeshPhysicalMaterial, MeshPhongMaterial, and MeshLambertMaterial requires one shared material envMap represented by the native IBL path. Use scene.environment, remove material.envMap when a scene environment or reflection probe is active, or render separate passes.');
2668
- }
2669
- }
2670
- function assertSupportedMaterialClass(material, customFragmentShader) {
2671
- if (customFragmentShader || supportedMaterialClass(material) || copyShaderMaterialInfo(material))
2672
- return;
2673
- const type = typeof material.type === 'string' && material.type.trim()
2674
- ? material.type
2675
- : 'Material';
2676
- throw new Error(`${type} is not supported directly by @headless-three/renderer. Use a supported built-in Three.js material, or provide material.userData.headlessThreeRenderer.fragmentWgsl with a WGSL fragment body for the renderer's custom material path.`);
2677
- }
2678
- function supportedMaterialClass(material) {
2679
- return material.isMeshBasicMaterial === true
2680
- || material.isMeshDepthMaterial === true
2681
- || material.isMeshDistanceMaterial === true
2682
- || material.isMeshLambertMaterial === true
2683
- || material.isMeshMatcapMaterial === true
2684
- || material.isMeshNormalMaterial === true
2685
- || material.isMeshPhongMaterial === true
2686
- || material.isMeshStandardMaterial === true
2687
- || material.isMeshPhysicalMaterial === true
2688
- || material.isMeshToonMaterial === true
2689
- || material.isShadowMaterial === true
2690
- || material.isLineBasicMaterial === true
2691
- || material.isLineDashedMaterial === true
2692
- || material.isPointsMaterial === true
2693
- || material.isSpriteMaterial === true;
2694
- }
2695
- function hasCustomOnBeforeCompile(material) {
2696
- if (typeof material.onBeforeCompile !== 'function')
2697
- return false;
2698
- return normalizeFunctionSource(material.onBeforeCompile) !== DefaultOnBeforeCompileSource;
2699
- }
2700
- function normalizeFunctionSource(fn) {
2701
- return Function.prototype.toString.call(fn).replace(/\s+/g, ' ').trim();
2702
- }
2703
- function shaderMaterialKind(material) {
2704
- if (material.isRawShaderMaterial === true || material.type === 'RawShaderMaterial') {
2705
- return 'RawShaderMaterial';
2706
- }
2707
- if (material.isNodeMaterial === true ||
2708
- (typeof material.type === 'string' && material.type.includes('NodeMaterial'))) {
2709
- return 'NodeMaterial';
2710
- }
2711
- if (material.isShaderMaterial === true || material.type === 'ShaderMaterial') {
2712
- return 'ShaderMaterial';
2713
- }
2714
- return undefined;
2715
- }
2716
- function copyShaderMaterialInfo(material) {
2717
- if (!material)
2718
- return null;
2719
- const kind = shaderMaterialKind(material);
2720
- if (kind !== 'ShaderMaterial' && kind !== 'RawShaderMaterial')
2721
- return null;
2722
- if (kind === 'ShaderMaterial' && !isCopyShaderFragment(material.fragmentShader))
2723
- return null;
2724
- if (kind === 'RawShaderMaterial' && !isOutputShaderFragment(material.fragmentShader))
2725
- return null;
2726
- const uniforms = material.uniforms;
2727
- if (!uniforms || typeof uniforms !== 'object' || Array.isArray(uniforms))
2728
- return null;
2729
- return {
2730
- texture: uniformValue(uniforms.tDiffuse),
2731
- opacity: kind === 'ShaderMaterial'
2732
- ? uniformValue(uniforms.opacity) ?? 1
2733
- : 1,
2734
- };
2735
- }
2736
- function uniformValue(uniform) {
2737
- if (!uniform || typeof uniform !== 'object' || Array.isArray(uniform))
2738
- return undefined;
2739
- return uniform.value;
2740
- }
2741
- function isCopyShaderFragment(fragmentShader) {
2742
- if (typeof fragmentShader !== 'string')
2743
- return false;
2744
- const compact = fragmentShader.replace(/\s+/g, '');
2745
- return compact.includes('uniformfloatopacity;') &&
2746
- compact.includes('uniformsampler2DtDiffuse;') &&
2747
- compact.includes('texture2D(tDiffuse,vUv)') &&
2748
- compact.includes('gl_FragColor=opacity*texel;');
2749
- }
2750
- function isOutputShaderFragment(fragmentShader) {
2751
- if (typeof fragmentShader !== 'string')
2752
- return false;
2753
- const compact = fragmentShader.replace(/\s+/g, '');
2754
- return compact.includes('uniformsampler2DtDiffuse;') &&
2755
- compact.includes('gl_FragColor=texture2D(tDiffuse,vUv);') &&
2756
- compact.includes('tonemapping_pars_fragment') &&
2757
- compact.includes('colorspace_pars_fragment');
2758
- }
2759
- function extractTextureData(material, context = {}) {
2760
- const copyShader = copyShaderMaterialInfo(material);
2761
- const slot = copyShader
2762
- ? copyShader.texture
2763
- : material?.isMeshMatcapMaterial
2764
- ? material.matcap
2765
- : material?.map;
2766
- const label = copyShader
2767
- ? 'material.uniforms.tDiffuse.value'
2768
- : material?.isMeshMatcapMaterial
2769
- ? 'material.matcap'
2770
- : 'material.map';
2771
- const base = extractTextureFromSlot(slot, label, context.textureCache);
2772
- if (!base)
2773
- return null;
2774
- const map = slot;
2775
- const state = textureSamplerState(map, label, context, {
2776
- includeWrap: material?.isMeshMatcapMaterial !== true,
2777
- includeTransform: material?.isMeshMatcapMaterial !== true,
2778
- includeUvChannel: material?.isMeshMatcapMaterial !== true,
2779
- });
2780
- return { ...base, ...state };
2781
- }
2782
- function textureSamplerState(map, label, context, options = {}) {
2783
- const signature = map && context.textureStateCache
2784
- ? textureStateSignature(map, options)
2785
- : null;
2786
- if (map && signature) {
2787
- const cached = context.textureStateCache?.get(map);
2788
- if (cached && sameTextureStateSignature(cached.signature, signature)) {
2789
- return copyTextureSamplerState(cached.state);
2790
- }
2791
- }
2792
- const state = {
2793
- wrapS: options.includeWrap === false ? undefined : wrapModeToString(map?.wrapS),
2794
- wrapT: options.includeWrap === false ? undefined : wrapModeToString(map?.wrapT),
2795
- magFilter: filterModeToString(map?.magFilter),
2796
- minFilter: minFilterModeToString(map),
2797
- anisotropy: textureAnisotropy(map, label),
2798
- transform: options.includeTransform === false ? undefined : textureTransform(map, label),
2799
- colorSpace: textureColorSpace(map),
2800
- usesUv2: options.includeUvChannel === false ? false : textureUvChannel(map) > 0,
2801
- };
2802
- if (map && signature) {
2803
- context.textureStateCache?.set(map, { signature, state: copyTextureSamplerState(state) });
2804
- }
2805
- return state;
2806
- }
2807
- function textureStateSignature(texture, options) {
2808
- const mipmaps = texture.mipmaps;
2809
- const matrix = texture.matrix;
2810
- const matrixElements = matrix?.elements;
2811
- return {
2812
- includeWrap: options.includeWrap,
2813
- includeTransform: options.includeTransform,
2814
- includeUvChannel: options.includeUvChannel,
2815
- wrapS: texture.wrapS,
2816
- wrapT: texture.wrapT,
2817
- magFilter: texture.magFilter,
2818
- minFilter: texture.minFilter,
2819
- generateMipmaps: texture.generateMipmaps,
2820
- mipmaps,
2821
- mipmapCount: Array.isArray(mipmaps) ? mipmaps.length : undefined,
2822
- anisotropy: texture.anisotropy,
2823
- colorSpace: texture.colorSpace,
2824
- encoding: texture.encoding,
2825
- channel: texture.channel,
2826
- flipY: texture.flipY,
2827
- matrixAutoUpdate: texture.matrixAutoUpdate,
2828
- matrix,
2829
- matrixElements,
2830
- matrixValues: matrixElements ? Array.from(matrixElements) : undefined,
2831
- offset: texture.offset,
2832
- offsetX: texture.offset?.x,
2833
- offsetY: texture.offset?.y,
2834
- repeat: texture.repeat,
2835
- repeatX: texture.repeat?.x,
2836
- repeatY: texture.repeat?.y,
2837
- rotation: texture.rotation,
2838
- center: texture.center,
2839
- centerX: texture.center?.x,
2840
- centerY: texture.center?.y,
2841
- };
2842
- }
2843
- function copyTextureSamplerState(state) {
2844
- return {
2845
- ...state,
2846
- transform: state.transform ? state.transform.slice() : undefined,
2847
- };
2848
- }
2849
- function sameTextureStateSignature(a, b) {
2850
- return a.includeWrap === b.includeWrap
2851
- && a.includeTransform === b.includeTransform
2852
- && a.includeUvChannel === b.includeUvChannel
2853
- && a.wrapS === b.wrapS
2854
- && a.wrapT === b.wrapT
2855
- && a.magFilter === b.magFilter
2856
- && a.minFilter === b.minFilter
2857
- && a.generateMipmaps === b.generateMipmaps
2858
- && a.mipmaps === b.mipmaps
2859
- && a.mipmapCount === b.mipmapCount
2860
- && a.anisotropy === b.anisotropy
2861
- && a.colorSpace === b.colorSpace
2862
- && a.encoding === b.encoding
2863
- && a.channel === b.channel
2864
- && a.flipY === b.flipY
2865
- && a.matrixAutoUpdate === b.matrixAutoUpdate
2866
- && a.matrix === b.matrix
2867
- && a.matrixElements === b.matrixElements
2868
- && sameUnknownArray(a.matrixValues, b.matrixValues)
2869
- && a.offset === b.offset
2870
- && a.offsetX === b.offsetX
2871
- && a.offsetY === b.offsetY
2872
- && a.repeat === b.repeat
2873
- && a.repeatX === b.repeatX
2874
- && a.repeatY === b.repeatY
2875
- && a.rotation === b.rotation
2876
- && a.center === b.center
2877
- && a.centerX === b.centerX
2878
- && a.centerY === b.centerY;
2879
- }
2880
- function extractBackgroundTexture(background, label = 'background') {
2881
- const map = textureLike(background);
2882
- if (!map)
2883
- return null;
2884
- if (isCubeBackgroundTexture(map)) {
2885
- assertSupportedTextureInput(map, label);
2886
- return extractCubeBackgroundTexture(map, label);
2887
- }
2888
- assertSupportedBackgroundTexture(map, label);
2889
- const base = extractTextureFromSlot(map, label);
2890
- if (!base)
2891
- return null;
2892
- return {
2893
- ...base,
2894
- wrapS: wrapModeToString(map?.wrapS),
2895
- wrapT: wrapModeToString(map?.wrapT),
2896
- magFilter: filterModeToString(map?.magFilter),
2897
- minFilter: minFilterModeToString(map),
2898
- anisotropy: textureAnisotropy(map, label),
2899
- transform: textureTransform(map, label),
2900
- colorSpace: textureColorSpace(map),
2901
- mapping: backgroundTextureMapping(map),
2902
- };
2903
- }
2904
- function backgroundTextureMapping(map) {
2905
- return map.mapping === EquirectangularReflectionMapping || map.mapping === EquirectangularRefractionMapping
2906
- ? 'equirectangular'
2907
- : 'uv';
2908
- }
2909
- function isCubeBackgroundTexture(map) {
2910
- return map.isCubeTexture === true ||
2911
- map.mapping === CubeReflectionMapping ||
2912
- map.mapping === CubeRefractionMapping ||
2913
- map.mapping === CubeUVReflectionMapping;
2914
- }
2915
- function isCubeEnvironmentTexture(map, label = 'texture') {
2916
- return map.isCubeTexture === true ||
2917
- map.mapping === CubeReflectionMapping ||
2918
- map.mapping === CubeRefractionMapping ||
2919
- (map.mapping === CubeUVReflectionMapping &&
2920
- (cubeFaceImages(map, label) !== null || cubeUvPackedImage(map, label) !== null));
2921
- }
2922
- function extractCubeBackgroundTexture(map, label) {
2923
- const cube = cubeTextureToEquirectangular(map, label);
2924
- return {
2925
- ...cube,
2926
- wrapS: 'repeat',
2927
- wrapT: 'clamp',
2928
- magFilter: filterModeToString(map.magFilter),
2929
- minFilter: minFilterModeToString(map),
2930
- anisotropy: textureAnisotropy(map, label),
2931
- colorSpace: textureColorSpace(map),
2932
- mapping: 'equirectangular',
2933
- };
2934
- }
2935
- function cubeTextureToEquirectangular(map, label) {
2936
- textureUnpackAlignment(map, label);
2937
- const faces = cubeFaceImages(map, label);
2938
- if (!faces) {
2939
- if (map.mapping === CubeUVReflectionMapping) {
2940
- const packedFaceTextures = packedCubeUvTextureToFaceTextures(map, label);
2941
- if (packedFaceTextures)
2942
- return cubeFaceTexturesToEquirectangular(packedFaceTextures, label);
2943
- throw new Error(`${label} uses PMREM/CubeUV mapping without readable six-face cube images or a readable packed CubeUV image.`);
2944
- }
2945
- throw new Error(`${label} uses a cube texture without six raw or encoded face images. Provide a CubeTexture with six DataTexture-style or encoded PNG/JPEG/WebP face images, use a 2D/equirectangular texture, or pre-render the background to a 2D image before rendering.`);
2946
- }
2947
- const premultiplyAlpha = optionalTextureBoolean(map.premultiplyAlpha, `${label}.premultiplyAlpha`) === true;
2948
- const faceTextures = faces.map((face, index) => imageToRgbaTexture(face, `${label}.image[${index}]`, map.type, map.format, { premultiplyAlpha }));
2949
- return cubeFaceTexturesToEquirectangular(faceTextures, label);
2950
- }
2951
- function cubeFaceTexturesToEquirectangular(faceTextures, label) {
2952
- const faceWidth = faceTextures[0].width;
2953
- const faceHeight = faceTextures[0].height;
2954
- if (faceWidth !== faceHeight) {
2955
- throw new Error(`${label} cube background faces must be square raw RGBA images.`);
2956
- }
2957
- for (let i = 1; i < faceTextures.length; i += 1) {
2958
- if (faceTextures[i].width !== faceWidth || faceTextures[i].height !== faceHeight) {
2959
- throw new Error(`${label} cube background faces must all use the same dimensions.`);
2960
- }
2961
- }
2962
- const width = Math.max(64, faceWidth * 4);
2963
- const height = Math.max(32, faceHeight * 2);
2964
- const out = new Uint8Array(width * height * 4);
2965
- for (let y = 0; y < height; y += 1) {
2966
- const v = (y + 0.5) / height;
2967
- const pitch = (v - 0.5) * Math.PI;
2968
- const dirY = Math.sin(pitch);
2969
- const ring = Math.cos(pitch);
2970
- for (let x = 0; x < width; x += 1) {
2971
- const u = (x + 0.5) / width;
2972
- const yaw = (u - 0.5) * Math.PI * 2;
2973
- const dir = [
2974
- Math.cos(yaw) * ring,
2975
- dirY,
2976
- Math.sin(yaw) * ring,
2977
- ];
2978
- const sample = sampleCubeFace(faceTextures, dir);
2979
- out.set(sample, (y * width + x) * 4);
2980
- }
2981
- }
2982
- return {
2983
- data: Buffer.from(out.buffer, out.byteOffset, out.byteLength),
2984
- width,
2985
- height,
2986
- };
2987
- }
2988
- function cubeFaceImages(map, label = 'texture') {
2989
- const sourceData = textureSourceData(map, label);
2990
- const image = map.image ?? sourceData;
2991
- if (Array.isArray(image) && image.length >= 6)
2992
- return image.slice(0, 6);
2993
- return null;
2994
- }
2995
- function cubeUvPackedImage(map, label = 'texture') {
2996
- if (map.mapping !== CubeUVReflectionMapping)
2997
- return null;
2998
- const sourceData = textureSourceData(map, label);
2999
- const image = map.image ?? sourceData;
3000
- if (!image || Array.isArray(image))
3001
- return null;
3002
- if (Buffer.isBuffer(image) || image instanceof Uint8Array)
3003
- return image;
3004
- if (typeof image === 'object')
3005
- return image;
3006
- return null;
3007
- }
3008
- function packedCubeUvTextureToFaceTextures(map, label) {
3009
- const packedImage = cubeUvPackedImage(map, label);
3010
- if (!packedImage)
3011
- return null;
3012
- const premultiplyAlpha = optionalTextureBoolean(map.premultiplyAlpha, `${label}.premultiplyAlpha`) === true;
3013
- const atlas = imageToRgbaTexture(packedImage, `${label}.image`, map.type, map.format, { premultiplyAlpha });
3014
- if (atlas.height % 4 !== 0) {
3015
- throw new Error(`${label} packed PMREM/CubeUV image height must be divisible by 4.`);
3016
- }
3017
- const faceSize = atlas.height / 4;
3018
- if (!Number.isInteger(faceSize) || faceSize < 16 || atlas.width < faceSize * 3) {
3019
- throw new Error(`${label} packed PMREM/CubeUV image must use Three.js' 3-column by 4-row layout with at least 16x16 face tiles.`);
3020
- }
3021
- const atlasFaceToCubeFace = [0, 2, 4, 1, 3, 5];
3022
- const cubeFaces = [];
3023
- for (let atlasFace = 0; atlasFace < 6; atlasFace += 1) {
3024
- const col = atlasFace % 3;
3025
- const row = atlasFace > 2 ? 1 : 0;
3026
- cubeFaces[atlasFaceToCubeFace[atlasFace]] = extractRgbaTile(atlas, col * faceSize, row * faceSize, faceSize);
3027
- }
3028
- return cubeFaces;
3029
- }
3030
- function extractRgbaTile(source, x, y, size) {
3031
- const out = new Uint8Array(size * size * 4);
3032
- for (let row = 0; row < size; row += 1) {
3033
- const sourceStart = ((y + row) * source.width + x) * 4;
3034
- out.set(source.rgba.subarray(sourceStart, sourceStart + size * 4), row * size * 4);
3035
- }
3036
- return { rgba: out, width: size, height: size };
3037
- }
3038
- function imageToRgbaTexture(image, label, textureType, textureFormat, options = {}) {
3039
- if (Buffer.isBuffer(image) || image instanceof Uint8Array) {
3040
- const buffer = Buffer.isBuffer(image)
3041
- ? image
3042
- : Buffer.from(image.buffer, image.byteOffset, image.byteLength);
3043
- const decoded = native.decodeImage?.(buffer);
3044
- if (!decoded?.data || !(decoded.width > 0) || !(decoded.height > 0)) {
3045
- throw new Error(`${label} encoded cube face image could not be decoded to RGBA pixels.`);
3046
- }
3047
- const rgba = decoded.data instanceof Uint8Array
3048
- ? decoded.data
3049
- : new Uint8Array(decoded.data);
3050
- if (rgba.byteLength !== decoded.width * decoded.height * 4) {
3051
- throw new Error(`${label} encoded cube face image decoded to an unexpected RGBA byte length.`);
3052
- }
3053
- return {
3054
- rgba: options.premultiplyAlpha === true ? premultiplyRgbaAlpha(rgba) : rgba,
3055
- width: decoded.width,
3056
- height: decoded.height,
3057
- };
3058
- }
3059
- if (!image || !image.data || !(image.width > 0) || !(image.height > 0)) {
3060
- const canvasImage = canvasLikeImageToRgba(image, label);
3061
- if (canvasImage) {
3062
- return {
3063
- rgba: options.premultiplyAlpha === true ? premultiplyRgbaAlpha(canvasImage.rgba) : canvasImage.rgba,
3064
- width: canvasImage.width,
3065
- height: canvasImage.height,
3066
- };
3067
- }
3068
- throw new Error(`${label} must provide raw face data, width, and height for cube background rendering.`);
3069
- }
3070
- const rgba = toRgba8(image.data, image.width, image.height, { type: textureType, format: textureFormat });
3071
- if (!rgba) {
3072
- throw new Error(`${label} must contain RGB or RGBA numeric pixel data for cube background rendering.`);
3073
- }
3074
- return {
3075
- rgba: options.premultiplyAlpha === true ? premultiplyRgbaAlpha(rgba) : rgba,
3076
- width: image.width,
3077
- height: image.height,
3078
- };
3079
- }
3080
- function canvasLikeImageToRgba(image, label) {
3081
- if (!image || typeof image !== 'object') {
3082
- return null;
3083
- }
3084
- if (typeof image.getContext === 'function') {
3085
- const candidate = image;
3086
- const width = canvasLikeImageDimension(candidate.width, `${label}.width`);
3087
- const height = canvasLikeImageDimension(candidate.height, `${label}.height`);
3088
- const context = canvasLike2dContext(candidate, label);
3089
- return canvasLikeContextToRgba(context, width, height, label);
3090
- }
3091
- return drawImageLikeToRgba(image, label);
3092
- }
3093
- function drawImageLikeToRgba(image, label) {
3094
- const offscreenCanvas = globalThis.OffscreenCanvas;
3095
- if (typeof offscreenCanvas !== 'function')
3096
- return null;
3097
- const candidate = image;
3098
- const width = canvasLikeImageDimension(candidate.width ?? candidate.naturalWidth, `${label}.width`);
3099
- const height = canvasLikeImageDimension(candidate.height ?? candidate.naturalHeight, `${label}.height`);
3100
- const canvas = new offscreenCanvas(width, height);
3101
- const context = canvasLike2dContext(canvas, label);
3102
- if (typeof context.drawImage !== 'function') {
3103
- throw new Error(`${label} OffscreenCanvas 2D context must provide drawImage() to read image-like texture pixels.`);
3104
- }
3105
- try {
3106
- context
3107
- .drawImage(image, 0, 0, width, height);
3108
- }
3109
- catch {
3110
- throw new Error(`${label} OffscreenCanvas 2D context drawImage() failed while reading image-like texture pixels.`);
3111
- }
3112
- return canvasLikeContextToRgba(context, width, height, label);
3113
- }
3114
- function canvasLike2dContext(canvas, label) {
3115
- let context;
3116
- try {
3117
- context = canvas.getContext?.('2d', { willReadFrequently: true })
3118
- ?? canvas.getContext?.('2d');
3119
- }
3120
- catch {
3121
- throw new Error(`${label}.getContext("2d") failed while reading canvas texture pixels.`);
3122
- }
3123
- if (!context || typeof context !== 'object' || typeof context.getImageData !== 'function') {
3124
- throw new Error(`${label} canvas-like texture images must provide getContext("2d").getImageData().`);
3125
- }
3126
- return context;
3127
- }
3128
- function canvasLikeContextToRgba(context, width, height, label) {
3129
- let imageData;
3130
- try {
3131
- imageData = context
3132
- .getImageData(0, 0, width, height);
3133
- }
3134
- catch {
3135
- throw new Error(`${label}.getContext("2d").getImageData() failed while reading canvas texture pixels.`);
3136
- }
3137
- if (!imageData || typeof imageData !== 'object') {
3138
- throw new Error(`${label}.getContext("2d").getImageData() must return an ImageData-like object.`);
3139
- }
3140
- const data = imageData.data;
3141
- if (!(data instanceof Uint8Array) && !(data instanceof Uint8ClampedArray)) {
3142
- throw new Error(`${label}.getContext("2d").getImageData().data must be a Uint8Array or Uint8ClampedArray.`);
3143
- }
3144
- if (data.length !== width * height * 4) {
3145
- throw new Error(`${label}.getContext("2d").getImageData().data length must equal width * height * 4.`);
3146
- }
3147
- return {
3148
- rgba: new Uint8Array(data.buffer, data.byteOffset, data.byteLength),
3149
- width,
3150
- height,
3151
- };
3152
- }
3153
- function canvasLikeImageDimension(value, label) {
3154
- if (!Number.isInteger(value) || value <= 0) {
3155
- throw new TypeError(`${label} must be a positive integer for canvas-like texture image reads.`);
3156
- }
3157
- return value;
3158
- }
3159
- function premultiplyRgbaAlpha(data) {
3160
- const out = new Uint8Array(data.byteLength);
3161
- for (let i = 0; i < data.byteLength; i += 4) {
3162
- const alpha = data[i + 3];
3163
- out[i] = Math.round((data[i] * alpha) / 255);
3164
- out[i + 1] = Math.round((data[i + 1] * alpha) / 255);
3165
- out[i + 2] = Math.round((data[i + 2] * alpha) / 255);
3166
- out[i + 3] = alpha;
3167
- }
3168
- return out;
3169
- }
3170
- function premultiplyFloatRgba(data) {
3171
- const out = new Float32Array(data.length);
3172
- for (let i = 0; i < data.length; i += 4) {
3173
- const alpha = data[i + 3];
3174
- out[i] = data[i] * alpha;
3175
- out[i + 1] = data[i + 1] * alpha;
3176
- out[i + 2] = data[i + 2] * alpha;
3177
- out[i + 3] = alpha;
3178
- }
3179
- return out;
3180
- }
3181
- function premultiplyHalfFloatRgba(data) {
3182
- const out = new Uint16Array(data.length);
3183
- for (let i = 0; i < data.length; i += 4) {
3184
- const alpha = halfFloatToNumber(data[i + 3]);
3185
- out[i] = numberToHalfFloat(halfFloatToNumber(data[i]) * alpha);
3186
- out[i + 1] = numberToHalfFloat(halfFloatToNumber(data[i + 1]) * alpha);
3187
- out[i + 2] = numberToHalfFloat(halfFloatToNumber(data[i + 2]) * alpha);
3188
- out[i + 3] = data[i + 3];
3189
- }
3190
- return out;
3191
- }
3192
- function sampleCubeFace(faces, dir) {
3193
- const [x, y, z] = dir;
3194
- const ax = Math.abs(x);
3195
- const ay = Math.abs(y);
3196
- const az = Math.abs(z);
3197
- let faceIndex = 0;
3198
- let sc = 0;
3199
- let tc = 0;
3200
- if (ax >= ay && ax >= az) {
3201
- if (x >= 0) {
3202
- faceIndex = 0;
3203
- sc = -z / ax;
3204
- }
3205
- else {
3206
- faceIndex = 1;
3207
- sc = z / ax;
3208
- }
3209
- tc = -y / ax;
3210
- }
3211
- else if (ay >= ax && ay >= az) {
3212
- if (y >= 0) {
3213
- faceIndex = 2;
3214
- sc = x / ay;
3215
- tc = z / ay;
3216
- }
3217
- else {
3218
- faceIndex = 3;
3219
- sc = x / ay;
3220
- tc = -z / ay;
3221
- }
3222
- }
3223
- else {
3224
- if (z >= 0) {
3225
- faceIndex = 4;
3226
- sc = x / az;
3227
- }
3228
- else {
3229
- faceIndex = 5;
3230
- sc = -x / az;
3231
- }
3232
- tc = -y / az;
3233
- }
3234
- const face = faces[faceIndex];
3235
- const u = Math.max(0, Math.min(1, (sc + 1) * 0.5));
3236
- const v = Math.max(0, Math.min(1, (tc + 1) * 0.5));
3237
- const px = Math.min(face.width - 1, Math.floor(u * face.width));
3238
- const py = Math.min(face.height - 1, Math.floor(v * face.height));
3239
- const offset = (py * face.width + px) * 4;
3240
- return face.rgba.subarray(offset, offset + 4);
3241
- }
3242
- function textureLike(value) {
3243
- if (!value || Array.isArray(value))
3244
- return null;
3245
- const candidate = value;
3246
- if (candidate.isTexture === true || candidate.image || candidate.source?.data) {
3247
- return candidate;
3248
- }
3249
- return null;
3250
- }
3251
- function textureSourceData(texture, label) {
3252
- const source = texture.source;
3253
- if (source == null)
3254
- return undefined;
3255
- if (typeof source !== 'object' || Array.isArray(source)) {
3256
- throw new TypeError(`${label}.source must be a source-like object.`);
3257
- }
3258
- const data = source.data;
3259
- if (data == null)
3260
- return undefined;
3261
- if (typeof data !== 'object') {
3262
- throw new TypeError(`${label}.source.data must be an image-like object.`);
3263
- }
3264
- return data;
3265
- }
3266
- function requiredEnvironmentTexture(value, label) {
3267
- const texture = textureLike(value);
3268
- if (texture)
3269
- return texture;
3270
- throw new TypeError(`${label} must be a Three.js texture or null for environment map rendering.`);
3271
- }
3272
- function wrapModeToString(mode) {
3273
- if (mode == null || mode === ClampToEdgeWrapping)
3274
- return undefined; // default = clamp
3275
- if (mode === RepeatWrapping)
3276
- return 'repeat';
3277
- if (mode === MirroredRepeatWrapping)
3278
- return 'mirror';
3279
- throw new Error(`texture wrap mode ${String(mode)} is not supported by @headless-three/renderer. Use ClampToEdgeWrapping, RepeatWrapping, or MirroredRepeatWrapping.`);
3280
- }
3281
- function filterModeToString(mode) {
3282
- if (mode == null)
3283
- return undefined; // default = linear
3284
- if (mode === NearestFilter ||
3285
- mode === NearestMipmapNearestFilter ||
3286
- mode === NearestMipmapLinearFilter) {
3287
- return 'nearest';
3288
- }
3289
- if (mode === LinearFilter ||
3290
- mode === LinearMipmapNearestFilter ||
3291
- mode === LinearMipmapLinearFilter) {
3292
- return 'linear';
3293
- }
3294
- throw new Error(`texture.magFilter ${String(mode)} is not supported by @headless-three/renderer. Use NearestFilter or LinearFilter.`);
3295
- }
3296
- function minFilterModeToString(texture) {
3297
- const mode = texture?.minFilter;
3298
- if (mode == null)
3299
- return undefined;
3300
- const generateMipmaps = optionalTextureBoolean(texture?.generateMipmaps, 'texture.generateMipmaps');
3301
- const allowMipmaps = generateMipmaps !== false || hasExplicitMipmaps(texture);
3302
- if (mode === NearestFilter)
3303
- return 'nearest';
3304
- if (mode === LinearFilter)
3305
- return 'linear';
3306
- if (mode === NearestMipmapNearestFilter)
3307
- return allowMipmaps ? 'nearest-mipmap-nearest' : 'nearest';
3308
- if (mode === NearestMipmapLinearFilter)
3309
- return allowMipmaps ? 'nearest-mipmap-linear' : 'nearest';
3310
- if (mode === LinearMipmapNearestFilter)
3311
- return allowMipmaps ? 'linear-mipmap-nearest' : 'linear';
3312
- if (mode === LinearMipmapLinearFilter)
3313
- return allowMipmaps ? 'linear-mipmap-linear' : 'linear';
3314
- throw new Error(`texture.minFilter ${String(mode)} is not supported by @headless-three/renderer. Use NearestFilter, LinearFilter, or a Three.js mipmap minFilter constant.`);
3315
- }
3316
- function extractTextureFromSlot(map, label = 'texture', cache) {
3317
- if (!map)
3318
- return null;
3319
- assertSupportedTextureInput(map, label, { allowMipmaps: true });
3320
- assertSupportedTwoDimensionalTextureSlot(map, label);
3321
- textureUnpackAlignment(map, label);
3322
- const sourceData = textureSourceData(map, label);
3323
- const image = map.image ?? sourceData;
3324
- if (!image)
3325
- return null;
3326
- const signature = cache ? texturePayloadSignature(map, image, sourceData, label) : null;
3327
- if (signature) {
3328
- const cached = cache?.get(map);
3329
- if (cached && texturePayloadSignaturesEqual(cached.signature, signature)) {
3330
- return cached.info;
3331
- }
3332
- }
3333
- const cacheInfo = (info) => {
3334
- if (signature) {
3335
- cache?.set(map, { signature, info });
3336
- }
3337
- return info;
3338
- };
3339
- // DataTexture style: { data: TypedArray, width, height }
3340
- if (image.data && image.width > 0 && image.height > 0) {
3341
- assertSupportedRawTextureType(map.type, label, 'texture rendering');
3342
- const rgba = toRgba8(image.data, image.width, image.height, { type: map.type, format: map.format });
3343
- if (rgba) {
3344
- const data = textureBytesWithExplicitMipmaps(map, label, rgba, image.width, image.height);
3345
- return cacheInfo({ data: Buffer.from(data.buffer, data.byteOffset, data.byteLength), width: image.width, height: image.height });
3346
- }
3347
- throw unsupportedRawTextureDataError(label, 'texture rendering');
3348
- }
3349
- // Encoded image (PNG/JPEG/WebP Buffer from file loaders)
3350
- if (Buffer.isBuffer(image)) {
3351
- assertNoEncodedExplicitMipmaps(map, label);
3352
- assertNoEncodedPremultiplyAlpha(map, label);
3353
- return cacheInfo({ data: image, width: 0, height: 0 });
3354
- }
3355
- if (image instanceof Uint8Array && !(image.width > 0)) {
3356
- assertNoEncodedExplicitMipmaps(map, label);
3357
- assertNoEncodedPremultiplyAlpha(map, label);
3358
- return cacheInfo({ data: Buffer.from(image.buffer, image.byteOffset, image.byteLength), width: 0, height: 0 });
3359
- }
3360
- // ImageData (canvas-based polyfill): { data: Uint8ClampedArray, width, height }
3361
- if (image.data instanceof Uint8ClampedArray && image.width > 0 && image.height > 0) {
3362
- const data = textureBytesWithExplicitMipmaps(map, label, image.data, image.width, image.height);
3363
- return cacheInfo({
3364
- data: Buffer.from(data.buffer, data.byteOffset, data.byteLength),
3365
- width: image.width,
3366
- height: image.height,
3367
- });
3368
- }
3369
- const canvasImage = canvasLikeImageToRgba(image, label);
3370
- if (canvasImage) {
3371
- const data = textureBytesWithExplicitMipmaps(map, label, canvasImage.rgba, canvasImage.width, canvasImage.height);
3372
- return cacheInfo({
3373
- data: Buffer.from(data.buffer, data.byteOffset, data.byteLength),
3374
- width: canvasImage.width,
3375
- height: canvasImage.height,
3376
- });
3377
- }
3378
- throw unsupportedTextureImageError(label, 'texture rendering');
3379
- }
3380
- function texturePayloadSignature(map, image, sourceData, label) {
3381
- const version = map.version;
3382
- if (typeof version !== 'number' || !Number.isFinite(version))
3383
- return null;
3384
- return {
3385
- version,
3386
- image,
3387
- sourceData,
3388
- imageData: textureImageDataSignature(image),
3389
- imageWidth: textureImageDimension(image, 'width'),
3390
- imageHeight: textureImageDimension(image, 'height'),
3391
- type: map.type,
3392
- format: map.format,
3393
- premultiplyAlpha: map.premultiplyAlpha,
3394
- generateMipmaps: map.generateMipmaps,
3395
- mipmaps: textureMipmapSignatures(map, label),
3396
- };
3397
- }
3398
- function textureImageDataSignature(image) {
3399
- if (Buffer.isBuffer(image) || image instanceof Uint8Array) {
3400
- return textureDataSignature(image);
3401
- }
3402
- if (!image || typeof image !== 'object')
3403
- return undefined;
3404
- return textureDataSignature(image.data);
3405
- }
3406
- function textureDataSignature(data) {
3407
- if (data == null)
3408
- return undefined;
3409
- const arrayLike = data;
3410
- const view = ArrayBuffer.isView(data) ? data : undefined;
3411
- return {
3412
- data,
3413
- length: arrayLike.length,
3414
- buffer: view?.buffer,
3415
- byteOffset: view?.byteOffset,
3416
- byteLength: view?.byteLength,
3417
- };
3418
- }
3419
- function textureImageDimension(image, key) {
3420
- if (!image || typeof image !== 'object')
3421
- return undefined;
3422
- return image[key];
3423
- }
3424
- function textureMipmapSignatures(map, label) {
3425
- const mipmaps = map.mipmaps;
3426
- if (mipmaps == null)
3427
- return [];
3428
- if (!Array.isArray(mipmaps)) {
3429
- throw new TypeError(`${label}.mipmaps must be an array of image-like mip levels.`);
3430
- }
3431
- return mipmaps.map((image) => ({
3432
- image,
3433
- data: image && typeof image === 'object' ? textureDataSignature(image.data) : undefined,
3434
- width: image && typeof image === 'object' ? image.width : undefined,
3435
- height: image && typeof image === 'object' ? image.height : undefined,
3436
- }));
3437
- }
3438
- function texturePayloadSignaturesEqual(a, b) {
3439
- return a.version === b.version
3440
- && a.image === b.image
3441
- && a.sourceData === b.sourceData
3442
- && textureDataSignaturesEqual(a.imageData, b.imageData)
3443
- && a.imageWidth === b.imageWidth
3444
- && a.imageHeight === b.imageHeight
3445
- && a.type === b.type
3446
- && a.format === b.format
3447
- && a.premultiplyAlpha === b.premultiplyAlpha
3448
- && a.generateMipmaps === b.generateMipmaps
3449
- && textureMipmapSignaturesEqual(a.mipmaps, b.mipmaps);
3450
- }
3451
- function textureMipmapSignaturesEqual(a, b) {
3452
- if (a.length !== b.length)
3453
- return false;
3454
- for (let i = 0; i < a.length; i += 1) {
3455
- if (a[i].image !== b[i].image ||
3456
- !textureDataSignaturesEqual(a[i].data, b[i].data) ||
3457
- a[i].width !== b[i].width ||
3458
- a[i].height !== b[i].height) {
3459
- return false;
3460
- }
3461
- }
3462
- return true;
3463
- }
3464
- function textureDataSignaturesEqual(a, b) {
3465
- if (a === b)
3466
- return true;
3467
- if (!a || !b)
3468
- return false;
3469
- return a.data === b.data
3470
- && a.length === b.length
3471
- && a.buffer === b.buffer
3472
- && a.byteOffset === b.byteOffset
3473
- && a.byteLength === b.byteLength;
3474
- }
3475
- function hasExplicitMipmaps(texture, label = 'texture') {
3476
- const mipmaps = texture?.mipmaps;
3477
- if (mipmaps == null)
3478
- return false;
3479
- if (!Array.isArray(mipmaps)) {
3480
- throw new TypeError(`${label}.mipmaps must be an array of image-like mip levels.`);
3481
- }
3482
- return mipmaps.length > 0;
3483
- }
3484
- function assertNoEncodedExplicitMipmaps(map, label) {
3485
- if (!hasExplicitMipmaps(map, label))
3486
- return;
3487
- throw new Error(`${label} provides explicit texture mipmaps with an encoded base image. Explicit mipmap upload requires raw DataTexture-style base image data with raw mipmap levels.`);
3488
- }
3489
- function assertNoEncodedPremultiplyAlpha(map, label) {
3490
- if (optionalTextureBoolean(map.premultiplyAlpha, `${label}.premultiplyAlpha`) !== true)
3491
- return;
3492
- throw new Error(`${label}.premultiplyAlpha is only supported for readable raw texture image data. Decode the encoded image to raw RGBA DataTexture-style data before rendering.`);
3493
- }
3494
- function textureBytesWithExplicitMipmaps(map, label, baseRgba, width, height) {
3495
- const premultiplyAlpha = optionalTextureBoolean(map.premultiplyAlpha, `${label}.premultiplyAlpha`) === true;
3496
- const baseLevel = premultiplyAlpha ? premultiplyRgbaAlpha(baseRgba) : baseRgba;
3497
- if (!hasExplicitMipmaps(map, label))
3498
- return baseLevel;
3499
- if (width <= 1 && height <= 1) {
3500
- throw new Error(`${label} provides explicit texture mipmaps for a ${width}x${height} base image, but no additional mip levels are valid after the 1x1 level.`);
3501
- }
3502
- const levels = [
3503
- baseLevel instanceof Uint8Array
3504
- ? new Uint8Array(baseLevel.buffer, baseLevel.byteOffset, baseLevel.byteLength)
3505
- : new Uint8Array(baseLevel),
3506
- ];
3507
- let expectedWidth = width;
3508
- let expectedHeight = height;
3509
- const mipmaps = map.mipmaps;
3510
- for (let i = 0; i < mipmaps.length; i += 1) {
3511
- expectedWidth = Math.max(1, Math.floor(expectedWidth / 2));
3512
- expectedHeight = Math.max(1, Math.floor(expectedHeight / 2));
3513
- const mip = mipmaps[i];
3514
- if (!mip || !mip.data || mip.width !== expectedWidth || mip.height !== expectedHeight) {
3515
- throw new Error(`${label}.mipmaps[${i}] must provide raw pixel data with size ${expectedWidth}x${expectedHeight} for explicit mipmap upload.`);
3516
- }
3517
- const rgba = toRgba8(mip.data, expectedWidth, expectedHeight, { type: map.type, format: map.format });
3518
- if (!rgba) {
3519
- throw unsupportedRawTextureDataError(`${label}.mipmaps[${i}]`, 'texture rendering');
3520
- }
3521
- levels.push(premultiplyAlpha ? premultiplyRgbaAlpha(rgba) : rgba);
3522
- if (expectedWidth === 1 && expectedHeight === 1 && i < mipmaps.length - 1) {
3523
- throw new Error(`${label} provides extra explicit mipmap levels after the 1x1 level.`);
3524
- }
3525
- }
3526
- if (expectedWidth !== 1 || expectedHeight !== 1) {
3527
- throw new Error(`${label} explicit texture mipmaps must include the complete mip chain down to 1x1.`);
3528
- }
3529
- const byteLength = levels.reduce((total, level) => total + level.byteLength, 0);
3530
- const out = new Uint8Array(byteLength);
3531
- let offset = 0;
3532
- for (const level of levels) {
3533
- out.set(level, offset);
3534
- offset += level.byteLength;
3535
- }
3536
- return out;
3537
- }
3538
- function unsupportedRawTextureDataError(label, usage) {
3539
- const supported = 'one-channel, two-channel, RGB, or RGBA numeric pixel data';
3540
- const expected = 'mismatched data lengths must match width * height texels, width * height * 2 values, width * height * 3 values, or width * height * 4 values; packed color types use one value per texel';
3541
- return new Error(`${label} raw texture data must contain ${supported} for ${usage}; ${expected}.`);
3542
- }
3543
- function unsupportedTextureImageError(label, usage) {
3544
- return new Error(`${label} uses a texture image object that is not readable or drawable by @headless-three/renderer for ${usage}. Provide encoded PNG/JPEG/WebP bytes directly as texture.image or texture.source.data, a canvas-like object with getContext("2d").getImageData(), an image-like object drawable through an available OffscreenCanvas/2D canvas polyfill, or raw one-channel, two-channel, RGB, or RGBA numeric pixel data as { data, width, height } before rendering.`);
3545
- }
3546
- function assertSupportedRawTextureType(type, label, usage) {
3547
- if (type == null ||
3548
- type === UnsignedByteType ||
3549
- type === ByteType ||
3550
- type === ShortType ||
3551
- type === UnsignedShortType ||
3552
- type === IntType ||
3553
- type === UnsignedIntType ||
3554
- type === HalfFloatType ||
3555
- type === FloatType ||
3556
- type === UnsignedShort4444Type ||
3557
- type === UnsignedShort5551Type ||
3558
- type === UnsignedInt5999Type ||
3559
- type === UnsignedInt101111Type) {
3560
- return;
3561
- }
3562
- throw new Error(`${label} raw texture type ${textureTypeName(type)} is not supported by @headless-three/renderer for ${usage}. Use UnsignedByteType, ByteType, ShortType, UnsignedShortType, IntType, UnsignedIntType, HalfFloatType, FloatType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt5999Type, or UnsignedInt101111Type raw data, or pre-convert the texture to RGBA8 before rendering.`);
3563
- }
3564
- function textureTypeName(type) {
3565
- switch (type) {
3566
- case ByteType:
3567
- return 'ByteType';
3568
- case ShortType:
3569
- return 'ShortType';
3570
- case IntType:
3571
- return 'IntType';
3572
- case UnsignedInt248Type:
3573
- return 'UnsignedInt248Type';
3574
- case UnsignedInt5999Type:
3575
- return 'UnsignedInt5999Type';
3576
- case UnsignedInt101111Type:
3577
- return 'UnsignedInt101111Type';
3578
- default:
3579
- return String(type);
3580
- }
3581
- }
3582
- function rawTextureChannelCount(data, width, height, label, usage) {
3583
- const pixels = width * height;
3584
- const length = typeof data.length === 'number' ? data.length : Number.NaN;
3585
- const channels = length / pixels;
3586
- if (channels === 1 || channels === 2 || channels === 3 || channels === 4)
3587
- return channels;
3588
- throw unsupportedRawTextureDataError(label, usage);
3589
- }
3590
- function rawHalfFloatTextureDataToRgba(rawData, width, height, label, usage, options = {}) {
3591
- const channels = rawTextureChannelCount(rawData, width, height, label, usage);
3592
- if (channels === 4) {
3593
- const data = options.premultiplyAlpha === true ? premultiplyHalfFloatRgba(rawData) : rawData;
3594
- return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
3595
- }
3596
- const pixels = width * height;
3597
- const out = new Uint16Array(pixels * 4);
3598
- for (let i = 0; i < pixels; i += 1) {
3599
- if (channels === 1) {
3600
- writeOneChannelRawRgba(out, i, rawData[i], 0x3C00, options.format);
3601
- }
3602
- else if (channels === 2) {
3603
- writeTwoChannelRawRgba(out, i, rawData[i * channels], rawData[i * channels + 1], 0x3C00, options.format);
3604
- }
3605
- else {
3606
- out[i * 4] = rawData[i * channels];
3607
- out[i * 4 + 1] = rawData[i * channels + 1];
3608
- out[i * 4 + 2] = rawData[i * channels + 2];
3609
- out[i * 4 + 3] = 0x3C00;
3610
- }
3611
- }
3612
- const data = options.premultiplyAlpha === true ? premultiplyHalfFloatRgba(out) : out;
3613
- return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
3614
- }
3615
- function rawFloatTextureDataToRgba(rawData, width, height, label, usage, options = {}) {
3616
- const channels = rawTextureChannelCount(rawData, width, height, label, usage);
3617
- if (channels === 4) {
3618
- const data = options.premultiplyAlpha === true ? premultiplyFloatRgba(rawData) : rawData;
3619
- return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
3620
- }
3621
- const pixels = width * height;
3622
- const out = new Float32Array(pixels * 4);
3623
- for (let i = 0; i < pixels; i += 1) {
3624
- if (channels === 1) {
3625
- writeOneChannelRawRgba(out, i, rawData[i], 1.0, options.format);
3626
- }
3627
- else if (channels === 2) {
3628
- writeTwoChannelRawRgba(out, i, rawData[i * channels], rawData[i * channels + 1], 1.0, options.format);
3629
- }
3630
- else {
3631
- out[i * 4] = rawData[i * channels];
3632
- out[i * 4 + 1] = rawData[i * channels + 1];
3633
- out[i * 4 + 2] = rawData[i * channels + 2];
3634
- out[i * 4 + 3] = 1.0;
3635
- }
3636
- }
3637
- const data = options.premultiplyAlpha === true ? premultiplyFloatRgba(out) : out;
3638
- return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
3639
- }
3640
- function writeOneChannelRawRgba(out, pixelIndex, value, opaqueAlpha, format) {
3641
- const offset = pixelIndex * 4;
3642
- out[offset] = value;
3643
- out[offset + 1] = value;
3644
- out[offset + 2] = value;
3645
- out[offset + 3] = format === AlphaFormat ? value : opaqueAlpha;
3646
- }
3647
- function writeTwoChannelRawRgba(out, pixelIndex, first, second, opaqueAlpha, format) {
3648
- const offset = pixelIndex * 4;
3649
- if (format === LuminanceAlphaFormat) {
3650
- out[offset] = first;
3651
- out[offset + 1] = first;
3652
- out[offset + 2] = first;
3653
- out[offset + 3] = second;
3654
- return;
3655
- }
3656
- out[offset] = first;
3657
- out[offset + 1] = second;
3658
- out[offset + 2] = 0;
3659
- out[offset + 3] = opaqueAlpha;
3660
- }
3661
- function assertSupportedBackgroundTexture(map, label) {
3662
- assertSupportedTextureInput(map, label, { allowMipmaps: true });
3663
- if (map.isCubeTexture === true ||
3664
- map.mapping === CubeReflectionMapping ||
3665
- map.mapping === CubeRefractionMapping ||
3666
- map.mapping === CubeUVReflectionMapping) {
3667
- throw new Error(`${label} uses a cube or PMREM/CubeUV texture mapping in a 2D background texture path. Use a readable six-face CubeTexture, a 2D/equirectangular texture, or pre-render the background to a 2D image before rendering.`);
3668
- }
3669
- }
3670
- function assertSupportedTwoDimensionalTextureSlot(map, label) {
3671
- if (map.isCubeTexture === true ||
3672
- map.mapping === CubeReflectionMapping ||
3673
- map.mapping === CubeRefractionMapping ||
3674
- map.mapping === CubeUVReflectionMapping) {
3675
- throw new Error(`${label} uses a cube or PMREM/CubeUV texture mapping, which is not supported for 2D material texture slots. Use a 2D texture for material maps or move cube textures to scene.environment, scene.background, or material.envMap where supported.`);
3676
- }
3677
- }
3678
- function isRefractionEnvironmentMapping(mapping) {
3679
- return mapping === CubeRefractionMapping || mapping === EquirectangularRefractionMapping;
3680
- }
3681
- function assertSupportedEnvironmentTexture(map, label, options = {}) {
3682
- assertSupportedTextureInput(map, label);
3683
- const usesRefraction = isRefractionEnvironmentMapping(map.mapping);
3684
- if (usesRefraction && options.allowRefraction !== true) {
3685
- throw new Error(`${label} uses refraction environment mapping, which is not supported by @headless-three/renderer yet. Provide an equirectangular or six-face cube reflection texture and let the renderer precompute IBL, or pre-convert the source before rendering.`);
3686
- }
3687
- if (map.mapping === CubeUVReflectionMapping && !isCubeEnvironmentTexture(map, label)) {
3688
- throw new Error(`${label} uses PMREM/CubeUV environment mapping without readable six-face cube images, which is not supported by @headless-three/renderer yet. Provide a CubeUV-mapped CubeTexture, an equirectangular texture, or a six-face cube reflection texture and let the renderer precompute IBL.`);
3689
- }
3690
- }
3691
- function assertSupportedTextureInput(map, label, options = {}) {
3692
- if (map.isFramebufferTexture === true) {
3693
- throw new Error(`${label} uses a FramebufferTexture, which is not supported by @headless-three/renderer texture slots. Copy framebuffer output into a readable raw texture with Renderer.copyFramebufferToTexture(), or render into a target-like object and use its color texture data.`);
3694
- }
3695
- if (map.isDepthTexture === true) {
3696
- throw new Error(`${label} uses a DepthTexture, which is only supported as target.depthTexture for render-target depth readback. Use a readable color texture for material, background, or environment slots.`);
3697
- }
3698
- if (map.isVideoTexture === true) {
3699
- throw new Error(`${label} uses a VideoTexture, which is not supported by @headless-three/renderer in Node because live video frames are not directly readable. Provide a canvas-like image exposing getContext("2d").getImageData(), an encoded image, or raw DataTexture pixels before rendering.`);
3700
- }
3701
- if (map.isStorageTexture === true) {
3702
- throw new Error(`${label} uses a StorageTexture, which is not supported by @headless-three/renderer texture slots because WebGPU storage texture backing data is not directly readable. Provide a readable raw, encoded, or canvas-like texture before rendering.`);
3703
- }
3704
- if (map.isCompressedTexture === true ||
3705
- map.isCompressedArrayTexture === true ||
3706
- map.isCompressedCubeTexture === true) {
3707
- throw new Error(`${label} uses a compressed texture. KTX2, Basis, and THREE.CompressedTexture inputs are not decoded by @headless-three/renderer yet; pre-decode the texture to RGBA data or an encoded PNG/JPEG/WebP image before rendering.`);
3708
- }
3709
- if (isCompressedTextureFormat(map.format)) {
3710
- throw new Error(`${label} uses a compressed texture format. KTX2, Basis, and compressed texture formats are not decoded by @headless-three/renderer yet; pre-decode the texture to RGBA data or an encoded PNG/JPEG/WebP image before rendering.`);
3711
- }
3712
- if (map.isDataArrayTexture === true ||
3713
- map.isData3DTexture === true ||
3714
- map.isArrayTexture === true ||
3715
- map.is3DTexture === true) {
3716
- throw new Error(`${label} uses an array or 3D texture, which is not supported by @headless-three/renderer yet. Provide a 2D texture image for this slot or render each layer separately.`);
3717
- }
3718
- if (!options.allowMipmaps && hasExplicitMipmaps(map, label)) {
3719
- throw new Error(`${label} provides explicit texture mipmaps, which are not uploaded by @headless-three/renderer yet. Provide only the base image level or prefilter/downsample the texture before rendering.`);
3720
- }
3721
- }
3722
- function assertCompatiblePackedPhysicalMapSamplers(material, features) {
3723
- const scalarSlots = activePackedPhysicalScalarMapSlots(material, features);
3724
- const sheenSlots = features.sheen
3725
- ? [
3726
- ['sheenColorMap', material.sheenColorMap],
3727
- ['sheenRoughnessMap', material.sheenRoughnessMap],
3728
- ]
3729
- : [];
3730
- assertNoPackedPhysicalMapMipmaps('physical extension scalar maps', scalarSlots);
3731
- assertNoPackedPhysicalMapMipmaps('physical extension sheen maps', sheenSlots);
3732
- assertNoPackedPhysicalMapMipmaps('physical extension specular maps', [
3733
- ['specularColorMap', material.specularColorMap],
3734
- ['specularIntensityMap', material.specularIntensityMap],
3735
- ]);
3736
- assertMatchingSamplerSettings('physical extension scalar maps', scalarSlots);
3737
- assertMatchingSamplerSettings('physical extension sheen maps', sheenSlots);
3738
- assertMatchingSamplerSettings('physical extension specular maps', [
3739
- ['specularColorMap', material.specularColorMap],
3740
- ['specularIntensityMap', material.specularIntensityMap],
3741
- ]);
3742
- }
3743
- function activePackedPhysicalScalarMapSlots(material, features) {
3744
- const slots = [];
3745
- if (features.clearcoat) {
3746
- slots.push(['clearcoatMap', material.clearcoatMap], ['clearcoatRoughnessMap', material.clearcoatRoughnessMap]);
3747
- }
3748
- if (features.transmission) {
3749
- slots.push(['transmissionMap', material.transmissionMap], ['thicknessMap', material.thicknessMap]);
3750
- }
3751
- if (features.anisotropy) {
3752
- slots.push(['anisotropyMap', material.anisotropyMap]);
3753
- }
3754
- if (features.iridescence) {
3755
- slots.push(['iridescenceMap', material.iridescenceMap], ['iridescenceThicknessMap', material.iridescenceThicknessMap]);
3756
- }
3757
- return slots;
3758
- }
3759
- function assertNoPackedPhysicalMapMipmaps(groupLabel, slots) {
3760
- for (const [label, texture] of slots) {
3761
- if (!texture || !hasExplicitMipmaps(texture, `material.${label}`))
3762
- continue;
3763
- throw new Error(`${groupLabel} are packed into one native texture, and explicit mipmaps for ${label} are not supported by @headless-three/renderer yet. Remove texture.mipmaps from packed physical-extension maps or rely on generated mipmaps from the packed base level.`);
3764
- }
3765
- }
3766
- function assertMatchingSamplerSettings(groupLabel, slots) {
3767
- let first = null;
3768
- for (const [label, texture] of slots) {
3769
- if (!texture)
3770
- continue;
3771
- const signature = samplerSignature(texture, `material.${label}`);
3772
- if (!first) {
3773
- first = { label, signature };
3774
- continue;
3775
- }
3776
- if (signature !== first.signature) {
3777
- throw new Error(`${groupLabel} are packed into one native texture and must use matching wrap/filter/anisotropy sampler settings. ${label} differs from ${first.label}; use matching wrapS/wrapT/magFilter/minFilter/anisotropy values or render separate passes until independent packed-channel samplers are supported.`);
3778
- }
3779
- }
3780
- }
3781
- function samplerSignature(texture, label) {
3782
- return [
3783
- wrapModeToString(texture.wrapS) ?? 'clamp',
3784
- wrapModeToString(texture.wrapT) ?? 'clamp',
3785
- filterModeToString(texture.magFilter) ?? 'linear',
3786
- minFilterModeToString(texture) ?? 'linear',
3787
- String(textureAnisotropy(texture, label) ?? 1),
3788
- ].join('|');
3789
- }
3790
- function textureAnisotropy(map, label) {
3791
- const value = map?.anisotropy;
3792
- if (value == null)
3793
- return undefined;
3794
- if (typeof value !== 'number' || !Number.isFinite(value)) {
3795
- throw new TypeError(`${label}.anisotropy must be a finite number.`);
3796
- }
3797
- if (value <= 1)
3798
- return undefined;
3799
- return Math.max(1, Math.min(16, Math.floor(value)));
3800
- }
3801
- function textureUnpackAlignment(map, label) {
3802
- const value = map?.unpackAlignment;
3803
- if (value == null)
3804
- return undefined;
3805
- if (!Number.isInteger(value)) {
3806
- throw new TypeError(`${label}.unpackAlignment must be an integer.`);
3807
- }
3808
- if (value === 1 || value === 2 || value === 4 || value === 8)
3809
- return value;
3810
- throw new Error(`${label}.unpackAlignment ${value} is not supported by @headless-three/renderer. Use 1, 2, 4, or 8.`);
3811
- }
3812
- function textureTransform(map, label) {
3813
- const flipY = optionalTextureBoolean(map?.flipY, `${label}.flipY`) !== false;
3814
- const flipTransform = flipY ? undefined : [1, 0, 0, 0, -1, 1];
3815
- if (!map)
3816
- return flipTransform;
3817
- const matrixAutoUpdate = optionalTextureBoolean(map.matrixAutoUpdate, `${label}.matrixAutoUpdate`);
3818
- if (matrixAutoUpdate === false) {
3819
- const e = map.matrix?.elements;
3820
- if (!e || e.length !== 9) {
3821
- throw new TypeError(`${label}.matrix.elements must contain nine finite numbers.`);
3822
- }
3823
- validateFiniteMatrix3(e, `${label}.matrix.elements`);
3824
- return composeTextureTransformWithFlipY([e[0], e[3], e[6], e[1], e[4], e[7]], flipY);
3825
- }
3826
- const tx = textureVector2Component(map.offset, `${label}.offset`, 'x', 0);
3827
- const ty = textureVector2Component(map.offset, `${label}.offset`, 'y', 0);
3828
- const sx = textureVector2Component(map.repeat, `${label}.repeat`, 'x', 1);
3829
- const sy = textureVector2Component(map.repeat, `${label}.repeat`, 'y', 1);
3830
- const rotation = finiteTextureTransformNumber(map.rotation, `${label}.rotation`, 0);
3831
- const cx = textureVector2Component(map.center, `${label}.center`, 'x', 0);
3832
- const cy = textureVector2Component(map.center, `${label}.center`, 'y', 0);
3833
- if (tx === 0 && ty === 0 && sx === 1 && sy === 1 && rotation === 0 && cx === 0 && cy === 0) {
3834
- return flipTransform;
3835
- }
3836
- const c = Math.cos(rotation);
3837
- const s = Math.sin(rotation);
3838
- return composeTextureTransformWithFlipY([
3839
- sx * c,
3840
- sx * s,
3841
- -sx * (c * cx + s * cy) + cx + tx,
3842
- -sy * s,
3843
- sy * c,
3844
- -sy * (-s * cx + c * cy) + cy + ty,
3845
- ], flipY);
3846
- }
3847
- function composeTextureTransformWithFlipY(transform, flipY) {
3848
- if (flipY)
3849
- return transform;
3850
- const [a, c, tx, b, d, ty] = transform;
3851
- return [a, -c, c + tx, b, -d, d + ty];
3852
- }
3853
- function optionalTextureBoolean(value, label) {
3854
- if (value == null)
3855
- return undefined;
3856
- if (typeof value === 'boolean')
3857
- return value;
3858
- throw new TypeError(`${label} must be a boolean.`);
3859
- }
3860
- function textureVector2Component(value, label, component, fallback) {
3861
- if (value == null)
3862
- return fallback;
3863
- if (typeof value !== 'object' || Array.isArray(value)) {
3864
- throw new TypeError(`${label} must be a vector-like object.`);
3865
- }
3866
- return finiteTextureTransformNumber(value[component], `${label}.${component}`, fallback);
3867
- }
3868
- function textureColorSpace(map) {
3869
- if (!map)
3870
- return undefined;
3871
- if (map.colorSpace === 'srgb')
3872
- return 'srgb';
3873
- if (map.colorSpace === 'srgb-linear' ||
3874
- map.colorSpace === 'linear-srgb' ||
3875
- map.colorSpace === 'linearsrgb' ||
3876
- map.colorSpace === 'linear') {
3877
- return 'linear';
3878
- }
3879
- if (map.colorSpace != null && map.colorSpace !== '') {
3880
- throw new Error(`texture.colorSpace ${String(map.colorSpace)} is not supported by @headless-three/renderer. Use THREE.SRGBColorSpace, THREE.LinearSRGBColorSpace, or THREE.NoColorSpace.`);
3881
- }
3882
- if (map.encoding === sRGBEncoding)
3883
- return 'srgb';
3884
- if (map.encoding != null && map.encoding !== LinearEncoding) {
3885
- throw new Error(`texture.encoding ${String(map.encoding)} is not supported by @headless-three/renderer. Use sRGBEncoding, LinearEncoding, or texture.colorSpace with THREE.SRGBColorSpace/THREE.LinearSRGBColorSpace.`);
3886
- }
3887
- return undefined;
3888
- }
3889
- function finiteOrDefault(value, fallback) {
3890
- return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
3891
- }
3892
- function finiteTextureTransformNumber(value, label, fallback) {
3893
- if (value == null)
3894
- return fallback;
3895
- if (typeof value === 'number' && Number.isFinite(value))
3896
- return value;
3897
- throw new TypeError(`${label} must be a finite number.`);
3898
- }
3899
- function validateFiniteMatrix3(values, label) {
3900
- for (let i = 0; i < 9; i += 1) {
3901
- if (typeof values[i] !== 'number' || !Number.isFinite(values[i])) {
3902
- throw new TypeError(`${label}[${i}] must be a finite number.`);
3903
- }
3904
- }
3905
- }
3906
- function toRgba8(data, width, height, options = {}) {
3907
- const pixels = width * height;
3908
- const allowNarrowChannels = options.narrowChannels !== false;
3909
- const textureType = options.type ?? UnsignedByteType;
3910
- const textureFormat = options.format;
3911
- if (textureType === HalfFloatType) {
3912
- if (!(data instanceof Uint16Array))
3913
- return null;
3914
- return halfFloatDataToRgba8(data, pixels, allowNarrowChannels, textureFormat);
3915
- }
3916
- if (textureType === ByteType) {
3917
- if (!(data instanceof Int8Array))
3918
- return null;
3919
- return normalizedSignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, 0x7f, textureFormat);
3920
- }
3921
- if (textureType === ShortType) {
3922
- if (!(data instanceof Int16Array))
3923
- return null;
3924
- return normalizedSignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, 0x7fff, textureFormat);
3925
- }
3926
- if (textureType === UnsignedShortType) {
3927
- if (!(data instanceof Uint16Array))
3928
- return null;
3929
- return normalizedUnsignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, 0xffff, textureFormat);
3930
- }
3931
- if (textureType === IntType) {
3932
- if (!(data instanceof Int32Array))
3933
- return null;
3934
- return normalizedSignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, 0x7fffffff, textureFormat);
3935
- }
3936
- if (textureType === UnsignedIntType) {
3937
- if (!(data instanceof Uint32Array))
3938
- return null;
3939
- return normalizedUnsignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, 0xffffffff, textureFormat);
3940
- }
3941
- if (textureType === UnsignedInt5999Type) {
3942
- if (!(data instanceof Uint32Array))
3943
- return null;
3944
- return packedUnsignedInt5999ToRgba8(data, pixels);
3945
- }
3946
- if (textureType === UnsignedInt101111Type) {
3947
- if (!(data instanceof Uint32Array))
3948
- return null;
3949
- return packedUnsignedInt101111ToRgba8(data, pixels);
3950
- }
3951
- if (textureType === UnsignedShort4444Type) {
3952
- if (!(data instanceof Uint16Array))
3953
- return null;
3954
- return packedUnsignedShort4444ToRgba8(data, pixels);
3955
- }
3956
- if (textureType === UnsignedShort5551Type) {
3957
- if (!(data instanceof Uint16Array))
3958
- return null;
3959
- return packedUnsignedShort5551ToRgba8(data, pixels);
3960
- }
3961
- if (data instanceof Uint8Array || data instanceof Uint8ClampedArray) {
3962
- if (data.length === pixels * 4)
3963
- return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
3964
- if (data.length === pixels * 3) {
3965
- const out = new Uint8Array(pixels * 4);
3966
- for (let i = 0; i < pixels; i++) {
3967
- out[i * 4] = data[i * 3];
3968
- out[i * 4 + 1] = data[i * 3 + 1];
3969
- out[i * 4 + 2] = data[i * 3 + 2];
3970
- out[i * 4 + 3] = 255;
3971
- }
3972
- return out;
3973
- }
3974
- if (allowNarrowChannels && data.length === pixels * 2) {
3975
- const out = new Uint8Array(pixels * 4);
3976
- for (let i = 0; i < pixels; i++) {
3977
- writeTwoChannelRgba8(out, i, data[i * 2], data[i * 2 + 1], textureFormat);
3978
- }
3979
- return out;
3980
- }
3981
- if (allowNarrowChannels && data.length === pixels) {
3982
- const out = new Uint8Array(pixels * 4);
3983
- for (let i = 0; i < pixels; i++) {
3984
- writeOneChannelRgba8(out, i, data[i], textureFormat);
3985
- }
3986
- return out;
3987
- }
3988
- return null;
3989
- }
3990
- if (data instanceof Float32Array || data instanceof Float64Array) {
3991
- if (data.length === pixels * 4) {
3992
- const out = new Uint8Array(pixels * 4);
3993
- for (let i = 0; i < pixels * 4; i++) {
3994
- out[i] = Math.max(0, Math.min(255, Math.round(data[i] * 255)));
3995
- }
3996
- return out;
3997
- }
3998
- if (data.length === pixels * 3) {
3999
- const out = new Uint8Array(pixels * 4);
4000
- for (let i = 0; i < pixels; i++) {
4001
- out[i * 4] = Math.max(0, Math.min(255, Math.round(data[i * 3] * 255)));
4002
- out[i * 4 + 1] = Math.max(0, Math.min(255, Math.round(data[i * 3 + 1] * 255)));
4003
- out[i * 4 + 2] = Math.max(0, Math.min(255, Math.round(data[i * 3 + 2] * 255)));
4004
- out[i * 4 + 3] = 255;
4005
- }
4006
- return out;
4007
- }
4008
- if (allowNarrowChannels && data.length === pixels * 2) {
4009
- const out = new Uint8Array(pixels * 4);
4010
- for (let i = 0; i < pixels; i++) {
4011
- writeTwoChannelRgba8(out, i, Math.max(0, Math.min(255, Math.round(data[i * 2] * 255))), Math.max(0, Math.min(255, Math.round(data[i * 2 + 1] * 255))), textureFormat);
4012
- }
4013
- return out;
4014
- }
4015
- if (allowNarrowChannels && data.length === pixels) {
4016
- const out = new Uint8Array(pixels * 4);
4017
- for (let i = 0; i < pixels; i++) {
4018
- const value = Math.max(0, Math.min(255, Math.round(data[i] * 255)));
4019
- writeOneChannelRgba8(out, i, value, textureFormat);
4020
- }
4021
- return out;
4022
- }
4023
- return null;
4024
- }
4025
- // Uint16Array or other numeric typed arrays — treat as 8-bit range after clamping
4026
- if (ArrayBuffer.isView(data)) {
4027
- if (data.length === pixels * 4) {
4028
- const out = new Uint8Array(pixels * 4);
4029
- for (let i = 0; i < pixels * 4; i++) {
4030
- out[i] = Math.max(0, Math.min(255, data[i]));
4031
- }
4032
- return out;
4033
- }
4034
- if (data.length === pixels * 3) {
4035
- const out = new Uint8Array(pixels * 4);
4036
- for (let i = 0; i < pixels; i++) {
4037
- out[i * 4] = Math.max(0, Math.min(255, data[i * 3]));
4038
- out[i * 4 + 1] = Math.max(0, Math.min(255, data[i * 3 + 1]));
4039
- out[i * 4 + 2] = Math.max(0, Math.min(255, data[i * 3 + 2]));
4040
- out[i * 4 + 3] = 255;
4041
- }
4042
- return out;
4043
- }
4044
- if (allowNarrowChannels && data.length === pixels * 2) {
4045
- const out = new Uint8Array(pixels * 4);
4046
- for (let i = 0; i < pixels; i++) {
4047
- writeTwoChannelRgba8(out, i, Math.max(0, Math.min(255, data[i * 2])), Math.max(0, Math.min(255, data[i * 2 + 1])), textureFormat);
4048
- }
4049
- return out;
4050
- }
4051
- if (allowNarrowChannels && data.length === pixels) {
4052
- const out = new Uint8Array(pixels * 4);
4053
- for (let i = 0; i < pixels; i++) {
4054
- const value = Math.max(0, Math.min(255, data[i]));
4055
- writeOneChannelRgba8(out, i, value, textureFormat);
4056
- }
4057
- return out;
4058
- }
4059
- }
4060
- if (data.length === pixels * 4) {
4061
- const out = new Uint8Array(pixels * 4);
4062
- for (let i = 0; i < pixels * 4; i++) {
4063
- out[i] = Math.max(0, Math.min(255, data[i]));
4064
- }
4065
- return out;
4066
- }
4067
- if (data.length === pixels * 3) {
4068
- const out = new Uint8Array(pixels * 4);
4069
- for (let i = 0; i < pixels; i++) {
4070
- out[i * 4] = Math.max(0, Math.min(255, data[i * 3]));
4071
- out[i * 4 + 1] = Math.max(0, Math.min(255, data[i * 3 + 1]));
4072
- out[i * 4 + 2] = Math.max(0, Math.min(255, data[i * 3 + 2]));
4073
- out[i * 4 + 3] = 255;
4074
- }
4075
- return out;
4076
- }
4077
- if (allowNarrowChannels && data.length === pixels * 2) {
4078
- const out = new Uint8Array(pixels * 4);
4079
- for (let i = 0; i < pixels; i++) {
4080
- writeTwoChannelRgba8(out, i, Math.max(0, Math.min(255, data[i * 2])), Math.max(0, Math.min(255, data[i * 2 + 1])), textureFormat);
4081
- }
4082
- return out;
4083
- }
4084
- if (allowNarrowChannels && data.length === pixels) {
4085
- const out = new Uint8Array(pixels * 4);
4086
- for (let i = 0; i < pixels; i++) {
4087
- const value = Math.max(0, Math.min(255, data[i]));
4088
- writeOneChannelRgba8(out, i, value, textureFormat);
4089
- }
4090
- return out;
4091
- }
4092
- return null;
4093
- }
4094
- function normalizedUnsignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, maxValue, format) {
4095
- if (data.length === pixels * 4) {
4096
- const out = new Uint8Array(pixels * 4);
4097
- for (let i = 0; i < pixels * 4; i++) {
4098
- out[i] = normalizedUnsignedIntegerToByte(data[i], maxValue);
4099
- }
4100
- return out;
4101
- }
4102
- if (data.length === pixels * 3) {
4103
- const out = new Uint8Array(pixels * 4);
4104
- for (let i = 0; i < pixels; i++) {
4105
- out[i * 4] = normalizedUnsignedIntegerToByte(data[i * 3], maxValue);
4106
- out[i * 4 + 1] = normalizedUnsignedIntegerToByte(data[i * 3 + 1], maxValue);
4107
- out[i * 4 + 2] = normalizedUnsignedIntegerToByte(data[i * 3 + 2], maxValue);
4108
- out[i * 4 + 3] = 255;
4109
- }
4110
- return out;
4111
- }
4112
- if (allowNarrowChannels && data.length === pixels * 2) {
4113
- const out = new Uint8Array(pixels * 4);
4114
- for (let i = 0; i < pixels; i++) {
4115
- writeTwoChannelRgba8(out, i, normalizedUnsignedIntegerToByte(data[i * 2], maxValue), normalizedUnsignedIntegerToByte(data[i * 2 + 1], maxValue), format);
4116
- }
4117
- return out;
4118
- }
4119
- if (allowNarrowChannels && data.length === pixels) {
4120
- const out = new Uint8Array(pixels * 4);
4121
- for (let i = 0; i < pixels; i++) {
4122
- const value = normalizedUnsignedIntegerToByte(data[i], maxValue);
4123
- writeOneChannelRgba8(out, i, value, format);
4124
- }
4125
- return out;
4126
- }
4127
- return null;
4128
- }
4129
- function normalizedUnsignedIntegerToByte(value, maxValue) {
4130
- return Math.max(0, Math.min(255, Math.round((value / maxValue) * 255)));
4131
- }
4132
- function normalizedSignedIntegerDataToRgba8(data, pixels, allowNarrowChannels, maxValue, format) {
4133
- if (data.length === pixels * 4) {
4134
- const out = new Uint8Array(pixels * 4);
4135
- for (let i = 0; i < pixels * 4; i++) {
4136
- out[i] = normalizedSignedIntegerToByte(data[i], maxValue);
4137
- }
4138
- return out;
4139
- }
4140
- if (data.length === pixels * 3) {
4141
- const out = new Uint8Array(pixels * 4);
4142
- for (let i = 0; i < pixels; i++) {
4143
- out[i * 4] = normalizedSignedIntegerToByte(data[i * 3], maxValue);
4144
- out[i * 4 + 1] = normalizedSignedIntegerToByte(data[i * 3 + 1], maxValue);
4145
- out[i * 4 + 2] = normalizedSignedIntegerToByte(data[i * 3 + 2], maxValue);
4146
- out[i * 4 + 3] = 255;
4147
- }
4148
- return out;
4149
- }
4150
- if (allowNarrowChannels && data.length === pixels * 2) {
4151
- const out = new Uint8Array(pixels * 4);
4152
- for (let i = 0; i < pixels; i++) {
4153
- writeTwoChannelRgba8(out, i, normalizedSignedIntegerToByte(data[i * 2], maxValue), normalizedSignedIntegerToByte(data[i * 2 + 1], maxValue), format);
4154
- }
4155
- return out;
4156
- }
4157
- if (allowNarrowChannels && data.length === pixels) {
4158
- const out = new Uint8Array(pixels * 4);
4159
- for (let i = 0; i < pixels; i++) {
4160
- const value = normalizedSignedIntegerToByte(data[i], maxValue);
4161
- writeOneChannelRgba8(out, i, value, format);
4162
- }
4163
- return out;
4164
- }
4165
- return null;
4166
- }
4167
- function normalizedSignedIntegerToByte(value, maxValue) {
4168
- return Math.max(0, Math.min(255, Math.round((Math.max(value, 0) / maxValue) * 255)));
4169
- }
4170
- function packedUnsignedShort4444ToRgba8(data, pixels) {
4171
- if (data.length !== pixels)
4172
- return null;
4173
- const out = new Uint8Array(pixels * 4);
4174
- for (let i = 0; i < pixels; i++) {
4175
- const value = data[i];
4176
- out[i * 4] = ((value >> 12) & 0xf) * 17;
4177
- out[i * 4 + 1] = ((value >> 8) & 0xf) * 17;
4178
- out[i * 4 + 2] = ((value >> 4) & 0xf) * 17;
4179
- out[i * 4 + 3] = (value & 0xf) * 17;
4180
- }
4181
- return out;
4182
- }
4183
- function packedUnsignedShort5551ToRgba8(data, pixels) {
4184
- if (data.length !== pixels)
4185
- return null;
4186
- const out = new Uint8Array(pixels * 4);
4187
- for (let i = 0; i < pixels; i++) {
4188
- const value = data[i];
4189
- out[i * 4] = normalizedUnsignedIntegerToByte((value >> 11) & 0x1f, 0x1f);
4190
- out[i * 4 + 1] = normalizedUnsignedIntegerToByte((value >> 6) & 0x1f, 0x1f);
4191
- out[i * 4 + 2] = normalizedUnsignedIntegerToByte((value >> 1) & 0x1f, 0x1f);
4192
- out[i * 4 + 3] = (value & 0x1) === 1 ? 255 : 0;
4193
- }
4194
- return out;
4195
- }
4196
- function packedUnsignedInt5999ToRgba8(data, pixels) {
4197
- if (data.length !== pixels)
4198
- return null;
4199
- const out = new Uint8Array(pixels * 4);
4200
- for (let i = 0; i < pixels; i++) {
4201
- const value = data[i];
4202
- const scale = 2 ** (((value >>> 27) & 0x1f) - 24);
4203
- out[i * 4] = normalizedPackedRgb9E5ToByte(value & 0x1ff, scale);
4204
- out[i * 4 + 1] = normalizedPackedRgb9E5ToByte((value >>> 9) & 0x1ff, scale);
4205
- out[i * 4 + 2] = normalizedPackedRgb9E5ToByte((value >>> 18) & 0x1ff, scale);
4206
- out[i * 4 + 3] = 255;
4207
- }
4208
- return out;
4209
- }
4210
- function normalizedPackedRgb9E5ToByte(mantissa, scale) {
4211
- return Math.max(0, Math.min(255, Math.round(mantissa * scale * 255)));
4212
- }
4213
- function packedUnsignedInt101111ToRgba8(data, pixels) {
4214
- if (data.length !== pixels)
4215
- return null;
4216
- const out = new Uint8Array(pixels * 4);
4217
- for (let i = 0; i < pixels; i++) {
4218
- const value = data[i];
4219
- out[i * 4] = unsignedPackedFloatToByte(value & 0x7ff, 6);
4220
- out[i * 4 + 1] = unsignedPackedFloatToByte((value >>> 11) & 0x7ff, 6);
4221
- out[i * 4 + 2] = unsignedPackedFloatToByte((value >>> 22) & 0x3ff, 5);
4222
- out[i * 4 + 3] = 255;
4223
- }
4224
- return out;
4225
- }
4226
- function unsignedPackedFloatToByte(bits, mantissaBits) {
4227
- const exponent = bits >>> mantissaBits;
4228
- const mantissa = bits & ((1 << mantissaBits) - 1);
4229
- let value;
4230
- if (exponent === 0) {
4231
- value = (mantissa / (2 ** mantissaBits)) * (2 ** -14);
4232
- }
4233
- else if (exponent === 0x1f) {
4234
- value = mantissa === 0 ? Infinity : Number.NaN;
4235
- }
4236
- else {
4237
- value = (1 + mantissa / (2 ** mantissaBits)) * (2 ** (exponent - 15));
4238
- }
4239
- if (!Number.isFinite(value))
4240
- return value > 0 ? 255 : 0;
4241
- return Math.max(0, Math.min(255, Math.round(value * 255)));
4242
- }
4243
- function halfFloatDataToRgba8(data, pixels, allowNarrowChannels, format) {
4244
- if (data.length === pixels * 4) {
4245
- const out = new Uint8Array(pixels * 4);
4246
- for (let i = 0; i < pixels * 4; i++) {
4247
- out[i] = halfFloatToByte(data[i]);
4248
- }
4249
- return out;
4250
- }
4251
- if (data.length === pixels * 3) {
4252
- const out = new Uint8Array(pixels * 4);
4253
- for (let i = 0; i < pixels; i++) {
4254
- out[i * 4] = halfFloatToByte(data[i * 3]);
4255
- out[i * 4 + 1] = halfFloatToByte(data[i * 3 + 1]);
4256
- out[i * 4 + 2] = halfFloatToByte(data[i * 3 + 2]);
4257
- out[i * 4 + 3] = 255;
4258
- }
4259
- return out;
4260
- }
4261
- if (allowNarrowChannels && data.length === pixels * 2) {
4262
- const out = new Uint8Array(pixels * 4);
4263
- for (let i = 0; i < pixels; i++) {
4264
- writeTwoChannelRgba8(out, i, halfFloatToByte(data[i * 2]), halfFloatToByte(data[i * 2 + 1]), format);
4265
- }
4266
- return out;
4267
- }
4268
- if (allowNarrowChannels && data.length === pixels) {
4269
- const out = new Uint8Array(pixels * 4);
4270
- for (let i = 0; i < pixels; i++) {
4271
- const value = halfFloatToByte(data[i]);
4272
- writeOneChannelRgba8(out, i, value, format);
4273
- }
4274
- return out;
4275
- }
4276
- return null;
4277
- }
4278
- function writeOneChannelRgba8(out, pixelIndex, value, format) {
4279
- const offset = pixelIndex * 4;
4280
- out[offset] = value;
4281
- out[offset + 1] = value;
4282
- out[offset + 2] = value;
4283
- out[offset + 3] = format === AlphaFormat ? value : 255;
4284
- }
4285
- function writeTwoChannelRgba8(out, pixelIndex, first, second, format) {
4286
- const offset = pixelIndex * 4;
4287
- if (format === LuminanceAlphaFormat) {
4288
- out[offset] = first;
4289
- out[offset + 1] = first;
4290
- out[offset + 2] = first;
4291
- out[offset + 3] = second;
4292
- return;
4293
- }
4294
- out[offset] = first;
4295
- out[offset + 1] = second;
4296
- out[offset + 2] = 0;
4297
- out[offset + 3] = 255;
4298
- }
4299
- function halfFloatToByte(bits) {
4300
- const value = halfFloatToNumber(bits);
4301
- if (!Number.isFinite(value))
4302
- return value > 0 ? 255 : 0;
4303
- return Math.max(0, Math.min(255, Math.round(value * 255)));
4304
- }
4305
- function halfFloatToNumber(bits) {
4306
- const sign = bits & 0x8000 ? -1 : 1;
4307
- const exponent = (bits >> 10) & 0x1f;
4308
- const mantissa = bits & 0x03ff;
4309
- if (exponent === 0) {
4310
- return sign * (mantissa / 0x400) * (2 ** -14);
4311
- }
4312
- if (exponent === 0x1f) {
4313
- return mantissa === 0 ? sign * Infinity : Number.NaN;
4314
- }
4315
- return sign * (1 + mantissa / 0x400) * (2 ** (exponent - 15));
4316
- }
4317
- function numberToHalfFloat(value) {
4318
- if (Number.isNaN(value))
4319
- return 0x7e00;
4320
- const sign = value < 0 || Object.is(value, -0) ? 0x8000 : 0;
4321
- const abs = Math.abs(value);
4322
- if (abs === 0)
4323
- return sign;
4324
- if (!Number.isFinite(abs))
4325
- return sign | 0x7c00;
4326
- if (abs >= 65504)
4327
- return sign | 0x7bff;
4328
- if (abs < 2 ** -14) {
4329
- return sign | Math.round(abs / (2 ** -24));
4330
- }
4331
- const exponent = Math.floor(Math.log2(abs));
4332
- let mantissa = Math.round((abs / (2 ** exponent) - 1) * 0x400);
4333
- let biasedExponent = exponent + 15;
4334
- if (mantissa === 0x400) {
4335
- mantissa = 0;
4336
- biasedExponent += 1;
4337
- }
4338
- if (biasedExponent >= 31)
4339
- return sign | 0x7bff;
4340
- return sign | (biasedExponent << 10) | mantissa;
4341
- }
3
+ exports.canvasLikeImageToRgba = exports.extractBackgroundTexture = exports.extractTextureData = exports.textureUvChannel = exports.materialShadowSide = exports.extractPbrProperties = exports.materialColor = exports.assertMaterialLike = exports.materialForGroup = exports.resolveEnvironmentMap = exports.resolveSceneOverrideMaterial = exports.extractEnvironmentMap = exports.isCompressedTextureFormat = void 0;
4
+ require("./materials.part-001");
5
+ require("./materials.part-002");
6
+ require("./materials.part-003");
7
+ require("./materials.part-004");
8
+ require("./materials.part-005");
9
+ require("./materials.part-006");
10
+ require("./materials.part-007");
11
+ require("./materials.part-008");
12
+ require("./materials.part-009");
13
+ require("./materials.part-010");
14
+ require("./materials.part-011");
15
+ require("./materials.part-012");
16
+ var materials_part_001_1 = require("./materials.part-001");
17
+ Object.defineProperty(exports, "isCompressedTextureFormat", { enumerable: true, get: function () { return materials_part_001_1.isCompressedTextureFormat; } });
18
+ var materials_part_001_2 = require("./materials.part-001");
19
+ Object.defineProperty(exports, "extractEnvironmentMap", { enumerable: true, get: function () { return materials_part_001_2.extractEnvironmentMap; } });
20
+ var materials_part_001_3 = require("./materials.part-001");
21
+ Object.defineProperty(exports, "resolveSceneOverrideMaterial", { enumerable: true, get: function () { return materials_part_001_3.resolveSceneOverrideMaterial; } });
22
+ var materials_part_001_4 = require("./materials.part-001");
23
+ Object.defineProperty(exports, "resolveEnvironmentMap", { enumerable: true, get: function () { return materials_part_001_4.resolveEnvironmentMap; } });
24
+ var materials_part_002_1 = require("./materials.part-002");
25
+ Object.defineProperty(exports, "materialForGroup", { enumerable: true, get: function () { return materials_part_002_1.materialForGroup; } });
26
+ var materials_part_002_2 = require("./materials.part-002");
27
+ Object.defineProperty(exports, "assertMaterialLike", { enumerable: true, get: function () { return materials_part_002_2.assertMaterialLike; } });
28
+ var materials_part_002_3 = require("./materials.part-002");
29
+ Object.defineProperty(exports, "materialColor", { enumerable: true, get: function () { return materials_part_002_3.materialColor; } });
30
+ var materials_part_003_1 = require("./materials.part-003");
31
+ Object.defineProperty(exports, "extractPbrProperties", { enumerable: true, get: function () { return materials_part_003_1.extractPbrProperties; } });
32
+ var materials_part_005_1 = require("./materials.part-005");
33
+ Object.defineProperty(exports, "materialShadowSide", { enumerable: true, get: function () { return materials_part_005_1.materialShadowSide; } });
34
+ var materials_part_005_2 = require("./materials.part-005");
35
+ Object.defineProperty(exports, "textureUvChannel", { enumerable: true, get: function () { return materials_part_005_2.textureUvChannel; } });
36
+ var materials_part_008_1 = require("./materials.part-008");
37
+ Object.defineProperty(exports, "extractTextureData", { enumerable: true, get: function () { return materials_part_008_1.extractTextureData; } });
38
+ var materials_part_008_2 = require("./materials.part-008");
39
+ Object.defineProperty(exports, "extractBackgroundTexture", { enumerable: true, get: function () { return materials_part_008_2.extractBackgroundTexture; } });
40
+ var materials_part_009_1 = require("./materials.part-009");
41
+ Object.defineProperty(exports, "canvasLikeImageToRgba", { enumerable: true, get: function () { return materials_part_009_1.canvasLikeImageToRgba; } });
4342
42
  //# sourceMappingURL=materials.js.map