@zephyr3d/scene 0.3.0 → 0.3.1

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 (41) hide show
  1. package/dist/asset/assetmanager.js +1 -1
  2. package/dist/index.d.ts +34 -4
  3. package/dist/material/lightmodel.js +6 -7
  4. package/dist/material/lightmodel.js.map +1 -1
  5. package/dist/material/lit.js +5 -99
  6. package/dist/material/lit.js.map +1 -1
  7. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +8 -1
  8. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  9. package/dist/material/mixins/pbr/common.js +2 -0
  10. package/dist/material/mixins/pbr/common.js.map +1 -1
  11. package/dist/material/mixins/vertexcolor.js +2 -0
  12. package/dist/material/mixins/vertexcolor.js.map +1 -1
  13. package/dist/material/pbrmr.js +1 -1
  14. package/dist/material/pbrsg.js +9 -4
  15. package/dist/material/pbrsg.js.map +1 -1
  16. package/dist/material/terrainlightmodel.js +1 -3
  17. package/dist/material/terrainlightmodel.js.map +1 -1
  18. package/dist/render/depth_pass.js +2 -3
  19. package/dist/render/depth_pass.js.map +1 -1
  20. package/dist/render/forward.js +6 -3
  21. package/dist/render/forward.js.map +1 -1
  22. package/dist/render/forward_pass.js +5 -6
  23. package/dist/render/forward_pass.js.map +1 -1
  24. package/dist/render/render_queue.js +1 -1
  25. package/dist/scene/mesh.js +1 -1
  26. package/dist/scene/octree.js +3 -3
  27. package/dist/shaders/lighting.js +10 -14
  28. package/dist/shaders/lighting.js.map +1 -1
  29. package/dist/utility/noisetexture.js +66 -0
  30. package/dist/utility/noisetexture.js.map +1 -0
  31. package/dist/utility/textures/gradientnoise.js +66 -0
  32. package/dist/utility/textures/gradientnoise.js.map +1 -0
  33. package/dist/utility/textures/randomnoise.js +41 -0
  34. package/dist/utility/textures/randomnoise.js.map +1 -0
  35. package/package.json +1 -1
  36. package/dist/material/grassmat.js +0 -127
  37. package/dist/material/grassmat.js.map +0 -1
  38. package/dist/material/terrainmat.js +0 -357
  39. package/dist/material/terrainmat.js.map +0 -1
  40. package/dist/utility/sheenlut.js +0 -196
  41. package/dist/utility/sheenlut.js.map +0 -1
@@ -1,357 +0,0 @@
1
- import { applyMaterialMixins, MeshMaterial } from './meshmaterial.js';
2
- import { mixinPBRMetallicRoughness } from './mixins/pbr/metallicroughness.js';
3
- import { mixinLight } from './mixins/lit.js';
4
- import { Application } from '../app.js';
5
- import { Vector4 } from '@zephyr3d/base';
6
- import { drawFullscreenQuad } from '../render/helper.js';
7
-
8
- class NewTerrainMaterial extends applyMaterialMixins(MeshMaterial, mixinLight, mixinPBRMetallicRoughness) {
9
- static _metallicRoughnessGenerationProgram = null;
10
- static _metallicRoughnessGenerationBindGroup = null;
11
- _options;
12
- _uvScales;
13
- _numDetailMaps;
14
- _terrainInfo;
15
- constructor(options){
16
- super();
17
- this.normalMapMode = 'object-space';
18
- this._options = null;
19
- this._numDetailMaps = 0;
20
- this._uvScales = null;
21
- this._terrainInfo = null;
22
- if (options && options.splatMap && options.detailMaps && options.detailMaps.albedoTextures) {
23
- this._options = Object.assign({}, options);
24
- const albedoTextures = this._options.detailMaps.albedoTextures;
25
- this._numDetailMaps = Array.isArray(albedoTextures) ? albedoTextures.length : albedoTextures.depth;
26
- if (!this._numDetailMaps) {
27
- throw new Error(`TerrainLightModel(): Invalid detail textures`);
28
- }
29
- if (this._numDetailMaps > 4) {
30
- throw new Error(`TerrainLightModel(): The maximum detail levels is 4`);
31
- }
32
- if (!this._options.detailMaps.uvScale || this._options.detailMaps.uvScale.length !== this._numDetailMaps) {
33
- throw new Error(`TerrainLightModel(): Invalid uv scale`);
34
- }
35
- this._uvScales = new Float32Array(this._numDetailMaps * 4);
36
- for(let i = 0; i < this._numDetailMaps; i++){
37
- this._uvScales[i * 4] = this._options.detailMaps.uvScale[i];
38
- this._uvScales[i * 4 + 1] = 1;
39
- this._uvScales[i * 4 + 2] = 0.01;
40
- this._uvScales[i * 4 + 3] = 0.99;
41
- }
42
- if (this._options.detailMaps.metallic) {
43
- if (this._options.detailMaps.metallic.length !== this._numDetailMaps) {
44
- throw new Error(`TerrainLightModel(): Invalid metallic values`);
45
- }
46
- for(let i = 0; i < this._numDetailMaps; i++){
47
- this._uvScales[i * 4 + 2] = this._options.detailMaps.metallic[i];
48
- }
49
- }
50
- if (this._options.detailMaps.roughness) {
51
- if (this._options.detailMaps.roughness.length !== this._numDetailMaps) {
52
- throw new Error(`TerrainLightModel(): Invalid roughness values`);
53
- }
54
- for(let i = 0; i < this._numDetailMaps; i++){
55
- this._uvScales[i * 4 + 3] = this._options.detailMaps.roughness[i];
56
- }
57
- }
58
- const normalTextures = options.detailMaps.normalTextures;
59
- if (normalTextures) {
60
- const m = Array.isArray(normalTextures) ? normalTextures.length : normalTextures.depth;
61
- if (m !== this._numDetailMaps) {
62
- throw new Error(`TerrainLightModel(): The number of normal textures not match the number of albedo textures`);
63
- }
64
- if (options.detailMaps.normalScale) {
65
- if (options.detailMaps.normalScale.length !== this._numDetailMaps) {
66
- throw new Error(`TerrainLightModel(): Invalid normal scale`);
67
- }
68
- for(let i = 0; i < this._numDetailMaps; i++){
69
- this._uvScales[i * 4 + 1] = options.detailMaps.normalScale[i];
70
- }
71
- }
72
- }
73
- this._options = Object.assign({}, options);
74
- if (Array.isArray(albedoTextures)) {
75
- for(let i = 0; i < albedoTextures.length; i++){
76
- if (!albedoTextures[i]) {
77
- throw new Error(`TerrainLightModel(): Invalid detail albedo texture`);
78
- }
79
- albedoTextures[i].samplerOptions = {
80
- addressU: 'repeat',
81
- addressV: 'repeat'
82
- };
83
- }
84
- } else {
85
- albedoTextures.samplerOptions = {
86
- addressU: 'repeat',
87
- addressV: 'repeat'
88
- };
89
- }
90
- if (Array.isArray(normalTextures)) {
91
- for(let i = 0; i < normalTextures.length; i++){
92
- if (!normalTextures[i]) {
93
- throw new Error(`TerrainLightModel(): Invalid detail normal texture`);
94
- }
95
- normalTextures[i].samplerOptions = {
96
- addressU: 'repeat',
97
- addressV: 'repeat'
98
- };
99
- }
100
- } else if (normalTextures) {
101
- normalTextures.samplerOptions = {
102
- addressU: 'repeat',
103
- addressV: 'repeat'
104
- };
105
- }
106
- }
107
- this.vertexNormal = true;
108
- this.metallicRoughnessTexture = this.generateMetallicRoughnessMap();
109
- this.metallicRoughnessTexCoordIndex = -1;
110
- this.albedoTexCoordIndex = -1;
111
- this.normalTexCoordIndex = -1;
112
- }
113
- get terrainInfo() {
114
- return this._terrainInfo;
115
- }
116
- set terrainInfo(val) {
117
- this._terrainInfo = val;
118
- this.optionChanged(false);
119
- }
120
- /**
121
- * {@inheritDoc Material.isTransparent}
122
- * @override
123
- */ isTransparent() {
124
- return false;
125
- }
126
- /**
127
- * {@inheritDoc Material.supportLighting}
128
- * @override
129
- */ supportLighting() {
130
- return true;
131
- }
132
- applyUniformValues(bindGroup, ctx) {
133
- super.applyUniformValues(bindGroup, ctx);
134
- if (this.needFragmentColor(ctx)) {
135
- bindGroup.setValue('terrainInfo', this._terrainInfo);
136
- if (this._options) {
137
- bindGroup.setValue('kkDetailScales', this._uvScales);
138
- bindGroup.setTexture('kkSplatMap', this._options.splatMap);
139
- if (Array.isArray(this._options.detailMaps.albedoTextures)) {
140
- for(let i = 0; i < this._numDetailMaps; i++){
141
- bindGroup.setTexture(`kkDetailAlbedoMap${i}`, this._options.detailMaps.albedoTextures[i]);
142
- }
143
- } else {
144
- bindGroup.setTexture('kkDetailAlbedoMap', this._options.detailMaps.albedoTextures);
145
- }
146
- if (Array.isArray(this._options.detailMaps.normalTextures)) {
147
- for(let i = 0; i < this._numDetailMaps; i++){
148
- bindGroup.setTexture(`kkDetailNormalMap${i}`, this._options.detailMaps.normalTextures[i]);
149
- }
150
- } else {
151
- bindGroup.setTexture('kkDetailNormalMap', this._options.detailMaps.normalTextures);
152
- }
153
- }
154
- }
155
- }
156
- /** @ts-ignore */ getMetallicRoughnessTexCoord(scope) {
157
- return scope.$inputs.mapUV;
158
- }
159
- /** @ts-ignore */ getNormalTexCoord(scope) {
160
- return scope.$inputs.mapUV;
161
- }
162
- /** @ts-ignore */ getAlbedoTexCoord(scope) {
163
- return scope.$inputs.mapUV;
164
- }
165
- calculateAlbedoColor(scope, ctx) {
166
- if (!this._options) {
167
- return super.calculateAlbedoColor(scope, ctx);
168
- }
169
- const that = this;
170
- const pb = scope.$builder;
171
- const funcName = 'getTerrainAlbedo';
172
- pb.func(funcName, [], function() {
173
- this.$l.mask = pb.textureSample(this.kkSplatMap, this.$inputs.mapUV);
174
- this.$l.color = pb.vec3(0);
175
- const useTextureArray = !Array.isArray(that._options.detailMaps.albedoTextures);
176
- for(let i = 0; i < that._numDetailMaps; i++){
177
- const uv = pb.mul(this.$inputs.mapUV, this.kkDetailScales.at(i).x);
178
- const sample = useTextureArray ? pb.textureArraySample(this.kkDetailAlbedoMap, uv, i).rgb : pb.textureSample(this[`kkDetailAlbedoMap${i}`], uv).rgb;
179
- this.color = pb.add(this.color, pb.mul(sample, this.mask[i]));
180
- }
181
- this.$return(pb.vec4(this.color, 1));
182
- });
183
- return pb.getGlobalScope()[funcName]();
184
- }
185
- sampleNormalMapWithTBN(scope, tex, texCoord, normalScale, TBN) {
186
- const pb = scope.$builder;
187
- const pixel = pb.sub(pb.mul(pb.textureSample(tex, texCoord).rgb, 2), pb.vec3(1));
188
- const normalTex = pb.mul(pixel, pb.vec3(pb.vec3(normalScale).xx, 1));
189
- return pb.normalize(pb.mul(TBN, normalTex));
190
- }
191
- calculateNormalAndTBN(scope, ctx) {
192
- scope.$l.normalInfo = super.calculateNormalAndTBN(scope, ctx);
193
- const pb = scope.$builder;
194
- let calcNormal = false;
195
- if (this._options && this._options.detailMaps.normalTextures) {
196
- scope.$l.detailMask = pb.textureSample(scope.kkSplatMap, scope.$inputs.mapUV);
197
- if (Array.isArray(this._options.detailMaps.normalTextures)) {
198
- for(let i = 0; i < this._options.detailMaps.normalTextures.length; i++){
199
- const tex = scope[`kkDetailNormalMap${i}`];
200
- const scale = scope.kkDetailScales.at(i).y;
201
- const texCoord = pb.mul(scope.$inputs.mapUV, scope.kkDetailScales.at(i).x);
202
- scope.normalInfo.normal = pb.add(scope.normalInfo.normal, pb.mul(this.sampleNormalMapWithTBN(scope, tex, texCoord, scale, scope.normalInfo.TBN), scope.detailMask[i]));
203
- calcNormal = true;
204
- }
205
- } else {
206
- const tex = scope.kkDetailNormalMap;
207
- for(let i = 0; i < this._numDetailMaps; i++){
208
- const scale = scope.kkDetailScales.at(i).y;
209
- const texCoord = pb.mul(scope.$inputs.mapUV, scope.kkDetailScales.at(i).x);
210
- const pixel = pb.sub(pb.mul(pb.textureArraySample(tex, texCoord, i).rgb, 2), pb.vec3(1));
211
- const normalTex = pb.mul(pixel, pb.vec3(pb.vec3(scale).xx, 1));
212
- const detailNormal = pb.normalize(pb.mul(scope.normalInfo.TBN, normalTex));
213
- scope.normalInfo.normal = pb.add(scope.normalInfo.normal, pb.mul(detailNormal, scope.detailMask[i]));
214
- calcNormal = true;
215
- }
216
- }
217
- }
218
- if (calcNormal) {
219
- scope.normalInfo.normal = pb.normalize(scope.normalInfo.normal);
220
- }
221
- return scope.normalInfo;
222
- }
223
- vertexShader(scope, ctx) {
224
- super.vertexShader(scope, ctx);
225
- const pb = scope.$builder;
226
- scope.$inputs.zPos = pb.vec3().attrib('position');
227
- if (this.needFragmentColor(ctx)) {
228
- scope.$g.terrainInfo = pb.vec4().uniform(2);
229
- scope.$outputs.mapUV = pb.div(scope.$inputs.zPos.xz, scope.terrainInfo.xy);
230
- }
231
- this.transformVertexAndNormal(scope);
232
- }
233
- fragmentShader(scope, ctx) {
234
- super.fragmentShader(scope, ctx);
235
- const pb = scope.$builder;
236
- const that = this;
237
- if (this.needFragmentColor(ctx)) {
238
- if (this._options) {
239
- scope.$g.kkDetailScales = pb.vec4[this._numDetailMaps]().uniform(2);
240
- scope.$g.kkSplatMap = pb.tex2D().uniform(2);
241
- const useAlbedoTextureArray = !Array.isArray(that._options.detailMaps.albedoTextures);
242
- if (useAlbedoTextureArray) {
243
- scope.$g.kkDetailAlbedoMap = pb.tex2DArray().uniform(2);
244
- } else {
245
- for(let i = 0; i < that._numDetailMaps; i++){
246
- scope.$g[`kkDetailAlbedoMap${i}`] = pb.tex2D().uniform(2);
247
- }
248
- }
249
- const useNormalTextureArray = !Array.isArray(that._options.detailMaps.normalTextures);
250
- if (useNormalTextureArray) {
251
- scope.$g.kkDetailNormalMap = pb.tex2DArray().uniform(2);
252
- } else {
253
- for(let i = 0; i < that._numDetailMaps; i++){
254
- scope.$g[`kkDetailNormalMap${i}`] = pb.tex2D().uniform(2);
255
- }
256
- }
257
- }
258
- scope.$l.albedo = this.calculateAlbedoColor(scope, ctx);
259
- scope.$l.normalInfo = this.calculateNormalAndTBN(scope, ctx);
260
- scope.$l.normal = scope.normalInfo.normal;
261
- scope.$l.viewVec = this.calculateViewVector(scope);
262
- scope.$l.pbrData = this.getCommonData(scope, scope.albedo, scope.viewVec, scope.normalInfo.TBN);
263
- scope.$l.lightingColor = pb.vec3(0);
264
- scope.$l.emissiveColor = this.calculateEmissiveColor(scope);
265
- this.indirectLighting(scope, scope.normal, scope.viewVec, scope.pbrData, scope.lightingColor, ctx);
266
- this.forEachLight(scope, ctx, function(type, posRange, dirCutoff, colorIntensity, shadow) {
267
- this.$l.diffuse = pb.vec3();
268
- this.$l.specular = pb.vec3();
269
- this.$l.lightAtten = that.calculateLightAttenuation(this, type, posRange, dirCutoff);
270
- this.$l.lightDir = that.calculateLightDirection(this, type, posRange, dirCutoff);
271
- this.$l.NoL = pb.clamp(pb.dot(this.normal, this.lightDir), 0, 1);
272
- this.$l.lightColor = pb.mul(colorIntensity.rgb, colorIntensity.a, this.lightAtten, this.NoL);
273
- if (shadow) {
274
- this.lightColor = pb.mul(this.lightColor, that.calculateShadow(this, this.NoL, ctx));
275
- }
276
- that.directLighting(this, this.lightDir, this.lightColor, this.normal, this.viewVec, this.pbrData, this.lightingColor);
277
- });
278
- scope.$l.litColor = pb.add(scope.lightingColor, scope.emissiveColor);
279
- this.outputFragmentColor(scope, pb.vec4(scope.litColor, scope.albedo.a), ctx);
280
- } else {
281
- this.outputFragmentColor(scope, null, ctx);
282
- }
283
- }
284
- generateMetallicRoughnessMap() {
285
- const device = Application.instance.device;
286
- if (!this._options) {
287
- const tex = device.createTexture2D('rgba8unorm', 1, 1, {
288
- samplerOptions: {
289
- mipFilter: 'none'
290
- }
291
- });
292
- tex.update(new Uint8Array([
293
- 0,
294
- 1,
295
- 0,
296
- 0
297
- ]), 0, 0, 1, 1);
298
- tex.name = 'TerrainMetallicRoughnessMap';
299
- return tex;
300
- }
301
- if (!NewTerrainMaterial._metallicRoughnessGenerationProgram) {
302
- NewTerrainMaterial._metallicRoughnessGenerationProgram = device.buildRenderProgram({
303
- vertex (pb) {
304
- this.$inputs.pos = pb.vec2().attrib('position');
305
- this.$outputs.uv = pb.vec2();
306
- pb.main(function() {
307
- this.$builtins.position = pb.vec4(this.$inputs.pos, 0, 1);
308
- this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));
309
- if (device.type === 'webgpu') {
310
- this.$builtins.position.y = pb.neg(this.$builtins.position.y);
311
- }
312
- });
313
- },
314
- fragment (pb) {
315
- this.$outputs.outColor = pb.vec4();
316
- this.roughness = pb.vec4().uniform(0);
317
- this.metallic = pb.vec4().uniform(0);
318
- this.splatMap = pb.tex2D().uniform(0);
319
- pb.main(function() {
320
- this.weights = pb.textureSample(this.splatMap, this.$inputs.uv);
321
- this.roughnessValue = pb.dot(this.weights, this.roughness);
322
- this.metallicValue = pb.dot(this.weights, this.metallic);
323
- this.$outputs.outColor = pb.vec4(0, this.roughnessValue, this.metallicValue, 1);
324
- });
325
- }
326
- });
327
- NewTerrainMaterial._metallicRoughnessGenerationBindGroup = device.createBindGroup(NewTerrainMaterial._metallicRoughnessGenerationProgram.bindGroupLayouts[0]);
328
- }
329
- const roughnessValues = Vector4.one();
330
- const metallicValues = Vector4.zero();
331
- for(let i = 0; i < this._numDetailMaps; i++){
332
- metallicValues[i] = this._uvScales[i * 4 + 2];
333
- roughnessValues[i] = this._uvScales[i * 4 + 3];
334
- }
335
- const tex = device.createTexture2D('rgba8unorm', this._options.splatMap.width, this._options.splatMap.height);
336
- tex.name = 'TerrainMetallicRoughnessMap';
337
- const program = NewTerrainMaterial._metallicRoughnessGenerationProgram;
338
- const bindgroup = NewTerrainMaterial._metallicRoughnessGenerationBindGroup;
339
- bindgroup.setValue('roughness', roughnessValues);
340
- bindgroup.setValue('metallic', metallicValues);
341
- bindgroup.setTexture('splatMap', this._options.splatMap);
342
- const fb = device.createFrameBuffer([
343
- tex
344
- ], null);
345
- device.pushDeviceStates();
346
- device.setFramebuffer(fb);
347
- device.setProgram(program);
348
- device.setBindGroup(0, bindgroup);
349
- drawFullscreenQuad();
350
- device.popDeviceStates();
351
- fb.dispose();
352
- return tex;
353
- }
354
- }
355
-
356
- export { NewTerrainMaterial };
357
- //# sourceMappingURL=terrainmat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"terrainmat.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,196 +0,0 @@
1
- import { Vector3, Vector2 } from '@zephyr3d/base';
2
- import { Application } from '../app.js';
3
-
4
- const bits = new Uint32Array(1);
5
- //Van der Corput radical inverse
6
- function radicalInverse_VdC(i) {
7
- bits[0] = i;
8
- bits[0] = (bits[0] << 16 | bits[0] >> 16) >>> 0;
9
- bits[0] = (bits[0] & 0x55555555) << 1 | (bits[0] & 0xaaaaaaaa) >>> 1 >>> 0;
10
- bits[0] = (bits[0] & 0x33333333) << 2 | (bits[0] & 0xcccccccc) >>> 2 >>> 0;
11
- bits[0] = (bits[0] & 0x0f0f0f0f) << 4 | (bits[0] & 0xf0f0f0f0) >>> 4 >>> 0;
12
- bits[0] = (bits[0] & 0x00ff00ff) << 8 | (bits[0] & 0xff00ff00) >>> 8 >>> 0;
13
- return bits[0] * 2.3283064365386963e-10; // / 0x100000000 or / 4294967296
14
- }
15
- function hammersley(i, iN, out) {
16
- out.setXY(i * iN, radicalInverse_VdC(i));
17
- }
18
- function distributionCharlie(NdotH, roughness) {
19
- // roughness = Math.max(roughness, 0.000001);
20
- const invAlpha = 1 / roughness;
21
- const cos2h = NdotH * NdotH;
22
- const sin2h = 1 - cos2h;
23
- return (2 + invAlpha) * Math.pow(sin2h, invAlpha * 0.5) / (2 * Math.PI);
24
- }
25
- function visibilityAshikhmin(NdotV, NdotL) {
26
- return Math.min(Math.max(1 / (4 * (NdotL + NdotV - NdotL * NdotV)), 0), 1);
27
- }
28
- function hemisphereUniformSample(u, out) {
29
- const phi = 2 * Math.PI * u.x;
30
- const cosTheta = 1 - u.y;
31
- const sinTheta = Math.sqrt(1 - cosTheta * cosTheta);
32
- out.setXYZ(sinTheta * Math.cos(phi), sinTheta * Math.sin(phi), cosTheta);
33
- }
34
- function dfvCharlieUniform(NdotV, roughness, numSamples) {
35
- let r = 0;
36
- const V = new Vector3(Math.sqrt(1 - NdotV * NdotV), 0, NdotV);
37
- const u = new Vector2();
38
- const H = new Vector3();
39
- const L = new Vector3();
40
- for(let i = 0; i < numSamples; i++){
41
- hammersley(i, 1 / numSamples, u);
42
- hemisphereUniformSample(u, H);
43
- Vector3.scale(H, Vector3.dot(V, H) * 2, L).subBy(V);
44
- const VdotH = Math.min(Math.max(Vector3.dot(V, H), 0), 1);
45
- const NdotL = Math.min(Math.max(L.z, 0), 1);
46
- const NdotH = Math.min(Math.max(H.z, 0), 1);
47
- if (NdotL > 0) {
48
- const v = visibilityAshikhmin(NdotV, NdotL);
49
- // const v = visibilityCharlie(NdotV, NdotL, roughness);
50
- const d = distributionCharlie(NdotH, roughness);
51
- r += v * d * NdotL * VdotH;
52
- }
53
- }
54
- return r * (4 * 2 * Math.PI / numSamples);
55
- }
56
- const _tables = function _generateTables() {
57
- // float32 to float16 helpers
58
- const buffer = new ArrayBuffer(4);
59
- const floatView = new Float32Array(buffer);
60
- const uint32View = new Uint32Array(buffer);
61
- const baseTable = new Uint32Array(512);
62
- const shiftTable = new Uint32Array(512);
63
- for(let i = 0; i < 256; ++i){
64
- const e = i - 127;
65
- // very small number (0, -0)
66
- if (e < -27) {
67
- baseTable[i] = 0x0000;
68
- baseTable[i | 0x100] = 0x8000;
69
- shiftTable[i] = 24;
70
- shiftTable[i | 0x100] = 24;
71
- // small number (denorm)
72
- } else if (e < -14) {
73
- baseTable[i] = 0x0400 >> -e - 14;
74
- baseTable[i | 0x100] = 0x0400 >> -e - 14 | 0x8000;
75
- shiftTable[i] = -e - 1;
76
- shiftTable[i | 0x100] = -e - 1;
77
- // normal number
78
- } else if (e <= 15) {
79
- baseTable[i] = e + 15 << 10;
80
- baseTable[i | 0x100] = e + 15 << 10 | 0x8000;
81
- shiftTable[i] = 13;
82
- shiftTable[i | 0x100] = 13;
83
- // large number (Infinity, -Infinity)
84
- } else if (e < 128) {
85
- baseTable[i] = 0x7c00;
86
- baseTable[i | 0x100] = 0xfc00;
87
- shiftTable[i] = 24;
88
- shiftTable[i | 0x100] = 24;
89
- // stay (NaN, Infinity, -Infinity)
90
- } else {
91
- baseTable[i] = 0x7c00;
92
- baseTable[i | 0x100] = 0xfc00;
93
- shiftTable[i] = 13;
94
- shiftTable[i | 0x100] = 13;
95
- }
96
- }
97
- // float16 to float32 helpers
98
- const mantissaTable = new Uint32Array(2048);
99
- const exponentTable = new Uint32Array(64);
100
- const offsetTable = new Uint32Array(64);
101
- for(let i = 1; i < 1024; ++i){
102
- let m = i << 13; // zero pad mantissa bits
103
- let e = 0; // zero exponent
104
- // normalized
105
- while((m & 0x00800000) === 0){
106
- m <<= 1;
107
- e -= 0x00800000; // decrement exponent
108
- }
109
- m &= ~0x00800000; // clear leading 1 bit
110
- e += 0x38800000; // adjust bias
111
- mantissaTable[i] = m | e;
112
- }
113
- for(let i = 1024; i < 2048; ++i){
114
- mantissaTable[i] = 0x38000000 + (i - 1024 << 13);
115
- }
116
- for(let i = 1; i < 31; ++i){
117
- exponentTable[i] = i << 23;
118
- }
119
- exponentTable[31] = 0x47800000;
120
- exponentTable[32] = 0x80000000;
121
- for(let i = 33; i < 63; ++i){
122
- exponentTable[i] = 0x80000000 + (i - 32 << 23);
123
- }
124
- exponentTable[63] = 0xc7800000;
125
- for(let i = 1; i < 64; ++i){
126
- if (i !== 32) {
127
- offsetTable[i] = 1024;
128
- }
129
- }
130
- return {
131
- floatView: floatView,
132
- uint32View: uint32View,
133
- baseTable: baseTable,
134
- shiftTable: shiftTable,
135
- mantissaTable: mantissaTable,
136
- exponentTable: exponentTable,
137
- offsetTable: offsetTable
138
- };
139
- }();
140
- function encodeF16(val) {
141
- val = Math.min(Math.max(val, -65504), 65504);
142
- _tables.floatView[0] = val;
143
- const f = _tables.uint32View[0];
144
- const e = f >> 23 & 0x1ff;
145
- return _tables.baseTable[e] + ((f & 0x007fffff) >> _tables.shiftTable[e]);
146
- }
147
- /*
148
- function decodeF16(val: number) {
149
- const exponent = (val & 0x7c00) >> 10;
150
- const fraction = val & 0x03ff;
151
- return (
152
- (val >> 15 ? -1 : 1) *
153
- (exponent
154
- ? exponent === 0x1f
155
- ? fraction
156
- ? NaN
157
- : Infinity
158
- : Math.pow(2, exponent - 15) * (1 + fraction / 0x400)
159
- : 6.103515625e-5 * (fraction / 0x400))
160
- );
161
- }
162
- */ async function createSheenLUT(textureSize, texture) {
163
- if (texture) {
164
- if (!texture.isTexture2D()) {
165
- throw new Error('can not reload sheen lut texture: invalid texture type');
166
- }
167
- if (texture.format !== 'rgba16f') {
168
- throw new Error('can not reload sheen lut texture: invalid texture format');
169
- }
170
- if (texture.width !== textureSize || texture.height !== textureSize) {
171
- throw new Error('can not reload sheen lut texture: invalid texture size');
172
- }
173
- }
174
- const tex = texture || Application.instance.device.createTexture2D('rgba16f', textureSize, textureSize);
175
- const image = new Uint16Array(textureSize * textureSize * 4);
176
- let p = 0;
177
- const one = encodeF16(1);
178
- for(let y = textureSize - 1; y >= 0; y--){
179
- const coord = Math.min(Math.max((y + 0.5) / textureSize, 0), 1);
180
- const roughness = coord * coord;
181
- for(let x = 0; x < textureSize; x++){
182
- const NdotV = Math.min(Math.max((x + 0.5) / textureSize, 0), 1);
183
- const c = dfvCharlieUniform(NdotV, roughness, 512);
184
- const f16 = encodeF16(c);
185
- image[p++] = 0;
186
- image[p++] = 0;
187
- image[p++] = f16;
188
- image[p++] = one;
189
- }
190
- }
191
- tex.update(image, 0, 0, textureSize, textureSize);
192
- return tex;
193
- }
194
-
195
- export { createSheenLUT };
196
- //# sourceMappingURL=sheenlut.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sheenlut.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}