@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.
- package/dist/asset/assetmanager.js +1 -1
- package/dist/index.d.ts +34 -4
- package/dist/material/lightmodel.js +6 -7
- package/dist/material/lightmodel.js.map +1 -1
- package/dist/material/lit.js +5 -99
- package/dist/material/lit.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +8 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +2 -0
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mixins/vertexcolor.js +2 -0
- package/dist/material/mixins/vertexcolor.js.map +1 -1
- package/dist/material/pbrmr.js +1 -1
- package/dist/material/pbrsg.js +9 -4
- package/dist/material/pbrsg.js.map +1 -1
- package/dist/material/terrainlightmodel.js +1 -3
- package/dist/material/terrainlightmodel.js.map +1 -1
- package/dist/render/depth_pass.js +2 -3
- package/dist/render/depth_pass.js.map +1 -1
- package/dist/render/forward.js +6 -3
- package/dist/render/forward.js.map +1 -1
- package/dist/render/forward_pass.js +5 -6
- package/dist/render/forward_pass.js.map +1 -1
- package/dist/render/render_queue.js +1 -1
- package/dist/scene/mesh.js +1 -1
- package/dist/scene/octree.js +3 -3
- package/dist/shaders/lighting.js +10 -14
- package/dist/shaders/lighting.js.map +1 -1
- package/dist/utility/noisetexture.js +66 -0
- package/dist/utility/noisetexture.js.map +1 -0
- package/dist/utility/textures/gradientnoise.js +66 -0
- package/dist/utility/textures/gradientnoise.js.map +1 -0
- package/dist/utility/textures/randomnoise.js +41 -0
- package/dist/utility/textures/randomnoise.js.map +1 -0
- package/package.json +1 -1
- package/dist/material/grassmat.js +0 -127
- package/dist/material/grassmat.js.map +0 -1
- package/dist/material/terrainmat.js +0 -357
- package/dist/material/terrainmat.js.map +0 -1
- package/dist/utility/sheenlut.js +0 -196
- 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/utility/sheenlut.js
DELETED
|
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|