@zephyr3d/scene 0.1.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.
- package/dist/animation/animation.js +173 -0
- package/dist/animation/animation.js.map +1 -0
- package/dist/animation/animationset.js +95 -0
- package/dist/animation/animationset.js.map +1 -0
- package/dist/animation/animationtrack.js +38 -0
- package/dist/animation/animationtrack.js.map +1 -0
- package/dist/animation/eulerrotationtrack.js +33 -0
- package/dist/animation/eulerrotationtrack.js.map +1 -0
- package/dist/animation/rotationtrack.js +37 -0
- package/dist/animation/rotationtrack.js.map +1 -0
- package/dist/animation/scaletrack.js +36 -0
- package/dist/animation/scaletrack.js.map +1 -0
- package/dist/animation/skeleton.js +97 -0
- package/dist/animation/skeleton.js.map +1 -0
- package/dist/animation/translationtrack.js +36 -0
- package/dist/animation/translationtrack.js.map +1 -0
- package/dist/animation/usertrack.js +47 -0
- package/dist/animation/usertrack.js.map +1 -0
- package/dist/app.js +173 -0
- package/dist/app.js.map +1 -0
- package/dist/asset/assetmanager.js +476 -0
- package/dist/asset/assetmanager.js.map +1 -0
- package/dist/asset/builtin.js +373 -0
- package/dist/asset/builtin.js.map +1 -0
- package/dist/asset/loaders/dds/dds.js +472 -0
- package/dist/asset/loaders/dds/dds.js.map +1 -0
- package/dist/asset/loaders/dds/dds_loader.js +38 -0
- package/dist/asset/loaders/dds/dds_loader.js.map +1 -0
- package/dist/asset/loaders/gltf/gltf_loader.js +981 -0
- package/dist/asset/loaders/gltf/gltf_loader.js.map +1 -0
- package/dist/asset/loaders/gltf/helpers.js +314 -0
- package/dist/asset/loaders/gltf/helpers.js.map +1 -0
- package/dist/asset/loaders/hdr/hdr.js +175 -0
- package/dist/asset/loaders/hdr/hdr.js.map +1 -0
- package/dist/asset/loaders/image/tga_Loader.js +117 -0
- package/dist/asset/loaders/image/tga_Loader.js.map +1 -0
- package/dist/asset/loaders/image/webimage_loader.js +50 -0
- package/dist/asset/loaders/image/webimage_loader.js.map +1 -0
- package/dist/asset/loaders/loader.js +45 -0
- package/dist/asset/loaders/loader.js.map +1 -0
- package/dist/asset/model.js +264 -0
- package/dist/asset/model.js.map +1 -0
- package/dist/blitter/blitter.js +389 -0
- package/dist/blitter/blitter.js.map +1 -0
- package/dist/blitter/box.js +118 -0
- package/dist/blitter/box.js.map +1 -0
- package/dist/blitter/copy.js +22 -0
- package/dist/blitter/copy.js.map +1 -0
- package/dist/blitter/depthlimitedgaussion.js +166 -0
- package/dist/blitter/depthlimitedgaussion.js.map +1 -0
- package/dist/blitter/gaussianblur.js +229 -0
- package/dist/blitter/gaussianblur.js.map +1 -0
- package/dist/camera/base.js +90 -0
- package/dist/camera/base.js.map +1 -0
- package/dist/camera/camera.js +358 -0
- package/dist/camera/camera.js.map +1 -0
- package/dist/camera/fps.js +246 -0
- package/dist/camera/fps.js.map +1 -0
- package/dist/camera/orbit.js +157 -0
- package/dist/camera/orbit.js.map +1 -0
- package/dist/camera/orthocamera.js +126 -0
- package/dist/camera/orthocamera.js.map +1 -0
- package/dist/camera/perspectivecamera.js +133 -0
- package/dist/camera/perspectivecamera.js.map +1 -0
- package/dist/index.d.ts +8402 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/input/inputmgr.js +242 -0
- package/dist/input/inputmgr.js.map +1 -0
- package/dist/material/blinn.js +75 -0
- package/dist/material/blinn.js.map +1 -0
- package/dist/material/grassmaterial.js +221 -0
- package/dist/material/grassmaterial.js.map +1 -0
- package/dist/material/lambert.js +52 -0
- package/dist/material/lambert.js.map +1 -0
- package/dist/material/lightmodel.js +2074 -0
- package/dist/material/lightmodel.js.map +1 -0
- package/dist/material/lit.js +578 -0
- package/dist/material/lit.js.map +1 -0
- package/dist/material/material.js +458 -0
- package/dist/material/material.js.map +1 -0
- package/dist/material/meshmaterial.js +311 -0
- package/dist/material/meshmaterial.js.map +1 -0
- package/dist/material/mixins/albedocolor.js +130 -0
- package/dist/material/mixins/albedocolor.js.map +1 -0
- package/dist/material/mixins/texture.js +110 -0
- package/dist/material/mixins/texture.js.map +1 -0
- package/dist/material/mixins/vertexcolor.js +45 -0
- package/dist/material/mixins/vertexcolor.js.map +1 -0
- package/dist/material/pbr.js +27 -0
- package/dist/material/pbr.js.map +1 -0
- package/dist/material/standard.js +282 -0
- package/dist/material/standard.js.map +1 -0
- package/dist/material/terrainlightmodel.js +259 -0
- package/dist/material/terrainlightmodel.js.map +1 -0
- package/dist/material/terrainmaterial.js +139 -0
- package/dist/material/terrainmaterial.js.map +1 -0
- package/dist/material/unlit.js +29 -0
- package/dist/material/unlit.js.map +1 -0
- package/dist/posteffect/bloom.js +398 -0
- package/dist/posteffect/bloom.js.map +1 -0
- package/dist/posteffect/compositor.js +264 -0
- package/dist/posteffect/compositor.js.map +1 -0
- package/dist/posteffect/fxaa.js +291 -0
- package/dist/posteffect/fxaa.js.map +1 -0
- package/dist/posteffect/grayscale.js +87 -0
- package/dist/posteffect/grayscale.js.map +1 -0
- package/dist/posteffect/posteffect.js +165 -0
- package/dist/posteffect/posteffect.js.map +1 -0
- package/dist/posteffect/sao.js +327 -0
- package/dist/posteffect/sao.js.map +1 -0
- package/dist/posteffect/tonemap.js +112 -0
- package/dist/posteffect/tonemap.js.map +1 -0
- package/dist/posteffect/water.js +535 -0
- package/dist/posteffect/water.js.map +1 -0
- package/dist/render/clipmap.js +462 -0
- package/dist/render/clipmap.js.map +1 -0
- package/dist/render/cluster_light.js +329 -0
- package/dist/render/cluster_light.js.map +1 -0
- package/dist/render/cull_visitor.js +124 -0
- package/dist/render/cull_visitor.js.map +1 -0
- package/dist/render/depth_pass.js +47 -0
- package/dist/render/depth_pass.js.map +1 -0
- package/dist/render/envlight.js +282 -0
- package/dist/render/envlight.js.map +1 -0
- package/dist/render/forward.js +186 -0
- package/dist/render/forward.js.map +1 -0
- package/dist/render/forward_pass.js +137 -0
- package/dist/render/forward_pass.js.map +1 -0
- package/dist/render/helper.js +38 -0
- package/dist/render/helper.js.map +1 -0
- package/dist/render/primitive.js +246 -0
- package/dist/render/primitive.js.map +1 -0
- package/dist/render/render_queue.js +163 -0
- package/dist/render/render_queue.js.map +1 -0
- package/dist/render/renderpass.js +151 -0
- package/dist/render/renderpass.js.map +1 -0
- package/dist/render/renderscheme.js +61 -0
- package/dist/render/renderscheme.js.map +1 -0
- package/dist/render/scatteringlut.js +634 -0
- package/dist/render/scatteringlut.js.map +1 -0
- package/dist/render/shadowmap_pass.js +70 -0
- package/dist/render/shadowmap_pass.js.map +1 -0
- package/dist/render/sky.js +881 -0
- package/dist/render/sky.js.map +1 -0
- package/dist/render/temporalcache.js +222 -0
- package/dist/render/temporalcache.js.map +1 -0
- package/dist/render/watermesh.js +835 -0
- package/dist/render/watermesh.js.map +1 -0
- package/dist/scene/environment.js +146 -0
- package/dist/scene/environment.js.map +1 -0
- package/dist/scene/graph_node.js +69 -0
- package/dist/scene/graph_node.js.map +1 -0
- package/dist/scene/light.js +436 -0
- package/dist/scene/light.js.map +1 -0
- package/dist/scene/mesh.js +215 -0
- package/dist/scene/mesh.js.map +1 -0
- package/dist/scene/model.js +111 -0
- package/dist/scene/model.js.map +1 -0
- package/dist/scene/octree.js +651 -0
- package/dist/scene/octree.js.map +1 -0
- package/dist/scene/octree_update_visitor.js +16 -0
- package/dist/scene/octree_update_visitor.js.map +1 -0
- package/dist/scene/raycast_visitor.js +72 -0
- package/dist/scene/raycast_visitor.js.map +1 -0
- package/dist/scene/scene.js +225 -0
- package/dist/scene/scene.js.map +1 -0
- package/dist/scene/scene_node.js +299 -0
- package/dist/scene/scene_node.js.map +1 -0
- package/dist/scene/terrain/grass.js +277 -0
- package/dist/scene/terrain/grass.js.map +1 -0
- package/dist/scene/terrain/heightfield.js +391 -0
- package/dist/scene/terrain/heightfield.js.map +1 -0
- package/dist/scene/terrain/patch.js +530 -0
- package/dist/scene/terrain/patch.js.map +1 -0
- package/dist/scene/terrain/quadtree.js +430 -0
- package/dist/scene/terrain/quadtree.js.map +1 -0
- package/dist/scene/terrain/terrain.js +258 -0
- package/dist/scene/terrain/terrain.js.map +1 -0
- package/dist/scene/xform.js +224 -0
- package/dist/scene/xform.js.map +1 -0
- package/dist/shaders/builtins.js +110 -0
- package/dist/shaders/builtins.js.map +1 -0
- package/dist/shaders/framework.js +709 -0
- package/dist/shaders/framework.js.map +1 -0
- package/dist/shaders/lighting.js +335 -0
- package/dist/shaders/lighting.js.map +1 -0
- package/dist/shaders/misc.js +405 -0
- package/dist/shaders/misc.js.map +1 -0
- package/dist/shaders/noise.js +157 -0
- package/dist/shaders/noise.js.map +1 -0
- package/dist/shaders/pbr.js +132 -0
- package/dist/shaders/pbr.js.map +1 -0
- package/dist/shaders/shadow.js +642 -0
- package/dist/shaders/shadow.js.map +1 -0
- package/dist/shaders/water.js +630 -0
- package/dist/shaders/water.js.map +1 -0
- package/dist/shadow/esm.js +235 -0
- package/dist/shadow/esm.js.map +1 -0
- package/dist/shadow/pcf_opt.js +182 -0
- package/dist/shadow/pcf_opt.js.map +1 -0
- package/dist/shadow/pcf_pd.js +190 -0
- package/dist/shadow/pcf_pd.js.map +1 -0
- package/dist/shadow/shadow_impl.js +15 -0
- package/dist/shadow/shadow_impl.js.map +1 -0
- package/dist/shadow/shadowmapper.js +709 -0
- package/dist/shadow/shadowmapper.js.map +1 -0
- package/dist/shadow/ssm.js +194 -0
- package/dist/shadow/ssm.js.map +1 -0
- package/dist/shadow/vsm.js +298 -0
- package/dist/shadow/vsm.js.map +1 -0
- package/dist/shapes/box.js +313 -0
- package/dist/shapes/box.js.map +1 -0
- package/dist/shapes/cylinder.js +74 -0
- package/dist/shapes/cylinder.js.map +1 -0
- package/dist/shapes/plane.js +48 -0
- package/dist/shapes/plane.js.map +1 -0
- package/dist/shapes/shape.js +33 -0
- package/dist/shapes/shape.js.map +1 -0
- package/dist/shapes/sphere.js +91 -0
- package/dist/shapes/sphere.js.map +1 -0
- package/dist/shapes/torus.js +100 -0
- package/dist/shapes/torus.js.map +1 -0
- package/dist/utility/aabbtree.js +390 -0
- package/dist/utility/aabbtree.js.map +1 -0
- package/dist/utility/bounding_volume.js +78 -0
- package/dist/utility/bounding_volume.js.map +1 -0
- package/dist/utility/panorama.js +163 -0
- package/dist/utility/panorama.js.map +1 -0
- package/dist/utility/pmrem.js +345 -0
- package/dist/utility/pmrem.js.map +1 -0
- package/dist/utility/shprojection.js +448 -0
- package/dist/utility/shprojection.js.map +1 -0
- package/dist/values.js +48 -0
- package/dist/values.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,2074 @@
|
|
|
1
|
+
import { Matrix4x4, Vector4 } from '@zephyr3d/base';
|
|
2
|
+
import { PBPrimitiveTypeInfo, PBPrimitiveType, PBStructTypeInfo } from '@zephyr3d/device';
|
|
3
|
+
import { calculateTBN, calculateTBNWithNormal } from '../shaders/misc.js';
|
|
4
|
+
import { Material } from './material.js';
|
|
5
|
+
import { fresnelSchlick, directLighting, directSheenLighting, directClearcoatLighting } from '../shaders/pbr.js';
|
|
6
|
+
import { ShaderFramework } from '../shaders/framework.js';
|
|
7
|
+
import { Application } from '../app.js';
|
|
8
|
+
|
|
9
|
+
const typeF32 = PBPrimitiveTypeInfo.getCachedTypeInfo(PBPrimitiveType.F32);
|
|
10
|
+
const typeF32Vec3 = PBPrimitiveTypeInfo.getCachedTypeInfo(PBPrimitiveType.F32VEC3);
|
|
11
|
+
const typeF32Vec4 = PBPrimitiveTypeInfo.getCachedTypeInfo(PBPrimitiveType.F32VEC4);
|
|
12
|
+
const typeMat3 = PBPrimitiveTypeInfo.getCachedTypeInfo(PBPrimitiveType.MAT3);
|
|
13
|
+
const identTexTransform = Matrix4x4.identity();
|
|
14
|
+
const TEX_NAME_ALBEDO = 'albedo';
|
|
15
|
+
const TEX_NAME_NORMAL = 'normal';
|
|
16
|
+
const TEX_NAME_EMISSIVE = 'emissive';
|
|
17
|
+
const TEX_NAME_OCCLUSION = 'occlusion';
|
|
18
|
+
const TEX_NAME_SPECULAR = 'specular';
|
|
19
|
+
const TEX_NAME_SPECULAR_COLOR = 'specularColor';
|
|
20
|
+
const TEX_NAME_METALLIC = 'metallic';
|
|
21
|
+
const TEX_NAME_SHEEN_COLOR = 'sheenColor';
|
|
22
|
+
const TEX_NAME_SHEEN_ROUGHNESS = 'sheenRoughness';
|
|
23
|
+
const TEX_NAME_SHEEN_LUT = 'sheenLut';
|
|
24
|
+
const TEX_NAME_CLEARCOAT_INTENSITY = 'clearcoatIntensity';
|
|
25
|
+
const TEX_NAME_CLEARCOAT_ROUGHNESS = 'clearcoatRoughness';
|
|
26
|
+
const TEX_NAME_CLEARCOAT_NORMAL = 'clearcoatNormal';
|
|
27
|
+
/**
|
|
28
|
+
* Base class for any kind of light model
|
|
29
|
+
* @public
|
|
30
|
+
*/ class LightModel {
|
|
31
|
+
/** @internal */ static funcNameBRDFEnvConstantAmbient = 'libLM_envConstantAmbient';
|
|
32
|
+
/** @internal */ static funcNameBRDFEnvHemispheric = 'libLM_envHemispheric';
|
|
33
|
+
/** @internal */ static uniformAlbedoColor = 'libLM_USAGE_albedoColor';
|
|
34
|
+
/** @internal */ static uniformNormalScale = 'libLM_USAGE_normalScale';
|
|
35
|
+
/** @internal */ static uniformEmissiveFactor = 'libLM_USAGE_emissiveFactor';
|
|
36
|
+
/** @internal */ static funcNameCalcAlbedo = 'libLM_calcAlbedo';
|
|
37
|
+
/** @internal */ _doubleSideLighting;
|
|
38
|
+
/** @internal */ _albedo;
|
|
39
|
+
/** @internal */ _normalScale;
|
|
40
|
+
/** @internal */ _normalMapMode;
|
|
41
|
+
/** @internal */ _emissiveFactor;
|
|
42
|
+
/** @internal */ _hash;
|
|
43
|
+
/** @internal */ _hashVersion;
|
|
44
|
+
/** @internal */ _uniformVersion;
|
|
45
|
+
/** @internal */ _bindGroupTagList;
|
|
46
|
+
/** @internal */ _texCoordChannels;
|
|
47
|
+
/** @internal */ _textureOptions;
|
|
48
|
+
/** @internal */ _surfaceDataType;
|
|
49
|
+
/**
|
|
50
|
+
* Creates an instance of LightModel
|
|
51
|
+
*/ constructor(){
|
|
52
|
+
this._albedo = Vector4.one();
|
|
53
|
+
this._doubleSideLighting = true;
|
|
54
|
+
this._normalScale = 1;
|
|
55
|
+
this._normalMapMode = 'tangent-space';
|
|
56
|
+
this._emissiveFactor = new Vector4(0, 0, 0, 1);
|
|
57
|
+
this._hash = null;
|
|
58
|
+
this._hashVersion = 0;
|
|
59
|
+
this._uniformVersion = 0;
|
|
60
|
+
this._bindGroupTagList = new WeakMap();
|
|
61
|
+
this._texCoordChannels = [];
|
|
62
|
+
this._textureOptions = {};
|
|
63
|
+
this._surfaceDataType = null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Gets the data structure of surface data
|
|
67
|
+
* @param env - environment lighting object
|
|
68
|
+
* @returns The data structure of surface data
|
|
69
|
+
*/ getSurfaceDataType(env) {
|
|
70
|
+
return this.createSurfaceDataType(env);
|
|
71
|
+
}
|
|
72
|
+
/** Whether enable double side lighting */ get doubleSideLighting() {
|
|
73
|
+
return this._doubleSideLighting;
|
|
74
|
+
}
|
|
75
|
+
set doubleSideLighting(val) {
|
|
76
|
+
if (this._doubleSideLighting !== !!val) {
|
|
77
|
+
this._doubleSideLighting = !!val;
|
|
78
|
+
this.optionChanged(true);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** The albedo color */ get albedo() {
|
|
82
|
+
return this._albedo;
|
|
83
|
+
}
|
|
84
|
+
set albedo(val) {
|
|
85
|
+
if (!val.equalsTo(this._albedo)) {
|
|
86
|
+
this._albedo.set(val);
|
|
87
|
+
this.optionChanged(false);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** The albedo texture */ get albedoMap() {
|
|
91
|
+
return (this._textureOptions[TEX_NAME_ALBEDO]?.texture) ?? null;
|
|
92
|
+
}
|
|
93
|
+
/** Sampler of the albedo texture */ get albedoSampler() {
|
|
94
|
+
return this._textureOptions[TEX_NAME_ALBEDO]?.sampler ?? null;
|
|
95
|
+
}
|
|
96
|
+
/** Texture coordinate index of the albedo texture */ get albedoMapTexCoord() {
|
|
97
|
+
return this._textureOptions[TEX_NAME_ALBEDO]?.texCoordIndex ?? null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Gets the texture transform matrix for given texture coordinate index.
|
|
101
|
+
* @param texCoordIndex - The texture coordinate index
|
|
102
|
+
* @returns Texture transform matrix
|
|
103
|
+
*/ getTexCoordTransform(texCoordIndex) {
|
|
104
|
+
return this._texCoordChannels[texCoordIndex]?.transform ?? null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Sets the texture transform matrix for given texture coordinate index.
|
|
108
|
+
* @param texCoordIndex - The texture coordinate index.
|
|
109
|
+
* @param transform - Texture transform matrix, if null, the identity matrix will be set.
|
|
110
|
+
*/ setTexCoordTransform(texCoordIndex, transform) {
|
|
111
|
+
if (!this._texCoordChannels[texCoordIndex]) {
|
|
112
|
+
console.error(`setTexCoordTransform(): texCoordIndex ${texCoordIndex} not in use`);
|
|
113
|
+
} else {
|
|
114
|
+
this._texCoordChannels[texCoordIndex].transform = transform ?? identTexTransform;
|
|
115
|
+
this.optionChanged(false);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Sets the albedo texture
|
|
120
|
+
* @param tex - The texture to set
|
|
121
|
+
* @param sampler - Sampler of the texture
|
|
122
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
123
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
124
|
+
*/ setAlbedoMap(tex, sampler, texCoordIndex, texTransform) {
|
|
125
|
+
this.setTextureOptions(TEX_NAME_ALBEDO, tex, sampler, texCoordIndex, texTransform);
|
|
126
|
+
}
|
|
127
|
+
/** The normal texture */ get normalMap() {
|
|
128
|
+
return (this._textureOptions[TEX_NAME_NORMAL]?.texture) ?? null;
|
|
129
|
+
}
|
|
130
|
+
/** Sampler of the normal texture */ get normalSampler() {
|
|
131
|
+
return this._textureOptions[TEX_NAME_NORMAL]?.sampler ?? null;
|
|
132
|
+
}
|
|
133
|
+
/** Texture coordinate index of the normal texture */ get normalMapTexCoord() {
|
|
134
|
+
return this._textureOptions[TEX_NAME_NORMAL]?.texCoordIndex ?? null;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Sets the normal texture
|
|
138
|
+
* @param tex - The texture to set
|
|
139
|
+
* @param sampler - Sampler of the texture
|
|
140
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
141
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
142
|
+
*/ setNormalMap(tex, sampler, texCoordIndex, texTransform) {
|
|
143
|
+
this.setTextureOptions(TEX_NAME_NORMAL, tex, sampler, texCoordIndex, texTransform);
|
|
144
|
+
}
|
|
145
|
+
/** Scale value of normal for normal mapping */ get normalScale() {
|
|
146
|
+
return this._normalScale;
|
|
147
|
+
}
|
|
148
|
+
set normalScale(val) {
|
|
149
|
+
if (val !== this._normalScale) {
|
|
150
|
+
this._normalScale = val;
|
|
151
|
+
if (this.normalMap) {
|
|
152
|
+
this.optionChanged(false);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** The emission texture */ get emissiveMap() {
|
|
157
|
+
return (this._textureOptions[TEX_NAME_EMISSIVE]?.texture) ?? null;
|
|
158
|
+
}
|
|
159
|
+
/** Sampler of the emission texture */ get emissiveSampler() {
|
|
160
|
+
return this._textureOptions[TEX_NAME_EMISSIVE]?.sampler ?? null;
|
|
161
|
+
}
|
|
162
|
+
/** Texture coordinate index of the emission texture */ get emissiveMapTexCoord() {
|
|
163
|
+
return this._textureOptions[TEX_NAME_EMISSIVE]?.texCoordIndex ?? null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Sets the emission texture
|
|
167
|
+
* @param tex - The texture to set
|
|
168
|
+
* @param sampler - Sampler of the texture
|
|
169
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
170
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
171
|
+
*/ setEmissiveMap(tex, sampler, texCoordIndex, texTransform) {
|
|
172
|
+
this.setTextureOptions(TEX_NAME_EMISSIVE, tex, sampler, texCoordIndex, texTransform);
|
|
173
|
+
}
|
|
174
|
+
/** The emission color */ get emissiveColor() {
|
|
175
|
+
return this._emissiveFactor.xyz();
|
|
176
|
+
}
|
|
177
|
+
set emissiveColor(val) {
|
|
178
|
+
if (val.x !== this._emissiveFactor.x || val.y !== this._emissiveFactor.y || val.z !== this._emissiveFactor.z) {
|
|
179
|
+
this._emissiveFactor.x = val.x;
|
|
180
|
+
this._emissiveFactor.y = val.y;
|
|
181
|
+
this._emissiveFactor.z = val.z;
|
|
182
|
+
this.optionChanged(false);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Strength of emission */ get emissiveStrength() {
|
|
186
|
+
return this._emissiveFactor.w;
|
|
187
|
+
}
|
|
188
|
+
set emissiveStrength(val) {
|
|
189
|
+
if (this._emissiveFactor.w !== val) {
|
|
190
|
+
this._emissiveFactor.w = val;
|
|
191
|
+
this.optionChanged(false);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Adds a texture uniforms for the light model
|
|
196
|
+
* @param name - Name of the texture uniform
|
|
197
|
+
* @param tex - Texture to set
|
|
198
|
+
* @param sampler - Sampler of the texture
|
|
199
|
+
* @param texCoord - Texture coordinate index of the texture
|
|
200
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
201
|
+
*/ setTextureOptions(name, tex, sampler, texCoord, texTransform) {
|
|
202
|
+
tex = tex ?? null;
|
|
203
|
+
let info = this._textureOptions[name];
|
|
204
|
+
if (!tex) {
|
|
205
|
+
if (info) {
|
|
206
|
+
delete this._textureOptions[name];
|
|
207
|
+
this.optionChanged(true);
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!info) {
|
|
212
|
+
info = {
|
|
213
|
+
texture: null,
|
|
214
|
+
texCoordIndex: null,
|
|
215
|
+
sampler: null
|
|
216
|
+
};
|
|
217
|
+
this._textureOptions[name] = info;
|
|
218
|
+
}
|
|
219
|
+
sampler = sampler ?? null;
|
|
220
|
+
texTransform = texTransform || identTexTransform;
|
|
221
|
+
let uniformChanged = false;
|
|
222
|
+
let hashChanged = false;
|
|
223
|
+
if (info.texture !== tex) {
|
|
224
|
+
hashChanged ||= !info.texture || !tex;
|
|
225
|
+
info.texture = tex;
|
|
226
|
+
}
|
|
227
|
+
if (info.sampler !== sampler) {
|
|
228
|
+
uniformChanged ||= !!info.texture;
|
|
229
|
+
info.sampler = sampler;
|
|
230
|
+
}
|
|
231
|
+
const index = this.addTexCoordChannel(texCoord, texTransform);
|
|
232
|
+
if (index !== info.texCoordIndex) {
|
|
233
|
+
info.texCoordIndex = index;
|
|
234
|
+
uniformChanged ||= !!info.texture;
|
|
235
|
+
}
|
|
236
|
+
if (uniformChanged || hashChanged) {
|
|
237
|
+
this.optionChanged(hashChanged);
|
|
238
|
+
}
|
|
239
|
+
return index;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Calculates the hash code of the shader program
|
|
243
|
+
* @returns The hash code of the shader program
|
|
244
|
+
*/ calculateHash() {
|
|
245
|
+
const texChannelHash = this._texCoordChannels.map((val)=>val.srcLocation).join('');
|
|
246
|
+
const albedoHash = this.albedoMap ? this.albedoMapTexCoord + 1 : 0;
|
|
247
|
+
const normalHash = this.normalMap ? `${this.normalMapTexCoord + 1}:${this._normalMapMode === 'tangent-space' ? 1 : 0}` : 0;
|
|
248
|
+
const emissiveHash = this.emissiveMap ? this.emissiveMapTexCoord + 1 : 0;
|
|
249
|
+
return `${texChannelHash}_${albedoHash}_${normalHash}_${emissiveHash}`;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Setup uniforms of the shader program
|
|
253
|
+
* @param scope - The shader scope
|
|
254
|
+
* @param ctx - The drawing context
|
|
255
|
+
*/ setupUniforms(scope, ctx) {
|
|
256
|
+
const pb = scope.$builder;
|
|
257
|
+
const that = this;
|
|
258
|
+
if (pb.shaderKind === 'vertex') {
|
|
259
|
+
for(let i = 0; i < that._texCoordChannels.length; i++){
|
|
260
|
+
scope[`lm_texTransform${i}`] = pb.mat4().uniform(2);
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
scope.lm_albedo = pb.vec4().uniform(2).tag(LightModel.uniformAlbedoColor);
|
|
264
|
+
if (this.normalMap) {
|
|
265
|
+
scope.lm_normalScale = pb.float().uniform(2).tag(LightModel.uniformNormalScale);
|
|
266
|
+
}
|
|
267
|
+
scope.lm_emissiveFactor = pb.vec4().uniform(2).tag(LightModel.uniformEmissiveFactor);
|
|
268
|
+
scope.surfaceData = pb.defineStructByType(that.getSurfaceDataType(ctx.drawEnvLight ? ctx.env.light.envLight : null))();
|
|
269
|
+
this.setupTextureUniforms(scope);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Updates uniforms of the shader program
|
|
274
|
+
* @param bindGroup - The bind group
|
|
275
|
+
* @param ctx - The drawing context
|
|
276
|
+
*/ applyUniforms(bindGroup, ctx) {
|
|
277
|
+
for(let i = 0; i < this._texCoordChannels.length; i++){
|
|
278
|
+
bindGroup.setValue(`lm_texTransform${i}`, this._texCoordChannels[i].transform);
|
|
279
|
+
}
|
|
280
|
+
bindGroup.setValue('lm_albedo', this._albedo);
|
|
281
|
+
if (this.normalMap) {
|
|
282
|
+
bindGroup.setValue('lm_normalScale', this._normalScale);
|
|
283
|
+
}
|
|
284
|
+
bindGroup.setValue('lm_emissiveFactor', this._emissiveFactor);
|
|
285
|
+
this.applyTextureUniforms(bindGroup);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Retreives the surface data of the material
|
|
289
|
+
* @param scope - The shader scope
|
|
290
|
+
* @param envLight - The environment lighting object
|
|
291
|
+
* @param worldPos - World space position of current fragment
|
|
292
|
+
* @param worldNormal - World space normal of current fragment
|
|
293
|
+
* @param worldTangent - World space tangent of current fragment
|
|
294
|
+
* @param worldBinormal - World space binormal of current fragment
|
|
295
|
+
* @returns The surface data
|
|
296
|
+
*/ getSurfaceData(scope, envLight, worldPos, worldNormal, worldTangent, worldBinormal) {
|
|
297
|
+
const funcNameGetSurfaceData = 'lib_getSurfaceData';
|
|
298
|
+
const pb = scope.$builder;
|
|
299
|
+
const that = this;
|
|
300
|
+
const args = [
|
|
301
|
+
worldPos.xyz
|
|
302
|
+
];
|
|
303
|
+
const params = [
|
|
304
|
+
pb.vec3('worldPos')
|
|
305
|
+
];
|
|
306
|
+
if (worldNormal) {
|
|
307
|
+
params.push(pb.vec3('worldNormal'));
|
|
308
|
+
args.push(worldNormal);
|
|
309
|
+
if (worldTangent) {
|
|
310
|
+
params.push(pb.vec3('worldTangent'), pb.vec3('worldBinormal'));
|
|
311
|
+
args.push(worldTangent, worldBinormal);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
pb.func(funcNameGetSurfaceData, params, function() {
|
|
315
|
+
this.$l.normalInfo = that.calculateNormal(this, this.worldPos, worldNormal ? this.worldNormal : null, worldTangent ? this.worldTangent : null, worldTangent ? this.worldBinormal : null);
|
|
316
|
+
this.surfaceData.TBN = this.normalInfo.TBN;
|
|
317
|
+
this.surfaceData.normal = this.normalInfo.normal;
|
|
318
|
+
this.surfaceData.viewVec = pb.normalize(pb.sub(ShaderFramework.getCameraPosition(this), this.worldPos));
|
|
319
|
+
this.surfaceData.NdotV = pb.clamp(pb.dot(this.surfaceData.normal, this.surfaceData.viewVec), 0.0001, 1);
|
|
320
|
+
this.surfaceData.diffuse = that.calculateAlbedo(this);
|
|
321
|
+
this.surfaceData.accumDiffuse = pb.vec3(0);
|
|
322
|
+
this.surfaceData.accumSpecular = pb.vec3(0);
|
|
323
|
+
this.surfaceData.accumEmissive = that.calculateEmissive(this);
|
|
324
|
+
this.surfaceData.accumColor = pb.vec3(0);
|
|
325
|
+
that.fillSurfaceData(this, envLight);
|
|
326
|
+
});
|
|
327
|
+
pb.getGlobalScope()[funcNameGetSurfaceData](...args);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Gets the name of a texture uniform by given key
|
|
331
|
+
* @param key - key of the texture
|
|
332
|
+
* @returns Name of the texture uniform
|
|
333
|
+
*/ getTextureUniformName(key) {
|
|
334
|
+
return `lm_${key}_Map`;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Calculates the texture coordinate of current fragment by given texture coordinate index
|
|
338
|
+
* @param scope - The shader scope
|
|
339
|
+
* @param index - The texture coordinate index
|
|
340
|
+
* @returns The texture coordinate
|
|
341
|
+
*/ calculateTexCoord(scope, index) {
|
|
342
|
+
return scope.$builder.mul(scope[`lm_texTransform${index}`], scope.$builder.vec4(scope.$inputs[`texcoord${this._texCoordChannels[index].srcLocation}`], 0, 1)).xy;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Calculates the texture coordinate of current fragment by given texture coordinate value
|
|
346
|
+
* @param scope - The shader scope
|
|
347
|
+
* @param index - The texture coordinate index
|
|
348
|
+
* @returns The texture coordinate
|
|
349
|
+
*/ calculateTexCoordNoInput(scope, index, value) {
|
|
350
|
+
return scope.$builder.mul(scope[`lm_texTransform${index}`], scope.$builder.vec4(value, 0, 1)).xy;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Calculates the emissive color for current fragment
|
|
354
|
+
* @param scope - The shader scope
|
|
355
|
+
* @returns The emissive color
|
|
356
|
+
*/ calculateEmissive(scope) {
|
|
357
|
+
const pb = scope.$builder;
|
|
358
|
+
const emissiveMap = scope[this.getTextureUniformName(TEX_NAME_EMISSIVE)];
|
|
359
|
+
const emissiveFactor = scope.$query(LightModel.uniformEmissiveFactor);
|
|
360
|
+
if (emissiveFactor) {
|
|
361
|
+
const emissiveColor = pb.mul(emissiveFactor.rgb, emissiveFactor.a);
|
|
362
|
+
if (emissiveMap) {
|
|
363
|
+
const emissiveTexCoord = scope.$inputs[`texcoord${this.emissiveMapTexCoord}`];
|
|
364
|
+
return pb.mul(pb.textureSample(emissiveMap, emissiveTexCoord).rgb, emissiveColor).rgb;
|
|
365
|
+
} else {
|
|
366
|
+
return emissiveColor;
|
|
367
|
+
}
|
|
368
|
+
} else {
|
|
369
|
+
return pb.vec3(0);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Calculates the albedo color for current fragment
|
|
374
|
+
* @param scope - The shader scope
|
|
375
|
+
* @returns The albedo color
|
|
376
|
+
*/ calculateAlbedo(scope) {
|
|
377
|
+
const that = this;
|
|
378
|
+
const pb = scope.$builder;
|
|
379
|
+
pb.func(LightModel.funcNameCalcAlbedo, [], function() {
|
|
380
|
+
const diffuseMap = this[that.getTextureUniformName(TEX_NAME_ALBEDO)];
|
|
381
|
+
const texCoord = diffuseMap && this.$inputs[`texcoord${that.albedoMapTexCoord}`];
|
|
382
|
+
const vertexColor = scope.$query(ShaderFramework.USAGE_VERTEX_COLOR);
|
|
383
|
+
let val = scope.$query(LightModel.uniformAlbedoColor);
|
|
384
|
+
if (diffuseMap && texCoord) {
|
|
385
|
+
const tex = pb.textureSample(diffuseMap, texCoord);
|
|
386
|
+
val = pb.mul(val, tex);
|
|
387
|
+
}
|
|
388
|
+
if (vertexColor) {
|
|
389
|
+
val = pb.mul(val, vertexColor);
|
|
390
|
+
}
|
|
391
|
+
this.$return(val);
|
|
392
|
+
});
|
|
393
|
+
return pb.getGlobalScope()[LightModel.funcNameCalcAlbedo]();
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Samples tangent space normal map and then convert it to object space
|
|
397
|
+
* @param scope - The shader scope
|
|
398
|
+
* @param tex - Normal map
|
|
399
|
+
* @param texCoord - Sample texture coordinate
|
|
400
|
+
* @param normalScale - The normal scale
|
|
401
|
+
* @param TBN - The TBN matrix
|
|
402
|
+
* @returns Object space normal
|
|
403
|
+
*/ sampleNormalMapWithTBN(scope, tex, texCoord, normalScale, TBN) {
|
|
404
|
+
const pb = scope.$builder;
|
|
405
|
+
const pixel = pb.sub(pb.mul(pb.textureSample(tex, texCoord).rgb, 2), pb.vec3(1));
|
|
406
|
+
const normalTex = pb.mul(pixel, pb.vec3(pb.vec3(normalScale).xx, 1));
|
|
407
|
+
return pb.normalize(pb.mul(TBN, normalTex));
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Samples object space normal map
|
|
411
|
+
* @param scope - The shader scope
|
|
412
|
+
* @param tex - Normal map
|
|
413
|
+
* @param texCoord - Sample texture coordinate
|
|
414
|
+
* @param normalScale - The normal scale
|
|
415
|
+
* @returns Object space normal
|
|
416
|
+
*/ sampleNormalMap(scope, tex, texCoord, normalScale) {
|
|
417
|
+
const pb = scope.$builder;
|
|
418
|
+
const pixel = pb.sub(pb.mul(pb.textureSample(tex, texCoord).rgb, 2), pb.vec3(1));
|
|
419
|
+
const normalTex = pb.mul(pixel, pb.vec3(pb.vec3(normalScale).xx, 1));
|
|
420
|
+
return pb.normalize(normalTex);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Calculate pixel normal by given TBN matrix
|
|
424
|
+
* @param scope - The shader scope
|
|
425
|
+
* @param TBN - TBN matrix
|
|
426
|
+
* @returns Calculated pixel normal
|
|
427
|
+
*/ calculateNormalWithTBN(scope, texCoord, TBN) {
|
|
428
|
+
return this.normalMap ? this._normalMapMode === 'tangent-space' ? this.sampleNormalMapWithTBN(scope, scope[this.getTextureUniformName(TEX_NAME_NORMAL)], texCoord, scope.$query(LightModel.uniformNormalScale) || scope.$builder.float(1), TBN) : this.sampleNormalMap(scope, scope[this.getTextureUniformName(TEX_NAME_NORMAL)], texCoord, scope.$query(LightModel.uniformNormalScale) || scope.$builder.float(1)) : TBN[2];
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Calculate the normal vector for current fragment
|
|
432
|
+
* @param scope - The shader scope
|
|
433
|
+
* @param worldPosition - World space position of current fragment
|
|
434
|
+
* @param worldNormal - World space normal of current fragment
|
|
435
|
+
* @param worldTangent - World space tangent of current fragment
|
|
436
|
+
* @param worldBinormal - World space binormal of current fragment
|
|
437
|
+
* @returns Normal vector for current fragment
|
|
438
|
+
*/ calculateNormal(scope, worldPosition, worldNormal, worldTangent, worldBinormal) {
|
|
439
|
+
const pb = scope.$builder;
|
|
440
|
+
const uv = this.normalMap ? scope.$inputs[`texcoord${this.normalMapTexCoord}`] ?? pb.vec2(0) : this.albedoMap ? scope.$inputs[`texcoord${this.albedoMapTexCoord}`] ?? pb.vec2(0) : pb.vec2(0);
|
|
441
|
+
let TBN;
|
|
442
|
+
if (!worldNormal) {
|
|
443
|
+
TBN = calculateTBN(scope, worldPosition, uv, this._doubleSideLighting);
|
|
444
|
+
} else if (!worldTangent) {
|
|
445
|
+
TBN = calculateTBNWithNormal(scope, worldPosition, worldNormal, uv, this._doubleSideLighting);
|
|
446
|
+
} else {
|
|
447
|
+
TBN = pb.mat3(pb.normalize(worldTangent), pb.normalize(worldBinormal), pb.normalize(worldNormal));
|
|
448
|
+
}
|
|
449
|
+
return this.calculatePixelNormal(scope, TBN);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Calculates the final color of current fragment by composing individual light contribution
|
|
453
|
+
* @param scope - The shader scope
|
|
454
|
+
* @returns The final fragment color
|
|
455
|
+
*/ finalComposite(scope) {
|
|
456
|
+
const funcNameFinalComposite = 'lib_finalComposite';
|
|
457
|
+
const pb = scope.$builder;
|
|
458
|
+
const that = this;
|
|
459
|
+
pb.func(funcNameFinalComposite, [], function() {
|
|
460
|
+
this.surfaceData.accumColor = pb.add(this.surfaceData.accumDiffuse, this.surfaceData.accumSpecular, this.surfaceData.accumEmissive);
|
|
461
|
+
that.compositeSurfaceData(this);
|
|
462
|
+
this.$return(Material.debugChannel ? this.surfaceData.debugColor : pb.vec4(this.surfaceData.accumColor, this.surfaceData.diffuse.a));
|
|
463
|
+
});
|
|
464
|
+
return pb.getGlobalScope()[funcNameFinalComposite]();
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Gets the shader hash
|
|
468
|
+
* @returns shader hash
|
|
469
|
+
*/ getHash() {
|
|
470
|
+
if (this._hash === null) {
|
|
471
|
+
this._hash = `${this.constructor.name}_${this.calculateHash()}`;
|
|
472
|
+
}
|
|
473
|
+
return this._hash;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Peeks the shader hash
|
|
477
|
+
* @returns shader hash
|
|
478
|
+
*/ peekHash() {
|
|
479
|
+
return this._hash;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Composite surface data to produce the final color
|
|
483
|
+
* @param scope - The shader scope
|
|
484
|
+
*/ compositeSurfaceData(scope) {
|
|
485
|
+
// to be overriden
|
|
486
|
+
const pb = scope.$builder;
|
|
487
|
+
switch(Material.debugChannel){
|
|
488
|
+
case 'normal':
|
|
489
|
+
{
|
|
490
|
+
scope.surfaceData.debugColor = pb.vec4(pb.add(pb.mul(scope.surfaceData.TBN[2], 0.5), pb.vec3(0.5)), 1);
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
case 'tangent':
|
|
494
|
+
{
|
|
495
|
+
scope.surfaceData.debugColor = pb.vec4(pb.add(pb.mul(scope.surfaceData.TBN[0], 0.5), pb.vec3(0.5)), 1);
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
case 'binormal':
|
|
499
|
+
{
|
|
500
|
+
scope.surfaceData.debugColor = pb.vec4(pb.add(pb.mul(scope.surfaceData.TBN[1], 0.5), pb.vec3(0.5)), 1);
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
case 'shadingNormal':
|
|
504
|
+
{
|
|
505
|
+
scope.surfaceData.debugColor = pb.vec4(pb.add(pb.mul(scope.surfaceData.normal, 0.5), pb.vec3(0.5)), 1);
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Creates the surface data type
|
|
512
|
+
* @param env - The environment lighting object
|
|
513
|
+
* @returns The surface data type
|
|
514
|
+
*/ createSurfaceDataType(env) {
|
|
515
|
+
const debugColor = Material.debugChannel ? [
|
|
516
|
+
{
|
|
517
|
+
name: 'debugColor',
|
|
518
|
+
type: typeF32Vec4
|
|
519
|
+
}
|
|
520
|
+
] : [];
|
|
521
|
+
return new PBStructTypeInfo('', 'default', [
|
|
522
|
+
{
|
|
523
|
+
name: 'diffuse',
|
|
524
|
+
type: typeF32Vec4
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
name: 'normal',
|
|
528
|
+
type: typeF32Vec3
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
name: 'viewVec',
|
|
532
|
+
type: typeF32Vec3
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: 'NdotV',
|
|
536
|
+
type: typeF32
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
name: 'TBN',
|
|
540
|
+
type: typeMat3
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
name: 'accumDiffuse',
|
|
544
|
+
type: typeF32Vec3
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
name: 'accumSpecular',
|
|
548
|
+
type: typeF32Vec3
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
name: 'accumEmissive',
|
|
552
|
+
type: typeF32Vec3
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
name: 'accumColor',
|
|
556
|
+
type: typeF32Vec3
|
|
557
|
+
},
|
|
558
|
+
...debugColor
|
|
559
|
+
]);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Check if specified texture is being used
|
|
563
|
+
* @param name - The texture name
|
|
564
|
+
* @returns true if the texture is being used
|
|
565
|
+
*/ isTextureUsed(name) {
|
|
566
|
+
return !!this._textureOptions[name]?.texture;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Initial fill the surface data of current fragment
|
|
570
|
+
* @param scope - The shader scope
|
|
571
|
+
* @param envLight - The environment lighting object
|
|
572
|
+
*/ fillSurfaceData(scope, envLight) {
|
|
573
|
+
// to be overriden
|
|
574
|
+
if (Material.debugChannel) {
|
|
575
|
+
scope.surfaceData.debugColor = scope.$builder.vec4(scope.surfaceData.diffuse.rgb, 1);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Update all texture uniforms
|
|
580
|
+
* @param bindGroup - The bind group
|
|
581
|
+
*/ applyTextureUniforms(bindGroup) {
|
|
582
|
+
for(const k in this._textureOptions){
|
|
583
|
+
if (this.isTextureUsed(k)) {
|
|
584
|
+
const uniformName = this.getTextureUniformName(k);
|
|
585
|
+
const info = this._textureOptions[k];
|
|
586
|
+
bindGroup.setTexture(uniformName, info.texture, info.sampler);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Setup all texture uniforms
|
|
592
|
+
* @param scope - The shader scope
|
|
593
|
+
*/ setupTextureUniforms(scope) {
|
|
594
|
+
const pb = scope.$builder;
|
|
595
|
+
for(const k in this._textureOptions){
|
|
596
|
+
if (this.isTextureUsed(k)) {
|
|
597
|
+
const uniformName = this.getTextureUniformName(k);
|
|
598
|
+
const texture = this._textureOptions[k].texture;
|
|
599
|
+
let exp;
|
|
600
|
+
if (texture.isTexture2D()) {
|
|
601
|
+
exp = pb.tex2D().uniform(2);
|
|
602
|
+
} else if (texture.isTextureCube()) {
|
|
603
|
+
exp = pb.texCube().uniform(2);
|
|
604
|
+
} else if (texture.isTexture3D()) {
|
|
605
|
+
exp = pb.tex3D().uniform(2);
|
|
606
|
+
} else if (texture.isTexture2DArray()) {
|
|
607
|
+
exp = pb.tex2DArray().uniform(2);
|
|
608
|
+
} else if (texture.isTextureVideo()) {
|
|
609
|
+
exp = pb.texExternal().uniform(2);
|
|
610
|
+
} else {
|
|
611
|
+
throw new Error('Unsupported light model texture type');
|
|
612
|
+
}
|
|
613
|
+
if (!texture.isFilterable()) {
|
|
614
|
+
exp.sampleType('unfilterable-float');
|
|
615
|
+
}
|
|
616
|
+
scope[uniformName] = exp;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/** @internal */ addTexCoordChannel(srcLocation, transform) {
|
|
621
|
+
transform = transform || Matrix4x4.identity();
|
|
622
|
+
let index = this._texCoordChannels.findIndex((val)=>val.srcLocation === srcLocation && val.transform.equalsTo(transform));
|
|
623
|
+
if (index < 0) {
|
|
624
|
+
index = this._texCoordChannels.length;
|
|
625
|
+
this._texCoordChannels.push({
|
|
626
|
+
srcLocation,
|
|
627
|
+
transform: new Matrix4x4(transform)
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
return index;
|
|
631
|
+
}
|
|
632
|
+
/** @internal */ calculatePixelNormal(scope, TBN) {
|
|
633
|
+
const pixelNormal = this.calculateNormalWithTBN(scope, scope.$inputs[`texcoord${this.normalMapTexCoord}`], TBN);
|
|
634
|
+
const pb = scope.$builder;
|
|
635
|
+
return pb.defineStruct([
|
|
636
|
+
pb.mat3('TBN'),
|
|
637
|
+
pb.vec3('normal')
|
|
638
|
+
])(TBN, pixelNormal);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Notifies that the options has changed
|
|
642
|
+
* @param changeHash - true if the shader need to be rebuild
|
|
643
|
+
*/ optionChanged(changeHash) {
|
|
644
|
+
this._uniformVersion++;
|
|
645
|
+
if (changeHash) {
|
|
646
|
+
this._hash = null;
|
|
647
|
+
this._surfaceDataType = null;
|
|
648
|
+
this._hashVersion++;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Checks if the specified texture coordinate index is being used
|
|
653
|
+
* @param texCoordIndex - The texture coordinate index
|
|
654
|
+
* @returns true if the texture coordinate index is being used
|
|
655
|
+
*/ isTexCoordIndexUsed(texCoordIndex) {
|
|
656
|
+
return typeof this._texCoordChannels[texCoordIndex]?.srcLocation === 'number';
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Checks if the specified texture coordinate location is being used
|
|
660
|
+
* @param loc - The texture coordinate location
|
|
661
|
+
* @returns true if the texture coordinate location is being used
|
|
662
|
+
*/ isTexCoordSrcLocationUsed(loc) {
|
|
663
|
+
return this._texCoordChannels.findIndex((val)=>val.srcLocation === loc) >= 0;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Gets the location of a given texture coordinate index
|
|
667
|
+
* @param texCoordIndex - The texture coordinate index
|
|
668
|
+
* @returns The location of the given texture coordinate index
|
|
669
|
+
*/ getTexCoordSrcLocation(texCoordIndex) {
|
|
670
|
+
return this._texCoordChannels[texCoordIndex].srcLocation;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Checks if normal vector is being used
|
|
674
|
+
* @returns true if normal vector is being used
|
|
675
|
+
*/ isNormalUsed() {
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Updates uniforms of the shader program if needed
|
|
680
|
+
* @param bindGroup - The bind group
|
|
681
|
+
* @param ctx - The drawing context
|
|
682
|
+
*/ applyUniformsIfOutdated(bindGroup, ctx) {
|
|
683
|
+
const tags = this._bindGroupTagList.get(bindGroup);
|
|
684
|
+
if (!tags || tags[0] !== this._uniformVersion || tags[1] !== bindGroup.cid) {
|
|
685
|
+
if (tags) {
|
|
686
|
+
tags[0] = this._uniformVersion;
|
|
687
|
+
tags[1] = bindGroup.cid;
|
|
688
|
+
} else {
|
|
689
|
+
this._bindGroupTagList.set(bindGroup, [
|
|
690
|
+
this._uniformVersion,
|
|
691
|
+
bindGroup.cid
|
|
692
|
+
]);
|
|
693
|
+
}
|
|
694
|
+
this.applyUniforms(bindGroup, ctx);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Unlit light model
|
|
700
|
+
* @public
|
|
701
|
+
*/ class UnlitLightModel extends LightModel {
|
|
702
|
+
/**
|
|
703
|
+
* {@inheritDoc LightModel.supportLighting}
|
|
704
|
+
* @override
|
|
705
|
+
*/ supportLighting() {
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* {@inheritDoc LightModel.envBRDF}
|
|
710
|
+
* @override
|
|
711
|
+
*/ envBRDF(envLight, scope) {}
|
|
712
|
+
/**
|
|
713
|
+
* {@inheritDoc LightModel.directBRDF}
|
|
714
|
+
* @override
|
|
715
|
+
*/ directBRDF(scope, lightDir, attenuation) {}
|
|
716
|
+
/**
|
|
717
|
+
* {@inheritDoc LightModel.isNormalUsed}
|
|
718
|
+
* @override
|
|
719
|
+
*/ isNormalUsed() {
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* {@inheritDoc LightModel.compositeSurfaceData}
|
|
724
|
+
* @override
|
|
725
|
+
*/ compositeSurfaceData(scope) {
|
|
726
|
+
scope.surfaceData.accumColor = scope.surfaceData.diffuse.rgb;
|
|
727
|
+
super.compositeSurfaceData(scope);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Lambert light model
|
|
732
|
+
* @public
|
|
733
|
+
*/ class LambertLightModel extends LightModel {
|
|
734
|
+
static funcNameBRDFEnvIBL = 'lib_lambertLM_envIBL';
|
|
735
|
+
static funcNameBRDFDirect = 'lib_lambertLM_direct';
|
|
736
|
+
/**
|
|
737
|
+
* {@inheritDoc LightModel.supportLighting}
|
|
738
|
+
* @override
|
|
739
|
+
*/ supportLighting() {
|
|
740
|
+
return true;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* {@inheritDoc LightModel.envBRDF}
|
|
744
|
+
* @override
|
|
745
|
+
*/ envBRDF(envLight, scope) {
|
|
746
|
+
const pb = scope.$builder;
|
|
747
|
+
if (envLight?.hasIrradiance()) {
|
|
748
|
+
scope.surfaceData.accumDiffuse = pb.add(scope.surfaceData.accumDiffuse, pb.mul(envLight.getIrradiance(scope, scope.surfaceData.normal).rgb, scope.surfaceData.diffuse.rgb, ShaderFramework.getEnvLightStrength(scope)));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* {@inheritDoc LightModel.directBRDF}
|
|
753
|
+
* @override
|
|
754
|
+
*/ directBRDF(scope, lightDir, attenuation) {
|
|
755
|
+
const pb = scope.$builder;
|
|
756
|
+
pb.func(LambertLightModel.funcNameBRDFDirect, [
|
|
757
|
+
pb.vec3('attenuation')
|
|
758
|
+
], function() {
|
|
759
|
+
this.surfaceData.accumDiffuse = pb.add(this.surfaceData.accumDiffuse, pb.mul(this.surfaceData.diffuse.rgb, this.attenuation));
|
|
760
|
+
});
|
|
761
|
+
pb.getGlobalScope()[LambertLightModel.funcNameBRDFDirect](attenuation);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Blinn-phong light model
|
|
766
|
+
* @public
|
|
767
|
+
*/ class BlinnLightModel extends LightModel {
|
|
768
|
+
static funcNameBRDFEnvIBL = 'lib_blinnLM_envIBL';
|
|
769
|
+
static funcNameBRDFDirect = 'lib_blinnLM_direct';
|
|
770
|
+
/** @internal */ _shininess;
|
|
771
|
+
/**
|
|
772
|
+
* Creates an instance of BlinnLightModel
|
|
773
|
+
*/ constructor(){
|
|
774
|
+
super();
|
|
775
|
+
this._shininess = 32;
|
|
776
|
+
}
|
|
777
|
+
/** Shininess */ get shininess() {
|
|
778
|
+
return this._shininess;
|
|
779
|
+
}
|
|
780
|
+
set shininess(val) {
|
|
781
|
+
this._shininess = val;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* {@inheritDoc LightModel.supportLighting}
|
|
785
|
+
* @override
|
|
786
|
+
*/ supportLighting() {
|
|
787
|
+
return true;
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* {@inheritDoc LightModel.setupUniforms}
|
|
791
|
+
* @override
|
|
792
|
+
*/ setupUniforms(scope, ctx) {
|
|
793
|
+
super.setupUniforms(scope, ctx);
|
|
794
|
+
if (scope.$builder.shaderKind === 'fragment') {
|
|
795
|
+
scope.shininess = scope.$builder.float().uniform(2);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* {@inheritDoc LightModel.applyUniforms}
|
|
800
|
+
* @override
|
|
801
|
+
*/ applyUniforms(bindGroup, ctx) {
|
|
802
|
+
super.applyUniforms(bindGroup, ctx);
|
|
803
|
+
bindGroup.setValue('shininess', this._shininess);
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* {@inheritDoc LightModel.envBRDF}
|
|
807
|
+
* @override
|
|
808
|
+
*/ envBRDF(envLight, scope) {
|
|
809
|
+
const pb = scope.$builder;
|
|
810
|
+
if (envLight?.hasIrradiance()) {
|
|
811
|
+
scope.surfaceData.accumDiffuse = pb.add(scope.surfaceData.accumDiffuse, pb.mul(envLight.getIrradiance(scope, scope.surfaceData.normal).rgb, scope.surfaceData.diffuse.rgb, ShaderFramework.getEnvLightStrength(scope)));
|
|
812
|
+
}
|
|
813
|
+
/*
|
|
814
|
+
if (envLight?.hasRadiance()) {
|
|
815
|
+
const refl = pb.reflect(pb.neg(scope.surfaceData.viewVec), scope.surfaceData.normal);
|
|
816
|
+
const roughness = pb.sub(1, pb.clamp(pb.div(scope.shininess, 64), 0, 1));
|
|
817
|
+
scope.surfaceData.accumSpecular = pb.add(scope.surfaceData.accumSpecular, envLight.getRadiance(scope, refl, roughness));
|
|
818
|
+
}
|
|
819
|
+
*/ }
|
|
820
|
+
/**
|
|
821
|
+
* {@inheritDoc LightModel.directBRDF}
|
|
822
|
+
* @override
|
|
823
|
+
*/ directBRDF(scope, lightDir, attenuation) {
|
|
824
|
+
const pb = scope.$builder;
|
|
825
|
+
pb.func(BlinnLightModel.funcNameBRDFDirect, [
|
|
826
|
+
pb.vec3('lightDir'),
|
|
827
|
+
pb.vec3('attenuation')
|
|
828
|
+
], function() {
|
|
829
|
+
this.$l.halfVec = pb.normalize(pb.sub(this.surfaceData.viewVec, this.lightDir));
|
|
830
|
+
this.$l.NdotH = pb.clamp(pb.dot(this.surfaceData.normal, this.halfVec), 0, 1);
|
|
831
|
+
this.$l.outDiffuse = pb.mul(this.surfaceData.diffuse.rgb, this.attenuation);
|
|
832
|
+
this.$l.outSpecular = pb.mul(this.attenuation, pb.pow(this.NdotH, this.shininess));
|
|
833
|
+
this.surfaceData.accumSpecular = pb.add(this.surfaceData.accumSpecular, this.outSpecular);
|
|
834
|
+
this.surfaceData.accumDiffuse = pb.add(this.surfaceData.accumDiffuse, this.outDiffuse);
|
|
835
|
+
});
|
|
836
|
+
pb.getGlobalScope()[BlinnLightModel.funcNameBRDFDirect](lightDir, attenuation);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Base class for PBR light model
|
|
841
|
+
* @public
|
|
842
|
+
*/ class PBRLightModelBase extends LightModel {
|
|
843
|
+
/** @internal */ static funcNameCalcPBRLight = 'lib_PBRLM_calcPBRLight';
|
|
844
|
+
/** @internal */ static funcNameIllumEnvLight = 'lib_PBRLM_illumEnvLight_pbr';
|
|
845
|
+
/** @internal */ static uniformF0 = 'PBRLM_f0';
|
|
846
|
+
/** @internal */ static uniformOcclusionStrength = 'PBRLM_occlusionStrength';
|
|
847
|
+
/** @internal */ static uniformSheenFactor = 'lib_PBRLM_sheenFactor';
|
|
848
|
+
/** @internal */ static uniformClearcoatFactor = 'lib_PBRLM_clearcoatFactor';
|
|
849
|
+
/** @internal */ static uniformClearcoatNormalScale = 'lib_PBRLM_clearcoatNormalScale';
|
|
850
|
+
/** @internal */ static ggxLut = null;
|
|
851
|
+
/** @internal */ _f0;
|
|
852
|
+
/** @internal */ _occlusionStrength;
|
|
853
|
+
/** @internal */ _sheen;
|
|
854
|
+
/** @internal */ _sheenFactor;
|
|
855
|
+
/** @internal */ _clearcoat;
|
|
856
|
+
/** @internal */ _clearcoatFactor;
|
|
857
|
+
/** @internal */ static getGGXLUT() {
|
|
858
|
+
if (!this.ggxLut) {
|
|
859
|
+
this.ggxLut = this.createGGXLUT(Application.instance.device, 1024);
|
|
860
|
+
}
|
|
861
|
+
return this.ggxLut;
|
|
862
|
+
}
|
|
863
|
+
/** @internal */ static createGGXLUT(device, size) {
|
|
864
|
+
const program = device.buildRenderProgram({
|
|
865
|
+
vertex (pb) {
|
|
866
|
+
this.$inputs.pos = pb.vec2().attrib('position');
|
|
867
|
+
this.$outputs.uv = pb.vec2();
|
|
868
|
+
pb.main(function() {
|
|
869
|
+
this.$builtins.position = pb.vec4(this.$inputs.pos, 0, 1);
|
|
870
|
+
this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));
|
|
871
|
+
if (device.type === 'webgpu') {
|
|
872
|
+
this.$builtins.position.y = pb.neg(this.$builtins.position.y);
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
},
|
|
876
|
+
fragment (pb) {
|
|
877
|
+
this.$outputs.color = pb.vec4();
|
|
878
|
+
const SAMPLE_COUNT = 1024;
|
|
879
|
+
if (device.type === 'webgl') {
|
|
880
|
+
pb.func('radicalInverse_VdC', [
|
|
881
|
+
pb.int('bits')
|
|
882
|
+
], function() {
|
|
883
|
+
this.$l.rand = pb.float(0);
|
|
884
|
+
this.$l.denom = pb.float(1);
|
|
885
|
+
this.$l.invBase = pb.float(0.5);
|
|
886
|
+
this.$l.n = this.bits;
|
|
887
|
+
this.$for(pb.int('i'), 0, 32, function() {
|
|
888
|
+
this.denom = pb.mul(this.denom, 2);
|
|
889
|
+
this.rand = pb.add(this.rand, pb.div(pb.mod(pb.float(this.n), 2), this.denom));
|
|
890
|
+
this.n = pb.div(this.n, 2);
|
|
891
|
+
this.$if(pb.equal(this.n, 0), function() {
|
|
892
|
+
this.$break();
|
|
893
|
+
});
|
|
894
|
+
});
|
|
895
|
+
this.$return(this.rand);
|
|
896
|
+
});
|
|
897
|
+
pb.func('hammersley2d', [
|
|
898
|
+
pb.int('i'),
|
|
899
|
+
pb.int('N')
|
|
900
|
+
], function() {
|
|
901
|
+
this.$return(pb.vec2(pb.div(pb.float(this.i), pb.float(this.N)), this.radicalInverse_VdC(this.i)));
|
|
902
|
+
});
|
|
903
|
+
} else {
|
|
904
|
+
pb.func('radicalInverse_VdC', [
|
|
905
|
+
pb.uint('bits')
|
|
906
|
+
], function() {
|
|
907
|
+
this.$l.n = this.bits;
|
|
908
|
+
this.n = pb.compOr(pb.sal(this.n, 16), pb.sar(this.n, 16));
|
|
909
|
+
this.n = pb.compOr(pb.sal(pb.compAnd(this.n, 0x55555555), 1), pb.sar(pb.compAnd(this.n, 0xAAAAAAAA), 1));
|
|
910
|
+
this.n = pb.compOr(pb.sal(pb.compAnd(this.n, 0x33333333), 2), pb.sar(pb.compAnd(this.n, 0xCCCCCCCC), 2));
|
|
911
|
+
this.n = pb.compOr(pb.sal(pb.compAnd(this.n, 0x0F0F0F0F), 4), pb.sar(pb.compAnd(this.n, 0xF0F0F0F0), 4));
|
|
912
|
+
this.n = pb.compOr(pb.sal(pb.compAnd(this.n, 0x00FF00FF), 8), pb.sar(pb.compAnd(this.n, 0xFF00FF00), 8));
|
|
913
|
+
this.$return(pb.mul(pb.float(this.n), 2.3283064365386963e-10));
|
|
914
|
+
});
|
|
915
|
+
pb.func('hammersley2d', [
|
|
916
|
+
pb.int('i'),
|
|
917
|
+
pb.int('N')
|
|
918
|
+
], function() {
|
|
919
|
+
this.$return(pb.vec2(pb.div(pb.float(this.i), pb.float(this.N)), this.radicalInverse_VdC(pb.uint(this.i))));
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
pb.func('generateTBN', [
|
|
923
|
+
pb.vec3('normal')
|
|
924
|
+
], function() {
|
|
925
|
+
this.$l.bitangent = pb.vec3(0, 1, 0);
|
|
926
|
+
this.$l.NoU = this.normal.y;
|
|
927
|
+
this.$l.epsl = 0.0000001;
|
|
928
|
+
this.$if(pb.lessThanEqual(pb.sub(1, pb.abs(this.normal.y)), this.epsl), function() {
|
|
929
|
+
this.bitangent = this.$choice(pb.greaterThan(this.normal.y, 0), pb.vec3(0, 0, 1), pb.vec3(0, 0, -1));
|
|
930
|
+
});
|
|
931
|
+
this.$l.tangent = pb.normalize(pb.cross(this.bitangent, this.normal));
|
|
932
|
+
this.bitangent = pb.cross(this.normal, this.tangent);
|
|
933
|
+
this.$return(pb.mat3(this.tangent, this.bitangent, this.normal));
|
|
934
|
+
});
|
|
935
|
+
pb.func('D_Charlie', [
|
|
936
|
+
pb.float('sheenRoughness'),
|
|
937
|
+
pb.float('NdotH')
|
|
938
|
+
], function() {
|
|
939
|
+
this.$l.roughness = pb.max(this.sheenRoughness, 0.000001);
|
|
940
|
+
this.$l.invR = pb.div(1, this.roughness);
|
|
941
|
+
this.$l.cos2h = pb.mul(this.NdotH, this.NdotH);
|
|
942
|
+
this.$l.sin2h = pb.sub(1, this.cos2h);
|
|
943
|
+
this.$return(pb.div(pb.mul(pb.add(this.invR, 2), pb.pow(this.sin2h, pb.mul(this.invR, 0.5))), Math.PI * 2));
|
|
944
|
+
});
|
|
945
|
+
pb.func('smithGGXCorrelated', [
|
|
946
|
+
pb.float('NoV'),
|
|
947
|
+
pb.float('NoL'),
|
|
948
|
+
pb.float('roughness')
|
|
949
|
+
], function() {
|
|
950
|
+
this.$l.a2 = pb.mul(this.roughness, this.roughness, this.roughness, this.roughness);
|
|
951
|
+
this.$l.GGXV = pb.mul(this.NoL, pb.sqrt(pb.add(pb.mul(this.NoV, this.NoV, pb.sub(1, this.a2)), this.a2)));
|
|
952
|
+
this.$l.GGXL = pb.mul(this.NoV, pb.sqrt(pb.add(pb.mul(this.NoL, this.NoL, pb.sub(1, this.a2)), this.a2)));
|
|
953
|
+
this.$return(pb.div(0.5, pb.add(this.GGXV, this.GGXL)));
|
|
954
|
+
});
|
|
955
|
+
pb.func('V_Ashikhmin', [
|
|
956
|
+
pb.float('NdotL'),
|
|
957
|
+
pb.float('NdotV')
|
|
958
|
+
], function() {
|
|
959
|
+
this.$return(pb.clamp(pb.div(1, pb.mul(pb.sub(pb.add(this.NdotL, this.NdotV), pb.mul(this.NdotL, this.NdotV)), 4)), 0, 1));
|
|
960
|
+
});
|
|
961
|
+
pb.func('importanceSample', [
|
|
962
|
+
pb.vec2('xi'),
|
|
963
|
+
pb.vec3('normal'),
|
|
964
|
+
pb.float('roughness'),
|
|
965
|
+
pb.vec3('ggx').out(),
|
|
966
|
+
pb.vec3('charlie').out()
|
|
967
|
+
], function() {
|
|
968
|
+
this.$l.alphaRoughness = pb.mul(this.roughness, this.roughness);
|
|
969
|
+
this.$l.cosTheta = pb.clamp(pb.sqrt(pb.div(pb.sub(1, this.xi.y), pb.add(1, pb.mul(pb.sub(pb.mul(this.alphaRoughness, this.alphaRoughness), 1), this.xi.y)))), 0, 1);
|
|
970
|
+
this.$l.sinTheta = pb.sqrt(pb.sub(1, pb.mul(this.cosTheta, this.cosTheta)));
|
|
971
|
+
this.$l.phi = pb.mul(this.xi.x, Math.PI * 2);
|
|
972
|
+
this.$l.TBN = this.generateTBN(this.normal);
|
|
973
|
+
this.$l.localSpaceDir = pb.normalize(pb.vec3(pb.mul(this.sinTheta, pb.cos(this.phi)), pb.mul(this.sinTheta, pb.sin(this.phi)), this.cosTheta));
|
|
974
|
+
this.ggx = pb.mul(this.TBN, this.localSpaceDir);
|
|
975
|
+
this.sinTheta = pb.pow(this.xi.y, pb.div(this.alphaRoughness, pb.add(pb.mul(this.alphaRoughness, 2), 1)));
|
|
976
|
+
this.cosTheta = pb.sqrt(pb.sub(1, pb.mul(this.sinTheta, this.sinTheta)));
|
|
977
|
+
this.localSpaceDir = pb.normalize(pb.vec3(pb.mul(this.sinTheta, pb.cos(this.phi)), pb.mul(this.sinTheta, pb.sin(this.phi)), this.cosTheta));
|
|
978
|
+
this.charlie = pb.mul(this.TBN, this.localSpaceDir);
|
|
979
|
+
});
|
|
980
|
+
pb.func('integrateBRDF', [
|
|
981
|
+
pb.float('NoV'),
|
|
982
|
+
pb.float('roughness')
|
|
983
|
+
], function() {
|
|
984
|
+
this.$l.V = pb.vec3(pb.sub(1, pb.mul(this.NoV, this.NoV)), 0, this.NoV);
|
|
985
|
+
this.$l.a = pb.float(0);
|
|
986
|
+
this.$l.b = pb.float(0);
|
|
987
|
+
this.$l.c = pb.float(0);
|
|
988
|
+
this.$l.n = pb.vec3(0, 0, 1);
|
|
989
|
+
this.$for(pb.int('i'), 0, SAMPLE_COUNT, function() {
|
|
990
|
+
this.$l.xi = this.hammersley2d(this.i, SAMPLE_COUNT);
|
|
991
|
+
this.$l.ggxSample = pb.vec3();
|
|
992
|
+
this.$l.charlieSample = pb.vec3();
|
|
993
|
+
this.importanceSample(this.xi, this.n, this.roughness, this.ggxSample, this.charlieSample);
|
|
994
|
+
this.$l.ggxL = pb.normalize(pb.reflect(pb.neg(this.V), this.ggxSample.xyz));
|
|
995
|
+
this.$l.ggxNoL = pb.clamp(this.ggxL.z, 0, 1);
|
|
996
|
+
this.$l.ggxNoH = pb.clamp(this.ggxSample.z, 0, 1);
|
|
997
|
+
this.$l.ggxVoH = pb.clamp(pb.dot(this.V, this.ggxSample.xyz), 0, 1);
|
|
998
|
+
this.$l.charlieL = pb.normalize(pb.reflect(pb.neg(this.V), this.charlieSample.xyz));
|
|
999
|
+
this.$l.charlieNoL = pb.clamp(this.charlieL.z, 0, 1);
|
|
1000
|
+
this.$l.charlieNoH = pb.clamp(this.charlieSample.z, 0, 1);
|
|
1001
|
+
this.$l.charlieVoH = pb.clamp(pb.dot(this.V, this.charlieSample.xyz), 0, 1);
|
|
1002
|
+
this.$if(pb.greaterThan(this.ggxNoL, 0), function() {
|
|
1003
|
+
this.$l.pdf = pb.div(pb.mul(this.smithGGXCorrelated(this.NoV, this.ggxNoL, this.roughness), this.ggxVoH, this.ggxNoL), this.ggxNoH);
|
|
1004
|
+
this.$l.Fc = pb.pow(pb.sub(1, this.ggxVoH), 5);
|
|
1005
|
+
this.a = pb.add(this.a, pb.mul(pb.sub(1, this.Fc), this.pdf));
|
|
1006
|
+
this.b = pb.add(this.b, pb.mul(this.Fc, this.pdf));
|
|
1007
|
+
});
|
|
1008
|
+
this.$if(pb.greaterThan(this.charlieNoL, 0), function() {
|
|
1009
|
+
this.$l.sheenDistribution = this.D_Charlie(this.roughness, this.charlieNoH);
|
|
1010
|
+
this.$l.sheenVis = this.V_Ashikhmin(this.charlieNoL, this.NoV);
|
|
1011
|
+
this.c = pb.add(this.c, pb.mul(this.sheenVis, this.sheenDistribution, this.charlieNoL, this.charlieVoH));
|
|
1012
|
+
});
|
|
1013
|
+
});
|
|
1014
|
+
this.$return(pb.div(pb.vec3(pb.mul(this.a, 4), pb.mul(this.b, 4), pb.mul(this.c, 8 * Math.PI)), SAMPLE_COUNT));
|
|
1015
|
+
});
|
|
1016
|
+
pb.main(function() {
|
|
1017
|
+
this.$outputs.color = pb.vec4(this.integrateBRDF(this.$inputs.uv.x, this.$inputs.uv.y), 1);
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
const vertexLayout = device.createVertexLayout({
|
|
1022
|
+
vertexBuffers: [
|
|
1023
|
+
{
|
|
1024
|
+
buffer: device.createVertexBuffer('position_f32x2', new Float32Array([
|
|
1025
|
+
-1,
|
|
1026
|
+
-1,
|
|
1027
|
+
1,
|
|
1028
|
+
-1,
|
|
1029
|
+
-1,
|
|
1030
|
+
1,
|
|
1031
|
+
1,
|
|
1032
|
+
1
|
|
1033
|
+
]))
|
|
1034
|
+
}
|
|
1035
|
+
]
|
|
1036
|
+
});
|
|
1037
|
+
const rs = device.createRenderStateSet();
|
|
1038
|
+
rs.useRasterizerState().setCullMode('none');
|
|
1039
|
+
rs.useDepthState().enableTest(false).enableWrite(false);
|
|
1040
|
+
const tex = device.createTexture2D('rgba8unorm', size, size, {
|
|
1041
|
+
samplerOptions: {
|
|
1042
|
+
mipFilter: 'none'
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
tex.name = 'GGXLUT';
|
|
1046
|
+
const fb = device.createFrameBuffer([
|
|
1047
|
+
tex
|
|
1048
|
+
], null);
|
|
1049
|
+
device.pushDeviceStates();
|
|
1050
|
+
device.setProgram(program);
|
|
1051
|
+
device.setVertexLayout(vertexLayout);
|
|
1052
|
+
device.setRenderStates(rs);
|
|
1053
|
+
device.setFramebuffer(fb);
|
|
1054
|
+
device.draw('triangle-strip', 0, 4);
|
|
1055
|
+
device.popDeviceStates();
|
|
1056
|
+
fb.dispose();
|
|
1057
|
+
vertexLayout.dispose();
|
|
1058
|
+
program.dispose();
|
|
1059
|
+
return tex;
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Creates an instance of PBRLightModelBase
|
|
1063
|
+
*/ constructor(){
|
|
1064
|
+
super();
|
|
1065
|
+
this._f0 = new Vector4(0.04, 0.04, 0.04, 1.5);
|
|
1066
|
+
this._sheen = false;
|
|
1067
|
+
this._sheenFactor = Vector4.zero();
|
|
1068
|
+
this._clearcoat = false;
|
|
1069
|
+
this._clearcoatFactor = new Vector4(0, 0, 1, 0);
|
|
1070
|
+
this._occlusionStrength = 1;
|
|
1071
|
+
}
|
|
1072
|
+
/** ior value */ get ior() {
|
|
1073
|
+
return this._f0.w;
|
|
1074
|
+
}
|
|
1075
|
+
set ior(val) {
|
|
1076
|
+
if (val !== this._f0.w) {
|
|
1077
|
+
let k = (val - 1) / (val + 1);
|
|
1078
|
+
k *= k;
|
|
1079
|
+
this._f0.setXYZW(k, k, k, val);
|
|
1080
|
+
this.optionChanged(false);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
/** occlusion strength */ get occlusionStrength() {
|
|
1084
|
+
return this._occlusionStrength;
|
|
1085
|
+
}
|
|
1086
|
+
set occlusionStrength(val) {
|
|
1087
|
+
if (this._occlusionStrength !== val) {
|
|
1088
|
+
this._occlusionStrength = val;
|
|
1089
|
+
if (this.occlusionMap) {
|
|
1090
|
+
this.optionChanged(false);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
/** The occlusion texture */ get occlusionMap() {
|
|
1095
|
+
return (this._textureOptions[TEX_NAME_OCCLUSION]?.texture) ?? null;
|
|
1096
|
+
}
|
|
1097
|
+
/** Sampler of the occlusion texture */ get occlusionSampler() {
|
|
1098
|
+
return this._textureOptions[TEX_NAME_OCCLUSION]?.sampler ?? null;
|
|
1099
|
+
}
|
|
1100
|
+
/** Texture coordinate index of the occlusion texture */ get occlusionMapTexCoord() {
|
|
1101
|
+
return this._textureOptions[TEX_NAME_OCCLUSION]?.texCoordIndex ?? null;
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Sets the occlusion texture
|
|
1105
|
+
* @param tex - The texture to set
|
|
1106
|
+
* @param sampler - Sampler of the texture
|
|
1107
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1108
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1109
|
+
*/ setOcclusionMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1110
|
+
this.setTextureOptions(TEX_NAME_OCCLUSION, tex, sampler, texCoordIndex, texTransform);
|
|
1111
|
+
}
|
|
1112
|
+
/** true if sheen lighting is being used */ get useSheen() {
|
|
1113
|
+
return this._sheen;
|
|
1114
|
+
}
|
|
1115
|
+
set useSheen(val) {
|
|
1116
|
+
if (this._sheen !== !!val) {
|
|
1117
|
+
this._sheen = !!val;
|
|
1118
|
+
this.optionChanged(true);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
/** Color factor for sheen lighting */ get sheenColorFactor() {
|
|
1122
|
+
return this._sheenFactor.xyz();
|
|
1123
|
+
}
|
|
1124
|
+
set sheenColorFactor(val) {
|
|
1125
|
+
if (val.x !== this._sheenFactor.x || val.y !== this._sheenFactor.y || val.z !== this._sheenFactor.z) {
|
|
1126
|
+
this._sheenFactor.x = val.x;
|
|
1127
|
+
this._sheenFactor.y = val.y;
|
|
1128
|
+
this._sheenFactor.z = val.z;
|
|
1129
|
+
if (this._sheen) {
|
|
1130
|
+
this.optionChanged(false);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
/** Roughness factor for sheen lighting */ get sheenRoughnessFactor() {
|
|
1135
|
+
return this._sheenFactor.w;
|
|
1136
|
+
}
|
|
1137
|
+
set sheenRoughnessFactor(val) {
|
|
1138
|
+
if (val !== this._sheenFactor.w) {
|
|
1139
|
+
this._sheenFactor.w = val;
|
|
1140
|
+
if (this._sheen) {
|
|
1141
|
+
this.optionChanged(false);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
/** Lut texture for sheen lighting */ get sheenLut() {
|
|
1146
|
+
return (this._textureOptions[TEX_NAME_SHEEN_LUT]?.texture) ?? null;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Sets the lut texture for sheen lighting
|
|
1150
|
+
* @param tex - The texture to set
|
|
1151
|
+
*/ setSheenLut(tex) {
|
|
1152
|
+
this.setTextureOptions(TEX_NAME_SHEEN_LUT, tex, null, 0, null);
|
|
1153
|
+
}
|
|
1154
|
+
/** The sheen color texture */ get sheenColorMap() {
|
|
1155
|
+
return (this._textureOptions[TEX_NAME_SHEEN_COLOR]?.texture) ?? null;
|
|
1156
|
+
}
|
|
1157
|
+
/** Sampler of the sheen color texture */ get sheenColorSampler() {
|
|
1158
|
+
return this._textureOptions[TEX_NAME_SHEEN_COLOR]?.sampler ?? null;
|
|
1159
|
+
}
|
|
1160
|
+
/** Texture coordinate index of the sheen color texture */ get sheenColorMapTexCoord() {
|
|
1161
|
+
return this._textureOptions[TEX_NAME_SHEEN_COLOR]?.texCoordIndex ?? null;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Sets the sheen color texture
|
|
1165
|
+
* @param tex - The texture to set
|
|
1166
|
+
* @param sampler - Sampler of the texture
|
|
1167
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1168
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1169
|
+
*/ setSheenColorMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1170
|
+
this.setTextureOptions(TEX_NAME_SHEEN_COLOR, tex, sampler, texCoordIndex, texTransform);
|
|
1171
|
+
}
|
|
1172
|
+
/** The sheen roughness texture */ get sheenRoughnessMap() {
|
|
1173
|
+
return (this._textureOptions[TEX_NAME_SHEEN_ROUGHNESS]?.texture) ?? null;
|
|
1174
|
+
}
|
|
1175
|
+
/** Sampler of the sheen roughness texture */ get sheenRoughnessSampler() {
|
|
1176
|
+
return this._textureOptions[TEX_NAME_SHEEN_ROUGHNESS]?.sampler ?? null;
|
|
1177
|
+
}
|
|
1178
|
+
get sheenRoughnessMapTexCoord() {
|
|
1179
|
+
return this._textureOptions[TEX_NAME_SHEEN_ROUGHNESS]?.texCoordIndex ?? null;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Sets the sheen roughness texture
|
|
1183
|
+
* @param tex - The texture to set
|
|
1184
|
+
* @param sampler - Sampler of the texture
|
|
1185
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1186
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1187
|
+
*/ setSheenRoughnessMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1188
|
+
this.setTextureOptions(TEX_NAME_SHEEN_ROUGHNESS, tex, sampler, texCoordIndex, texTransform);
|
|
1189
|
+
}
|
|
1190
|
+
/** true if the clearcoat lighting is enabled */ get useClearcoat() {
|
|
1191
|
+
return this._clearcoat;
|
|
1192
|
+
}
|
|
1193
|
+
set useClearcoat(val) {
|
|
1194
|
+
if (this._clearcoat !== !!val) {
|
|
1195
|
+
this._clearcoat = !!val;
|
|
1196
|
+
this.optionChanged(true);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
/** Intensity of clearcoat lighting */ get clearcoatIntensity() {
|
|
1200
|
+
return this._clearcoatFactor.x;
|
|
1201
|
+
}
|
|
1202
|
+
set clearcoatIntensity(val) {
|
|
1203
|
+
if (val !== this._clearcoatFactor.x) {
|
|
1204
|
+
this._clearcoatFactor.x = val;
|
|
1205
|
+
if (this._clearcoat) {
|
|
1206
|
+
this.optionChanged(false);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
/** Roughness factor of clearcoat lighting */ get clearcoatRoughnessFactor() {
|
|
1211
|
+
return this._clearcoatFactor.y;
|
|
1212
|
+
}
|
|
1213
|
+
set clearcoatRoughnessFactor(val) {
|
|
1214
|
+
if (val !== this._clearcoatFactor.y) {
|
|
1215
|
+
this._clearcoatFactor.y = val;
|
|
1216
|
+
if (this._clearcoat) {
|
|
1217
|
+
this.optionChanged(false);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
/** Normal scale of clearcoat lighting */ get clearcoatNormalScale() {
|
|
1222
|
+
return this._clearcoatFactor.z;
|
|
1223
|
+
}
|
|
1224
|
+
set clearcoatNormalScale(val) {
|
|
1225
|
+
if (val !== this._clearcoatFactor.z) {
|
|
1226
|
+
this._clearcoatFactor.z = val;
|
|
1227
|
+
if (this._clearcoat) {
|
|
1228
|
+
this.optionChanged(false);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
/** The clearcoat intensity texture */ get clearcoatIntensityMap() {
|
|
1233
|
+
return (this._textureOptions[TEX_NAME_CLEARCOAT_INTENSITY]?.texture) ?? null;
|
|
1234
|
+
}
|
|
1235
|
+
/** Sampler of the clearcoat intensity texture */ get clearcoatIntensitySampler() {
|
|
1236
|
+
return this._textureOptions[TEX_NAME_CLEARCOAT_INTENSITY]?.sampler ?? null;
|
|
1237
|
+
}
|
|
1238
|
+
/** Texture coordinate index of the clearcoat intensity texture */ get clearcoatIntensityMapTexCoord() {
|
|
1239
|
+
return this._textureOptions[TEX_NAME_CLEARCOAT_INTENSITY]?.texCoordIndex ?? null;
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Sets the clearcoat intensity texture
|
|
1243
|
+
* @param tex - The texture to set
|
|
1244
|
+
* @param sampler - Sampler of the texture
|
|
1245
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1246
|
+
* @param texTransform - Transformation matrox for texture coordinates of the texture
|
|
1247
|
+
*/ setClearcoatIntensityMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1248
|
+
this.setTextureOptions(TEX_NAME_CLEARCOAT_INTENSITY, tex, sampler, texCoordIndex, texTransform);
|
|
1249
|
+
}
|
|
1250
|
+
/** The clearcoat roughness texture */ get clearcoatRoughnessMap() {
|
|
1251
|
+
return (this._textureOptions[TEX_NAME_CLEARCOAT_ROUGHNESS]?.texture) ?? null;
|
|
1252
|
+
}
|
|
1253
|
+
/** Sampler of the clearcoat roughness texture */ get clearcoatRoughnessSampler() {
|
|
1254
|
+
return this._textureOptions[TEX_NAME_CLEARCOAT_ROUGHNESS]?.sampler ?? null;
|
|
1255
|
+
}
|
|
1256
|
+
/** Texture coordinate index of the clearcoat roughness texture */ get clearcoatRoughnessMapTexCoord() {
|
|
1257
|
+
return this._textureOptions[TEX_NAME_CLEARCOAT_ROUGHNESS]?.texCoordIndex ?? null;
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Sets the clearcoat roughness texture
|
|
1261
|
+
* @param tex - The texture to set
|
|
1262
|
+
* @param sampler - Sampler of the texture
|
|
1263
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1264
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1265
|
+
*/ setClearcoatRoughnessMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1266
|
+
this.setTextureOptions(TEX_NAME_CLEARCOAT_ROUGHNESS, tex, sampler, texCoordIndex, texTransform);
|
|
1267
|
+
}
|
|
1268
|
+
/** The clearcoat normal texture */ get clearcoatNormalMap() {
|
|
1269
|
+
return (this._textureOptions[TEX_NAME_CLEARCOAT_NORMAL]?.texture) ?? null;
|
|
1270
|
+
}
|
|
1271
|
+
/** Sampler of the clearcoat normal texture */ get clearcoatNormalSampler() {
|
|
1272
|
+
return this._textureOptions[TEX_NAME_CLEARCOAT_NORMAL]?.sampler ?? null;
|
|
1273
|
+
}
|
|
1274
|
+
/** Texture coordinate index of the clearcoat normal texture */ get clearcoatNormalMapTexCoord() {
|
|
1275
|
+
return this._textureOptions[TEX_NAME_CLEARCOAT_NORMAL]?.texCoordIndex ?? null;
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Sets the clearcoat normal texture
|
|
1279
|
+
* @param tex - The texture to set
|
|
1280
|
+
* @param sampler - Sampler of the texture
|
|
1281
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1282
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1283
|
+
*/ setClearcoatNormalMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1284
|
+
this.setTextureOptions(TEX_NAME_CLEARCOAT_NORMAL, tex, sampler, texCoordIndex, texTransform);
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* {@inheritDoc LightModel.calculateHash}
|
|
1288
|
+
* @override
|
|
1289
|
+
*/ calculateHash() {
|
|
1290
|
+
const occlusionHash = this.occlusionMap ? this.occlusionMapTexCoord + 1 : 0;
|
|
1291
|
+
const ccIntensityHash = this.clearcoatIntensityMap ? this.clearcoatIntensityMapTexCoord + 1 : 0;
|
|
1292
|
+
const ccRoughnessHash = this.clearcoatRoughnessMap ? this.clearcoatRoughnessMapTexCoord + 1 : 0;
|
|
1293
|
+
const ccNormalHash = this.clearcoatNormalMap ? this.clearcoatNormalMapTexCoord + 1 : 0;
|
|
1294
|
+
const ccHash = this.useClearcoat ? `(${ccIntensityHash}-${ccRoughnessHash}-${ccNormalHash})` : '';
|
|
1295
|
+
const sheenColorHash = this.sheenColorMap ? this.sheenColorMapTexCoord + 1 : 0;
|
|
1296
|
+
const sheenRoughnessHash = this.sheenRoughnessMap ? this.sheenRoughnessMapTexCoord + 1 : 0;
|
|
1297
|
+
const sheenHash = this.useSheen ? `(${sheenColorHash}-${sheenRoughnessHash})` : '';
|
|
1298
|
+
return `${super.calculateHash()}_${occlusionHash}_${sheenHash}_${ccHash}`;
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* {@inheritDoc LightModel.setupUniforms}
|
|
1302
|
+
* @override
|
|
1303
|
+
*/ setupUniforms(scope, ctx) {
|
|
1304
|
+
super.setupUniforms(scope, ctx);
|
|
1305
|
+
if (scope.$builder.shaderKind === 'fragment') {
|
|
1306
|
+
if (ctx.drawEnvLight) {
|
|
1307
|
+
scope.ggxLut = scope.$builder.tex2D().uniform(2);
|
|
1308
|
+
}
|
|
1309
|
+
scope.lm_f0 = scope.$builder.vec4().uniform(2).tag(PBRLightModelBase.uniformF0);
|
|
1310
|
+
if (this.occlusionMap) {
|
|
1311
|
+
scope.lm_occlusionStrength = scope.$builder.float().uniform(2).tag(PBRLightModelBase.uniformOcclusionStrength);
|
|
1312
|
+
}
|
|
1313
|
+
if (this._sheen) {
|
|
1314
|
+
scope.lm_sheenFactor = scope.$builder.vec4().uniform(2).tag(PBRLightModelBase.uniformSheenFactor);
|
|
1315
|
+
}
|
|
1316
|
+
if (this._clearcoat) {
|
|
1317
|
+
scope.lm_clearcoatFactor = scope.$builder.vec4().uniform(2).tag(PBRLightModelBase.uniformClearcoatFactor);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* {@inheritDoc LightModel.applyUniforms}
|
|
1323
|
+
* @override
|
|
1324
|
+
*/ applyUniforms(bindGroup, ctx) {
|
|
1325
|
+
super.applyUniforms(bindGroup, ctx);
|
|
1326
|
+
if (ctx.drawEnvLight) {
|
|
1327
|
+
bindGroup.setTexture('ggxLut', PBRLightModelBase.getGGXLUT());
|
|
1328
|
+
}
|
|
1329
|
+
bindGroup.setValue('lm_f0', this._f0);
|
|
1330
|
+
if (this.occlusionMap) {
|
|
1331
|
+
bindGroup.setValue('lm_occlusionStrength', this._occlusionStrength);
|
|
1332
|
+
}
|
|
1333
|
+
if (this._sheen) {
|
|
1334
|
+
bindGroup.setValue('lm_sheenFactor', this._sheenFactor);
|
|
1335
|
+
}
|
|
1336
|
+
if (this._clearcoat) {
|
|
1337
|
+
bindGroup.setValue('lm_clearcoatFactor', this._clearcoatFactor);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* {@inheritDoc LightModel.createSurfaceDataType}
|
|
1342
|
+
* @override
|
|
1343
|
+
*/ createSurfaceDataType(env) {
|
|
1344
|
+
const type = super.createSurfaceDataType(env);
|
|
1345
|
+
const props = [
|
|
1346
|
+
{
|
|
1347
|
+
name: 'metallic',
|
|
1348
|
+
type: typeF32
|
|
1349
|
+
},
|
|
1350
|
+
{
|
|
1351
|
+
name: 'roughness',
|
|
1352
|
+
type: typeF32
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
name: 'f0',
|
|
1356
|
+
type: typeF32Vec4
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
name: 'f90',
|
|
1360
|
+
type: typeF32Vec3
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
name: 'occlusion',
|
|
1364
|
+
type: typeF32Vec4
|
|
1365
|
+
},
|
|
1366
|
+
{
|
|
1367
|
+
name: 'irradiance',
|
|
1368
|
+
type: typeF32Vec3
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
name: 'radiance',
|
|
1372
|
+
type: typeF32Vec3
|
|
1373
|
+
}
|
|
1374
|
+
];
|
|
1375
|
+
if (env) {
|
|
1376
|
+
props.push({
|
|
1377
|
+
name: 'ggxLutSample',
|
|
1378
|
+
type: typeF32Vec4
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
if (this._sheen) {
|
|
1382
|
+
props.push({
|
|
1383
|
+
name: 'sheenColor',
|
|
1384
|
+
type: typeF32Vec3
|
|
1385
|
+
}, {
|
|
1386
|
+
name: 'sheenRoughness',
|
|
1387
|
+
type: typeF32
|
|
1388
|
+
}, {
|
|
1389
|
+
name: 'sheenAlbedoScaling',
|
|
1390
|
+
type: typeF32
|
|
1391
|
+
}, {
|
|
1392
|
+
name: 'sheenContrib',
|
|
1393
|
+
type: typeF32Vec3
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
if (this._clearcoat) {
|
|
1397
|
+
props.push({
|
|
1398
|
+
name: 'clearcoatFactor',
|
|
1399
|
+
type: typeF32Vec4
|
|
1400
|
+
}, {
|
|
1401
|
+
name: 'clearcoatNormal',
|
|
1402
|
+
type: typeF32Vec3
|
|
1403
|
+
}, {
|
|
1404
|
+
name: 'clearcoatNdotV',
|
|
1405
|
+
type: typeF32
|
|
1406
|
+
}, {
|
|
1407
|
+
name: 'clearcoatFresnel',
|
|
1408
|
+
type: typeF32Vec3
|
|
1409
|
+
}, {
|
|
1410
|
+
name: 'clearcoatContrib',
|
|
1411
|
+
type: typeF32Vec3
|
|
1412
|
+
}, {
|
|
1413
|
+
name: 'radianceClearcoat',
|
|
1414
|
+
type: typeF32Vec3
|
|
1415
|
+
});
|
|
1416
|
+
if (env) {
|
|
1417
|
+
props.push({
|
|
1418
|
+
name: 'clearcoatGGXLutSample',
|
|
1419
|
+
type: typeF32Vec4
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
return props.length > 0 ? type.extends('', props) : type;
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* {@inheritDoc LightModel.fillSurfaceData}
|
|
1427
|
+
* @override
|
|
1428
|
+
*/ fillSurfaceData(scope, envLight) {
|
|
1429
|
+
super.fillSurfaceData(scope, envLight);
|
|
1430
|
+
const funcNameFillSurfaceDataPBRCommon = 'lib_fillSurfaceDataPBRCommon';
|
|
1431
|
+
const pb = scope.$builder;
|
|
1432
|
+
const that = this;
|
|
1433
|
+
pb.func(funcNameFillSurfaceDataPBRCommon, [], function() {
|
|
1434
|
+
this.surfaceData.f0 = this.$query(PBRLightModelBase.uniformF0);
|
|
1435
|
+
this.surfaceData.f90 = pb.vec3(1);
|
|
1436
|
+
const strength = ShaderFramework.getEnvLightStrength(this);
|
|
1437
|
+
if (that.occlusionMap) {
|
|
1438
|
+
const occlusionStrength = this.$query(PBRLightModelBase.uniformOcclusionStrength);
|
|
1439
|
+
const texCoord = this.$inputs[`texcoord${that.occlusionMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1440
|
+
this.surfaceData.occlusion = pb.textureSample(this[that.getTextureUniformName(TEX_NAME_OCCLUSION)], texCoord);
|
|
1441
|
+
this.surfaceData.occlusion.r = pb.mul(pb.add(pb.mul(occlusionStrength, pb.sub(this.surfaceData.occlusion.r, 1)), 1), strength);
|
|
1442
|
+
} else {
|
|
1443
|
+
this.surfaceData.occlusion = pb.vec4(strength);
|
|
1444
|
+
}
|
|
1445
|
+
if (that.useClearcoat) {
|
|
1446
|
+
this.surfaceData.clearcoatFactor = this.$query(PBRLightModelBase.uniformClearcoatFactor);
|
|
1447
|
+
if (that.clearcoatNormalMap) {
|
|
1448
|
+
const clearcoatNormalMap = this[that.getTextureUniformName(TEX_NAME_CLEARCOAT_NORMAL)];
|
|
1449
|
+
const texCoord = this.$inputs[`texcoord${that.clearcoatNormalMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1450
|
+
this.$l.ccNormal = pb.sub(pb.mul(pb.textureSample(clearcoatNormalMap, texCoord).rgb, 2), pb.vec3(1));
|
|
1451
|
+
this.ccNormal = pb.mul(this.ccNormal, pb.vec3(this.surfaceData.clearcoatFactor.z, this.surfaceData.clearcoatFactor.z, 1));
|
|
1452
|
+
this.surfaceData.clearcoatNormal = pb.normalize(pb.mul(this.surfaceData.TBN, this.ccNormal));
|
|
1453
|
+
this.surfaceData.clearcoatNdotV = pb.clamp(pb.dot(this.surfaceData.clearcoatNormal, this.surfaceData.viewVec), 0.0001, 1);
|
|
1454
|
+
} else {
|
|
1455
|
+
this.surfaceData.clearcoatNormal = this.surfaceData.TBN[2];
|
|
1456
|
+
this.surfaceData.clearcoatNdotV = this.surfaceData.NdotV;
|
|
1457
|
+
}
|
|
1458
|
+
if (that.clearcoatIntensityMap) {
|
|
1459
|
+
const clearcoatIntensityMap = this[that.getTextureUniformName(TEX_NAME_CLEARCOAT_INTENSITY)];
|
|
1460
|
+
const texCoord = this.$inputs[`texcoord${that.clearcoatIntensityMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1461
|
+
this.surfaceData.clearcoatFactor.x = pb.mul(this.surfaceData.clearcoatFactor.x, pb.textureSample(clearcoatIntensityMap, texCoord).r);
|
|
1462
|
+
}
|
|
1463
|
+
if (that.clearcoatRoughnessMap) {
|
|
1464
|
+
const clearcoatRoughnessMap = this[that.getTextureUniformName(TEX_NAME_CLEARCOAT_ROUGHNESS)];
|
|
1465
|
+
const texCoord = this.$inputs[`texcoord${that.clearcoatRoughnessMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1466
|
+
this.surfaceData.clearcoatFactor.y = pb.mul(this.surfaceData.clearcoatFactor.y, pb.textureSample(clearcoatRoughnessMap, texCoord).g);
|
|
1467
|
+
}
|
|
1468
|
+
this.surfaceData.clearcoatFactor.y = pb.clamp(this.surfaceData.clearcoatFactor.y, 0, 1);
|
|
1469
|
+
this.surfaceData.clearcoatContrib = pb.vec3(0);
|
|
1470
|
+
if (envLight) {
|
|
1471
|
+
this.surfaceData.clearcoatGGXLutSample = pb.clamp(pb.textureSample(this.ggxLut, pb.vec2(this.surfaceData.NdotV, this.surfaceData.clearcoatFactor.y)), pb.vec4(0), pb.vec4(1));
|
|
1472
|
+
}
|
|
1473
|
+
// clearcoatFresnel/radianceClearcoat will be set after f0 and f90 are set
|
|
1474
|
+
}
|
|
1475
|
+
if (that._sheen) {
|
|
1476
|
+
this.$l.sheenColor = this.$query(PBRLightModelBase.uniformSheenFactor).rgb;
|
|
1477
|
+
this.$l.sheenRoughness = this.$query(PBRLightModelBase.uniformSheenFactor).a;
|
|
1478
|
+
if (that.sheenColorMap) {
|
|
1479
|
+
const sheenColorMap = this[that.getTextureUniformName(TEX_NAME_SHEEN_COLOR)];
|
|
1480
|
+
const texCoord = this.$inputs[`texcoord${that.sheenColorMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1481
|
+
this.$l.sheenColor = pb.mul(this.$l.sheenColor, pb.textureSample(sheenColorMap, texCoord).rgb);
|
|
1482
|
+
}
|
|
1483
|
+
if (that.sheenRoughnessMap) {
|
|
1484
|
+
const sheenRoughnessMap = this[that.getTextureUniformName(TEX_NAME_SHEEN_ROUGHNESS)];
|
|
1485
|
+
const texCoord = this.$inputs[`texcoord${that.sheenRoughnessMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1486
|
+
this.$l.sheenRoughness = pb.mul(this.$l.sheenRoughness, pb.textureSample(sheenRoughnessMap, texCoord).a);
|
|
1487
|
+
}
|
|
1488
|
+
if (that.sheenLut) {
|
|
1489
|
+
const sheenLut = this[that.getTextureUniformName(TEX_NAME_SHEEN_LUT)];
|
|
1490
|
+
this.$l.sheenDFG = pb.textureSample(sheenLut, pb.vec2(this.surfaceData.NdotV, this.sheenRoughness)).b;
|
|
1491
|
+
} else {
|
|
1492
|
+
this.$l.sheenDFG = 0.157;
|
|
1493
|
+
}
|
|
1494
|
+
this.surfaceData.sheenAlbedoScaling = pb.sub(1, pb.mul(pb.max(pb.max(this.sheenColor.r, this.sheenColor.g), this.sheenColor.b), this.sheenDFG));
|
|
1495
|
+
this.surfaceData.sheenColor = this.sheenColor;
|
|
1496
|
+
this.surfaceData.sheenRoughness = this.sheenRoughness;
|
|
1497
|
+
this.surfaceData.sheenContrib = pb.vec3(0);
|
|
1498
|
+
/*
|
|
1499
|
+
this.$l.k = pb.clamp(pb.textureSample(this.ggxLut, pb.vec2(this.surfaceData.NdotV, this.surfaceData.sheenRoughness)), pb.vec4(0), pb.vec4(1)).b;
|
|
1500
|
+
this.surfaceData.sheenAlbedoScaling = pb.sub(1, pb.mul(this.k, pb.max(pb.max(this.surfaceData.sheenColor.r, this.surfaceData.sheenColor.g), this.surfaceData.sheenColor.b)));
|
|
1501
|
+
*/ }
|
|
1502
|
+
});
|
|
1503
|
+
pb.getGlobalScope()[funcNameFillSurfaceDataPBRCommon]();
|
|
1504
|
+
}
|
|
1505
|
+
iblSpecular(scope, brdf, f0, radiance, NdotV, roughness, specularWeight) {
|
|
1506
|
+
const pb = scope.$builder;
|
|
1507
|
+
const funcName = 'lib_PBRLM_iblspecular_pbr';
|
|
1508
|
+
pb.func(funcName, [
|
|
1509
|
+
pb.vec4('brdf'),
|
|
1510
|
+
pb.vec3('f0'),
|
|
1511
|
+
pb.vec3('radiance'),
|
|
1512
|
+
pb.float('NdotV'),
|
|
1513
|
+
pb.float('roughness'),
|
|
1514
|
+
pb.float('specularWeight')
|
|
1515
|
+
], function() {
|
|
1516
|
+
this.$l.f_ab = this.brdf.rg;
|
|
1517
|
+
this.$l.Fr = pb.sub(pb.max(pb.vec3(pb.sub(1, this.roughness)), this.f0), this.f0);
|
|
1518
|
+
this.$l.k_S = pb.add(this.f0, pb.mul(this.Fr, pb.pow(pb.sub(1, this.NdotV), 5)));
|
|
1519
|
+
this.$l.FssEss = pb.add(pb.mul(this.k_S, this.f_ab.x), pb.vec3(this.f_ab.y));
|
|
1520
|
+
this.$return(pb.mul(this.radiance, this.FssEss, this.specularWeight));
|
|
1521
|
+
});
|
|
1522
|
+
return pb.getGlobalScope()[funcName](brdf, f0, radiance, NdotV, roughness, specularWeight);
|
|
1523
|
+
}
|
|
1524
|
+
iblDiffuse(scope, brdf, f0, diffuse, irradiance, NdotV, roughness, specularWeight) {
|
|
1525
|
+
const pb = scope.$builder;
|
|
1526
|
+
const funcName = 'lib_PBRLM_ibldiffuse_pbr';
|
|
1527
|
+
pb.func(funcName, [
|
|
1528
|
+
pb.vec4('brdf'),
|
|
1529
|
+
pb.vec3('f0'),
|
|
1530
|
+
pb.vec3('diffuse'),
|
|
1531
|
+
pb.vec3('irradiance'),
|
|
1532
|
+
pb.float('NdotV'),
|
|
1533
|
+
pb.float('roughness'),
|
|
1534
|
+
pb.float('specularWeight')
|
|
1535
|
+
], function() {
|
|
1536
|
+
this.$l.f_ab = this.brdf.rg;
|
|
1537
|
+
this.$l.Fr = pb.sub(pb.max(pb.vec3(pb.sub(1, this.roughness)), this.f0), this.f0);
|
|
1538
|
+
this.$l.k_S = pb.add(this.f0, pb.mul(this.Fr, pb.pow(pb.sub(1, this.NdotV), 5)));
|
|
1539
|
+
this.$l.FssEss = pb.add(pb.mul(this.k_S, this.f_ab.x, this.specularWeight), pb.vec3(this.f_ab.y));
|
|
1540
|
+
this.$l.Ems = pb.sub(1, pb.add(this.f_ab.x, this.f_ab.y));
|
|
1541
|
+
this.$l.F_avg = pb.mul(pb.add(this.f0, pb.div(pb.sub(pb.vec3(1), this.f0), 21)), this.specularWeight);
|
|
1542
|
+
this.$l.FmsEms = pb.div(pb.mul(this.FssEss, this.F_avg, this.Ems), pb.sub(pb.vec3(1), pb.mul(this.F_avg, this.Ems)));
|
|
1543
|
+
this.$l.k_D = pb.mul(this.diffuse, pb.add(pb.sub(pb.vec3(1), this.FssEss), this.FmsEms));
|
|
1544
|
+
this.$return(pb.mul(pb.add(this.FmsEms, this.k_D), this.irradiance));
|
|
1545
|
+
});
|
|
1546
|
+
return pb.getGlobalScope()[funcName](brdf, f0, diffuse, irradiance, NdotV, roughness, specularWeight);
|
|
1547
|
+
}
|
|
1548
|
+
/** @internal */ illumEnvLight(scope, envLight) {
|
|
1549
|
+
const pb = scope.$builder;
|
|
1550
|
+
const that = this;
|
|
1551
|
+
pb.func(PBRLightModelBase.funcNameIllumEnvLight, [], function() {
|
|
1552
|
+
if (envLight.hasRadiance()) {
|
|
1553
|
+
this.$l.iblSpecular = that.iblSpecular(this, this.surfaceData.ggxLutSample, this.surfaceData.f0.rgb, this.surfaceData.radiance, this.surfaceData.NdotV, this.surfaceData.roughness, this.surfaceData.specularWeight);
|
|
1554
|
+
this.surfaceData.accumSpecular = pb.add(this.surfaceData.accumSpecular, pb.mul(this.iblSpecular, this.surfaceData.occlusion.r));
|
|
1555
|
+
}
|
|
1556
|
+
if (envLight.hasIrradiance()) {
|
|
1557
|
+
this.$l.iblDiffuse = that.iblDiffuse(this, this.surfaceData.ggxLutSample, this.surfaceData.f0.rgb, this.surfaceData.diffuse.rgb, this.surfaceData.irradiance, this.surfaceData.NdotV, this.surfaceData.roughness, this.surfaceData.specularWeight);
|
|
1558
|
+
this.surfaceData.accumDiffuse = pb.add(this.surfaceData.accumDiffuse, pb.mul(this.iblDiffuse, this.surfaceData.occlusion.r));
|
|
1559
|
+
}
|
|
1560
|
+
if (that._clearcoat) {
|
|
1561
|
+
this.$l.ccSpecular = that.iblSpecular(this, this.surfaceData.ggxLutSample, this.surfaceData.f0.rgb, this.surfaceData.radianceClearcoat, this.surfaceData.clearcoatNdotV, this.surfaceData.clearcoatFactor.y, 1);
|
|
1562
|
+
this.surfaceData.clearcoatContrib = pb.add(this.surfaceData.clearcoatContrib, pb.mul(this.ccSpecular, this.surfaceData.occlusion.r));
|
|
1563
|
+
}
|
|
1564
|
+
if (envLight.hasIrradiance() && that._sheen) {
|
|
1565
|
+
this.$l.refl = pb.reflect(pb.neg(this.surfaceData.viewVec), this.surfaceData.normal);
|
|
1566
|
+
this.$l.sheenEnvSample = envLight.getRadiance(this, this.refl, this.surfaceData.sheenRoughness);
|
|
1567
|
+
this.$l.sheenBRDF = pb.textureSample(this.ggxLut, pb.clamp(pb.vec2(this.surfaceData.NdotV, this.surfaceData.sheenRoughness), pb.vec2(0), pb.vec2(1))).b;
|
|
1568
|
+
//this.$l.sheenBRDF = iblSheenBRDF(this, this.surfaceData.sheenRoughness, this.surfaceData.NdotV);
|
|
1569
|
+
this.$l.sheenLighting = pb.mul(this.surfaceData.sheenColor.rgb, this.iblDiffuse, this.sheenBRDF);
|
|
1570
|
+
this.surfaceData.sheenContrib = pb.add(this.surfaceData.sheenContrib, pb.mul(this.sheenLighting, this.surfaceData.occlusion.r));
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
pb.getGlobalScope()[PBRLightModelBase.funcNameIllumEnvLight]();
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* {@inheritDoc LightModel.supportLighting}
|
|
1577
|
+
* @override
|
|
1578
|
+
*/ supportLighting() {
|
|
1579
|
+
return true;
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* {@inheritDoc LightModel.envBRDF}
|
|
1583
|
+
* @override
|
|
1584
|
+
*/ envBRDF(envLight, scope) {
|
|
1585
|
+
this.illumEnvLight(scope, envLight);
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* {@inheritDoc LightModel.directBRDF}
|
|
1589
|
+
* @override
|
|
1590
|
+
*/ directBRDF(scope, lightDir, attenuation) {
|
|
1591
|
+
const that = this;
|
|
1592
|
+
const pb = scope.$builder;
|
|
1593
|
+
pb.func(PBRLightModelBase.funcNameCalcPBRLight, [
|
|
1594
|
+
pb.vec3('lightDir'),
|
|
1595
|
+
pb.vec3('attenuation')
|
|
1596
|
+
], function() {
|
|
1597
|
+
this.$l.L = pb.neg(this.lightDir);
|
|
1598
|
+
this.$l.halfVec = pb.normalize(pb.sub(this.surfaceData.viewVec, this.lightDir));
|
|
1599
|
+
this.$l.NdotH = pb.clamp(pb.dot(this.surfaceData.normal, this.halfVec), 0, 1);
|
|
1600
|
+
this.$l.NdotL = pb.clamp(pb.dot(this.surfaceData.normal, this.L), 0, 1);
|
|
1601
|
+
this.$l.VdotH = pb.clamp(pb.dot(this.surfaceData.viewVec, this.halfVec), 0, 1);
|
|
1602
|
+
this.$l.outSpecular = pb.vec3();
|
|
1603
|
+
this.$l.outDiffuse = pb.vec3();
|
|
1604
|
+
this.$l.F = fresnelSchlick(this, this.VdotH, this.surfaceData.f0.rgb, this.surfaceData.f90);
|
|
1605
|
+
directLighting(this, this.surfaceData.diffuse.rgb, this.surfaceData.NdotV, this.NdotH, this.NdotL, this.F, this.surfaceData.roughness, this.surfaceData.specularWeight, this.outSpecular, this.outDiffuse);
|
|
1606
|
+
this.surfaceData.accumSpecular = pb.add(this.surfaceData.accumSpecular, pb.mul(this.outSpecular, this.attenuation));
|
|
1607
|
+
this.surfaceData.accumDiffuse = pb.add(this.surfaceData.accumDiffuse, pb.mul(this.outDiffuse, this.attenuation));
|
|
1608
|
+
if (that._sheen) {
|
|
1609
|
+
this.$l.sheenLighting = directSheenLighting(this, this.surfaceData.NdotV, this.NdotL, this.NdotH, this.surfaceData.sheenColor, this.surfaceData.sheenRoughness);
|
|
1610
|
+
this.surfaceData.sheenContrib = pb.add(this.surfaceData.sheenContrib, pb.mul(this.sheenLighting, this.attenuation));
|
|
1611
|
+
}
|
|
1612
|
+
if (that._clearcoat) {
|
|
1613
|
+
this.$l.ccNdotH = pb.clamp(pb.dot(this.surfaceData.clearcoatNormal, this.halfVec), 0, 1);
|
|
1614
|
+
this.$l.ccNdotL = pb.clamp(pb.dot(this.surfaceData.clearcoatNormal, this.L), 0, 1);
|
|
1615
|
+
this.$l.ccLighting = directClearcoatLighting(this, this.surfaceData.clearcoatNdotV, this.ccNdotH, this.ccNdotL, this.F, this.surfaceData.clearcoatFactor.y);
|
|
1616
|
+
this.surfaceData.clearcoatContrib = pb.add(this.surfaceData.clearcoatContrib, pb.mul(this.ccLighting, this.attenuation));
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
pb.getGlobalScope()[PBRLightModelBase.funcNameCalcPBRLight](lightDir, attenuation);
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* {@inheritDoc LightModel.compositeSurfaceData}
|
|
1623
|
+
* @override
|
|
1624
|
+
*/ compositeSurfaceData(scope) {
|
|
1625
|
+
// to be overriden
|
|
1626
|
+
const pb = scope.$builder;
|
|
1627
|
+
switch(Material.debugChannel){
|
|
1628
|
+
case 'pbrBase':
|
|
1629
|
+
{
|
|
1630
|
+
break;
|
|
1631
|
+
}
|
|
1632
|
+
case 'pbrMetallic':
|
|
1633
|
+
{
|
|
1634
|
+
scope.surfaceData.debugColor = pb.vec4(scope.surfaceData.metallic, scope.surfaceData.metallic, scope.surfaceData.metallic, 1);
|
|
1635
|
+
break;
|
|
1636
|
+
}
|
|
1637
|
+
case 'pbrRoughness':
|
|
1638
|
+
{
|
|
1639
|
+
scope.surfaceData.debugColor = pb.vec4(scope.surfaceData.roughness, scope.surfaceData.roughness, scope.surfaceData.roughness, 1);
|
|
1640
|
+
break;
|
|
1641
|
+
}
|
|
1642
|
+
case 'pbrMetallicRoughness':
|
|
1643
|
+
{
|
|
1644
|
+
scope.surfaceData.debugColor = pb.vec4(pb.add(scope.surfaceData.accumDiffuse, scope.surfaceData.accumSpecular), 1);
|
|
1645
|
+
break;
|
|
1646
|
+
}
|
|
1647
|
+
case 'pbrSheen':
|
|
1648
|
+
{
|
|
1649
|
+
if (this._sheen) {
|
|
1650
|
+
scope.surfaceData.debugColor = pb.vec4(scope.surfaceData.sheenContrib, 1);
|
|
1651
|
+
} else {
|
|
1652
|
+
scope.surfaceData.debugColor = pb.vec4(0, 0, 0, 1);
|
|
1653
|
+
}
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
case 'pbrSheenColor':
|
|
1657
|
+
{
|
|
1658
|
+
if (this._sheen) {
|
|
1659
|
+
scope.surfaceData.debugColor = pb.vec4(scope.surfaceData.sheenColor, 1);
|
|
1660
|
+
} else {
|
|
1661
|
+
scope.surfaceData.debugColor = pb.vec4(0, 0, 0, 1);
|
|
1662
|
+
}
|
|
1663
|
+
break;
|
|
1664
|
+
}
|
|
1665
|
+
case 'pbrSheenRoughness':
|
|
1666
|
+
{
|
|
1667
|
+
if (this._sheen) {
|
|
1668
|
+
scope.surfaceData.debugColor = pb.vec4(scope.surfaceData.sheenRoughness, scope.surfaceData.sheenRoughness, scope.surfaceData.sheenRoughness, 1);
|
|
1669
|
+
} else {
|
|
1670
|
+
scope.surfaceData.debugColor = pb.vec4(0, 0, 0, 1);
|
|
1671
|
+
}
|
|
1672
|
+
break;
|
|
1673
|
+
}
|
|
1674
|
+
case 'pbrSheenAlbedoScaling':
|
|
1675
|
+
{
|
|
1676
|
+
if (this._sheen) {
|
|
1677
|
+
scope.surfaceData.debugColor = pb.vec4(scope.surfaceData.sheenAlbedoScaling, scope.surfaceData.sheenAlbedoScaling, scope.surfaceData.sheenAlbedoScaling, 1);
|
|
1678
|
+
} else {
|
|
1679
|
+
scope.surfaceData.debugColor = pb.vec4(0, 0, 0, 1);
|
|
1680
|
+
}
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
default:
|
|
1684
|
+
{
|
|
1685
|
+
if (this._sheen) {
|
|
1686
|
+
scope.surfaceData.accumColor = pb.add(pb.mul(scope.surfaceData.accumColor, scope.surfaceData.sheenAlbedoScaling), scope.surfaceData.sheenContrib);
|
|
1687
|
+
}
|
|
1688
|
+
if (this._clearcoat) {
|
|
1689
|
+
scope.surfaceData.accumColor = pb.add(pb.mul(scope.surfaceData.accumColor, pb.sub(pb.vec3(1), pb.mul(scope.surfaceData.clearcoatFresnel, scope.surfaceData.clearcoatFactor.x))), pb.mul(scope.surfaceData.clearcoatContrib, scope.surfaceData.clearcoatFactor.x));
|
|
1690
|
+
// surfaceData.accumColor = pb.add(pb.mul(surfaceData.clearcoatNormal, 0.5), pb.vec3(0.5));
|
|
1691
|
+
// surfaceData.accumColor = pb.vec3(surfaceData.clearcoatFresnel);
|
|
1692
|
+
}
|
|
1693
|
+
break;
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
super.compositeSurfaceData(scope);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* specular-glossness PBR light model
|
|
1701
|
+
* @public
|
|
1702
|
+
*/ class PBRLightModelSG extends PBRLightModelBase {
|
|
1703
|
+
/** @internal */ static uniformSpecularFactor = 'lib_PBRSG_specularFactor';
|
|
1704
|
+
/** @internal */ static uniformGlossinessFactor = 'lib_PBRSG_glossinessFactor';
|
|
1705
|
+
/** @internal */ _specularFactor;
|
|
1706
|
+
/** @internal */ _glossinessFactor;
|
|
1707
|
+
/**
|
|
1708
|
+
* Creates an instance of PBRLightModelSG
|
|
1709
|
+
*/ constructor(){
|
|
1710
|
+
super();
|
|
1711
|
+
this._specularFactor = Vector4.one();
|
|
1712
|
+
this._glossinessFactor = 1;
|
|
1713
|
+
}
|
|
1714
|
+
/** The specular factor */ get specularFactor() {
|
|
1715
|
+
return this._specularFactor;
|
|
1716
|
+
}
|
|
1717
|
+
set specularFactor(val) {
|
|
1718
|
+
if (val && !this._specularFactor.equalsTo(val)) {
|
|
1719
|
+
this._specularFactor.set(val);
|
|
1720
|
+
this.optionChanged(false);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
/** The glossness factor */ get glossinessFactor() {
|
|
1724
|
+
return this._glossinessFactor;
|
|
1725
|
+
}
|
|
1726
|
+
set glossinessFactor(val) {
|
|
1727
|
+
if (val !== this._glossinessFactor) {
|
|
1728
|
+
this._glossinessFactor = val;
|
|
1729
|
+
this.optionChanged(false);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
/** The specular texture */ get specularMap() {
|
|
1733
|
+
return (this._textureOptions[TEX_NAME_SPECULAR]?.texture) ?? null;
|
|
1734
|
+
}
|
|
1735
|
+
/** Texture coordinate index of the specular texture */ get specularMapTexCoord() {
|
|
1736
|
+
return this._textureOptions[TEX_NAME_SPECULAR]?.texCoordIndex ?? null;
|
|
1737
|
+
}
|
|
1738
|
+
/** Sampler of the specular texture */ get specularSampler() {
|
|
1739
|
+
return this._textureOptions[TEX_NAME_SPECULAR]?.sampler ?? null;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Sets the specular texture
|
|
1743
|
+
* @param tex - The texture to set
|
|
1744
|
+
* @param sampler - Sampler of the texture
|
|
1745
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1746
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1747
|
+
*/ setSpecularMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1748
|
+
this.setTextureOptions(TEX_NAME_SPECULAR, tex, sampler, texCoordIndex, texTransform);
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* {@inheritDoc LightModel.applyUniforms}
|
|
1752
|
+
* @override
|
|
1753
|
+
*/ applyUniforms(bindGroup, ctx) {
|
|
1754
|
+
super.applyUniforms(bindGroup, ctx);
|
|
1755
|
+
bindGroup.setValue('lm_specularFactor', this._specularFactor);
|
|
1756
|
+
bindGroup.setValue('lm_glossinessFactor', this._glossinessFactor);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* {@inheritDoc LightModel.calculateHash}
|
|
1760
|
+
* @override
|
|
1761
|
+
*/ calculateHash() {
|
|
1762
|
+
return `${super.calculateHash()}_${this.specularMap ? `${this.specularMapTexCoord + 1}` : 0}`;
|
|
1763
|
+
}
|
|
1764
|
+
/**
|
|
1765
|
+
* {@inheritDoc LightModel.setupUniforms}
|
|
1766
|
+
* @override
|
|
1767
|
+
*/ setupUniforms(scope, ctx) {
|
|
1768
|
+
super.setupUniforms(scope, ctx);
|
|
1769
|
+
if (scope.$builder.shaderKind === 'fragment') {
|
|
1770
|
+
scope.lm_specularFactor = scope.$builder.vec4().uniform(2).tag(PBRLightModelSG.uniformSpecularFactor);
|
|
1771
|
+
scope.lm_glossinessFactor = scope.$builder.float().uniform(2).tag(PBRLightModelSG.uniformGlossinessFactor);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* {@inheritDoc LightModel.fillSurfaceData}
|
|
1776
|
+
* @override
|
|
1777
|
+
*/ fillSurfaceData(scope, envLight) {
|
|
1778
|
+
const funcNameFillSurfaceDataSG = 'lib_fillSurfaceDataSG';
|
|
1779
|
+
const that = this;
|
|
1780
|
+
const pb = scope.$builder;
|
|
1781
|
+
super.fillSurfaceData(scope, envLight);
|
|
1782
|
+
// surface data contains F0, metallic, roughness
|
|
1783
|
+
pb.func(funcNameFillSurfaceDataSG, [], function() {
|
|
1784
|
+
this.surfaceData.f0 = pb.vec4(this.$query(PBRLightModelSG.uniformSpecularFactor).rgb, this.surfaceData.f0.a);
|
|
1785
|
+
this.surfaceData.roughness = this.$query(PBRLightModelSG.uniformGlossinessFactor);
|
|
1786
|
+
if (that.specularMap) {
|
|
1787
|
+
const texCoord = this.$inputs[`texcoord${that.specularMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
1788
|
+
this.$l.t = pb.textureSample(this[that.getTextureUniformName(TEX_NAME_SPECULAR)], texCoord);
|
|
1789
|
+
this.surfaceData.roughness = pb.mul(this.surfaceData.roughness, this.t.a);
|
|
1790
|
+
this.surfaceData.f0 = pb.mul(this.surfaceData.f0, pb.vec4(this.t.rgb, 1));
|
|
1791
|
+
}
|
|
1792
|
+
this.surfaceData.roughness = pb.sub(1, this.surfaceData.roughness);
|
|
1793
|
+
this.surfaceData.metallic = pb.max(pb.max(this.surfaceData.f0.r, this.surfaceData.f0.g), this.surfaceData.f0.b);
|
|
1794
|
+
if (envLight) {
|
|
1795
|
+
this.surfaceData.ggxLutSample = pb.clamp(pb.textureSample(this.ggxLut, pb.vec2(this.surfaceData.NdotV, this.surfaceData.roughness)), pb.vec4(0), pb.vec4(1));
|
|
1796
|
+
}
|
|
1797
|
+
this.surfaceData.diffuse = pb.vec4(pb.mul(this.surfaceData.diffuse.rgb, pb.sub(1, this.surfaceData.metallic)), this.surfaceData.diffuse.a);
|
|
1798
|
+
this.surfaceData.specularWeight = pb.float(1);
|
|
1799
|
+
if (that._clearcoat) {
|
|
1800
|
+
this.surfaceData.clearcoatFresnel = fresnelSchlick(this, this.surfaceData.clearcoatNdotV, this.surfaceData.f0.rgb, this.surfaceData.f90);
|
|
1801
|
+
}
|
|
1802
|
+
if (envLight?.hasIrradiance()) {
|
|
1803
|
+
this.surfaceData.irradiance = envLight.getIrradiance(this, this.surfaceData.normal);
|
|
1804
|
+
} else {
|
|
1805
|
+
this.surfaceData.irradiance = pb.vec3(0);
|
|
1806
|
+
}
|
|
1807
|
+
if (envLight?.hasRadiance()) {
|
|
1808
|
+
this.$l.refl = pb.reflect(pb.neg(this.surfaceData.viewVec), this.surfaceData.normal);
|
|
1809
|
+
this.surfaceData.radiance = envLight.getRadiance(this, this.refl, this.surfaceData.roughness);
|
|
1810
|
+
if (that.useClearcoat) {
|
|
1811
|
+
this.$l.ccRefl = pb.reflect(pb.neg(this.surfaceData.viewVec), this.surfaceData.clearcoatNormal);
|
|
1812
|
+
this.surfaceData.radianceClearcoat = envLight.getRadiance(this, this.ccRefl, this.surfaceData.clearcoatFactor.y);
|
|
1813
|
+
}
|
|
1814
|
+
} else {
|
|
1815
|
+
this.surfaceData.radiance = pb.vec3(0);
|
|
1816
|
+
if (that.useClearcoat) {
|
|
1817
|
+
this.surfaceData.radianceClearcoat = pb.vec3(0);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
pb.getGlobalScope()[funcNameFillSurfaceDataSG]();
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* {@inheritDoc LightModel.createSurfaceDataType}
|
|
1825
|
+
* @override
|
|
1826
|
+
*/ createSurfaceDataType(env) {
|
|
1827
|
+
return super.createSurfaceDataType(env).extends('', [
|
|
1828
|
+
{
|
|
1829
|
+
name: 'specularWeight',
|
|
1830
|
+
type: typeF32
|
|
1831
|
+
}
|
|
1832
|
+
]);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Metallic-Roughness PBR light model
|
|
1837
|
+
* @public
|
|
1838
|
+
*/ class PBRLightModelMR extends PBRLightModelBase {
|
|
1839
|
+
/** @internal */ static uniformMetallic = 'lib_PBRLM_metallic';
|
|
1840
|
+
/** @internal */ static uniformRoughness = 'lib_PBRLM_roughness';
|
|
1841
|
+
/** @internal */ static uniformSpecularFactor = 'lib_PBRLM_specularFactor';
|
|
1842
|
+
/** @internal */ _metallic;
|
|
1843
|
+
/** @internal */ _roughness;
|
|
1844
|
+
/** @internal */ _metallicIndex;
|
|
1845
|
+
/** @internal */ _roughnessIndex;
|
|
1846
|
+
/** @internal */ _specularFactor;
|
|
1847
|
+
/**
|
|
1848
|
+
* Creates an instance of PBRLightModelMR
|
|
1849
|
+
*/ constructor(){
|
|
1850
|
+
super();
|
|
1851
|
+
this._metallic = 1;
|
|
1852
|
+
this._roughness = 1;
|
|
1853
|
+
this._metallicIndex = 2;
|
|
1854
|
+
this._roughnessIndex = 1;
|
|
1855
|
+
this._specularFactor = Vector4.one();
|
|
1856
|
+
}
|
|
1857
|
+
/** The metallic factor */ get metallic() {
|
|
1858
|
+
return this._metallic;
|
|
1859
|
+
}
|
|
1860
|
+
set metallic(val) {
|
|
1861
|
+
if (val !== this._metallic) {
|
|
1862
|
+
this._metallic = val;
|
|
1863
|
+
this.optionChanged(false);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
/** The roughness factor */ get roughness() {
|
|
1867
|
+
return this._roughness;
|
|
1868
|
+
}
|
|
1869
|
+
set roughness(val) {
|
|
1870
|
+
if (val !== this._roughness) {
|
|
1871
|
+
this._roughness = val;
|
|
1872
|
+
this.optionChanged(false);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
/** index of the metallic channel in the metallic-roughness texture */ get metallicIndex() {
|
|
1876
|
+
return this._metallicIndex;
|
|
1877
|
+
}
|
|
1878
|
+
set metallicIndex(val) {
|
|
1879
|
+
if (this._metallicIndex !== val) {
|
|
1880
|
+
this._metallicIndex = val;
|
|
1881
|
+
this.optionChanged(true);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
/** index of the roughness channel in the metallic-roughness texture */ get roughnessIndex() {
|
|
1885
|
+
return this._roughnessIndex;
|
|
1886
|
+
}
|
|
1887
|
+
set roughnessIndex(val) {
|
|
1888
|
+
if (this._roughnessIndex !== val) {
|
|
1889
|
+
this._roughnessIndex = val;
|
|
1890
|
+
this.optionChanged(true);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
/** The metallic-roughness texture */ get metallicMap() {
|
|
1894
|
+
return (this._textureOptions[TEX_NAME_METALLIC]?.texture) ?? null;
|
|
1895
|
+
}
|
|
1896
|
+
/** Sampler of the metallic-roughness texture */ get metallicSampler() {
|
|
1897
|
+
return this._textureOptions[TEX_NAME_METALLIC]?.sampler ?? null;
|
|
1898
|
+
}
|
|
1899
|
+
/** Texture coordinate index of the metallic-roughness texture */ get metallicMapTexCoord() {
|
|
1900
|
+
return this._textureOptions[TEX_NAME_METALLIC]?.texCoordIndex ?? null;
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Sets the metallic-roughness texture
|
|
1904
|
+
* @param tex - The texture to set
|
|
1905
|
+
* @param sampler - Sampler of the texture
|
|
1906
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1907
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1908
|
+
*/ setMetallicMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1909
|
+
this.setTextureOptions(TEX_NAME_METALLIC, tex, sampler, texCoordIndex, texTransform);
|
|
1910
|
+
}
|
|
1911
|
+
/** The specular factor */ get specularFactor() {
|
|
1912
|
+
return this._specularFactor;
|
|
1913
|
+
}
|
|
1914
|
+
set specularFactor(val) {
|
|
1915
|
+
if (!val.equalsTo(this._specularFactor)) {
|
|
1916
|
+
this._specularFactor.set(val);
|
|
1917
|
+
this.optionChanged(true);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
/** The specular texture */ get specularMap() {
|
|
1921
|
+
return (this._textureOptions[TEX_NAME_SPECULAR]?.texture) ?? null;
|
|
1922
|
+
}
|
|
1923
|
+
/** Sampler of the specular texture */ get specularSampler() {
|
|
1924
|
+
return this._textureOptions[TEX_NAME_SPECULAR]?.sampler ?? null;
|
|
1925
|
+
}
|
|
1926
|
+
/** Texture coordinate index of the specular texture */ get specularMapTexCoord() {
|
|
1927
|
+
return this._textureOptions[TEX_NAME_SPECULAR]?.texCoordIndex ?? null;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Sets the specular texture
|
|
1931
|
+
* @param tex - The texture to set
|
|
1932
|
+
* @param sampler - Sampler of the texture
|
|
1933
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1934
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1935
|
+
*/ setSpecularMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1936
|
+
this.setTextureOptions(TEX_NAME_SPECULAR, tex, sampler, texCoordIndex, texTransform);
|
|
1937
|
+
}
|
|
1938
|
+
/** The specular color texture */ get specularColorMap() {
|
|
1939
|
+
return (this._textureOptions[TEX_NAME_SPECULAR_COLOR]?.texture) ?? null;
|
|
1940
|
+
}
|
|
1941
|
+
/** Sampler of the specular color texture */ get specularColorSampler() {
|
|
1942
|
+
return this._textureOptions[TEX_NAME_SPECULAR_COLOR]?.sampler ?? null;
|
|
1943
|
+
}
|
|
1944
|
+
/** Texture coordinate index of the specular color texture */ get specularColorMapTexCoord() {
|
|
1945
|
+
return this._textureOptions[TEX_NAME_SPECULAR_COLOR]?.texCoordIndex ?? null;
|
|
1946
|
+
}
|
|
1947
|
+
/**
|
|
1948
|
+
* Sets the specular color texture
|
|
1949
|
+
* @param tex - The texture to set
|
|
1950
|
+
* @param sampler - Sampler of the texture
|
|
1951
|
+
* @param texCoordIndex - Texture coordinate index of the texture
|
|
1952
|
+
* @param texTransform - Transformation matrix for texture coordinates of the texture
|
|
1953
|
+
*/ setSpecularColorMap(tex, sampler, texCoordIndex, texTransform) {
|
|
1954
|
+
this.setTextureOptions(TEX_NAME_SPECULAR_COLOR, tex, sampler, texCoordIndex, texTransform);
|
|
1955
|
+
}
|
|
1956
|
+
/**
|
|
1957
|
+
* {@inheritDoc LightModel.applyUniforms}
|
|
1958
|
+
* @override
|
|
1959
|
+
*/ applyUniforms(bindGroup, ctx) {
|
|
1960
|
+
super.applyUniforms(bindGroup, ctx);
|
|
1961
|
+
bindGroup.setValue('lm_pbrMetallic', this._metallic);
|
|
1962
|
+
bindGroup.setValue('lm_pbrRoughness', this._roughness);
|
|
1963
|
+
bindGroup.setValue('lm_pbrSpecularFactor', this._specularFactor);
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* {@inheritDoc LightModel.calculateHash}
|
|
1967
|
+
* @override
|
|
1968
|
+
*/ calculateHash() {
|
|
1969
|
+
const metallicMapHash = this.metallicMap ? `${this.metallicMapTexCoord + 1}_${this._metallicIndex}_${this._roughnessIndex}` : '0';
|
|
1970
|
+
const specularMapHash = this.specularMap ? `${this.specularMapTexCoord + 1}` : '0';
|
|
1971
|
+
const specularColorMapHash = this.specularColorMap ? `${this.specularColorMapTexCoord + 1}` : '0';
|
|
1972
|
+
return `${super.calculateHash()}_${metallicMapHash}_${specularMapHash}_${specularColorMapHash}`;
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* {@inheritDoc LightModel.setupUniforms}
|
|
1976
|
+
* @override
|
|
1977
|
+
*/ setupUniforms(scope, ctx) {
|
|
1978
|
+
super.setupUniforms(scope, ctx);
|
|
1979
|
+
if (scope.$builder.shaderKind === 'fragment') {
|
|
1980
|
+
scope.lm_pbrMetallic = scope.$builder.float().uniform(2).tag(PBRLightModelMR.uniformMetallic);
|
|
1981
|
+
scope.lm_pbrRoughness = scope.$builder.float().uniform(2).tag(PBRLightModelMR.uniformRoughness);
|
|
1982
|
+
scope.lm_pbrSpecularFactor = scope.$builder.vec4().uniform(2).tag(PBRLightModelMR.uniformSpecularFactor);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
/**
|
|
1986
|
+
* {@inheritDoc LightModel.fillSurfaceData}
|
|
1987
|
+
* @override
|
|
1988
|
+
*/ fillSurfaceData(scope, envLight) {
|
|
1989
|
+
const funcNameFillSurfaceDataMR = 'lib_fillSurfaceDataMR';
|
|
1990
|
+
const that = this;
|
|
1991
|
+
const pb = scope.$builder;
|
|
1992
|
+
super.fillSurfaceData(scope, envLight);
|
|
1993
|
+
// surface data contains F0, metallic, roughness
|
|
1994
|
+
pb.func(funcNameFillSurfaceDataMR, [], function() {
|
|
1995
|
+
const metallicMap = that.metallicMap ? this[that.getTextureUniformName(TEX_NAME_METALLIC)] : null;
|
|
1996
|
+
const specularMap = that.specularMap ? this[that.getTextureUniformName(TEX_NAME_SPECULAR)] : null;
|
|
1997
|
+
const specularColorMap = that.specularColorMap ? this[that.getTextureUniformName(TEX_NAME_SPECULAR_COLOR)] : null;
|
|
1998
|
+
const metallicFactor = this.$query(PBRLightModelMR.uniformMetallic);
|
|
1999
|
+
const roughnessFactor = this.$query(PBRLightModelMR.uniformRoughness);
|
|
2000
|
+
if (metallicMap) {
|
|
2001
|
+
const texCoord = this.$inputs[`texcoord${that.metallicMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
2002
|
+
this.$l.t = pb.textureSample(metallicMap, texCoord);
|
|
2003
|
+
const metallic = this.t['xyzw'[that._metallicIndex] || 'z'];
|
|
2004
|
+
const roughness = this.t['xyzw'[that._roughnessIndex] || 'y'];
|
|
2005
|
+
this.surfaceData.metallic = metallicFactor ? pb.mul(metallic, metallicFactor) : metallic;
|
|
2006
|
+
this.surfaceData.roughness = roughnessFactor ? pb.mul(roughness, roughnessFactor) : roughness;
|
|
2007
|
+
} else {
|
|
2008
|
+
this.surfaceData.metallic = metallicFactor;
|
|
2009
|
+
this.surfaceData.roughness = roughnessFactor;
|
|
2010
|
+
}
|
|
2011
|
+
if (envLight) {
|
|
2012
|
+
this.surfaceData.ggxLutSample = pb.textureSample(this.ggxLut, pb.vec2(this.surfaceData.NdotV, this.surfaceData.roughness));
|
|
2013
|
+
}
|
|
2014
|
+
const specularFactor = this.$query(PBRLightModelMR.uniformSpecularFactor);
|
|
2015
|
+
this.$l.specularColorFactor = specularFactor.rgb;
|
|
2016
|
+
this.surfaceData.specularWeight = specularFactor.a;
|
|
2017
|
+
if (specularColorMap) {
|
|
2018
|
+
const texCoord = this.$inputs[`texcoord${that.specularColorMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
2019
|
+
this.specularColorFactor = pb.mul(this.specularColorFactor, pb.textureSample(specularColorMap, texCoord).rgb);
|
|
2020
|
+
}
|
|
2021
|
+
if (specularMap) {
|
|
2022
|
+
const texCoord = this.$inputs[`texcoord${that.specularMapTexCoord ?? that.albedoMapTexCoord}`];
|
|
2023
|
+
this.surfaceData.specularWeight = pb.mul(this.surfaceData.specularWeight, pb.textureSample(specularMap, texCoord).a);
|
|
2024
|
+
}
|
|
2025
|
+
this.surfaceData.f0 = pb.vec4(pb.mix(pb.min(pb.mul(this.surfaceData.f0.rgb, this.specularColorFactor), pb.vec3(1)), this.surfaceData.diffuse.rgb, this.surfaceData.metallic), this.surfaceData.f0.a);
|
|
2026
|
+
this.surfaceData.diffuse = pb.vec4(pb.mix(this.surfaceData.diffuse.rgb, pb.vec3(0), this.surfaceData.metallic), this.surfaceData.diffuse.a);
|
|
2027
|
+
if (that._clearcoat) {
|
|
2028
|
+
this.surfaceData.clearcoatFresnel = fresnelSchlick(this, this.surfaceData.clearcoatNdotV, this.surfaceData.f0.rgb, this.surfaceData.f90);
|
|
2029
|
+
}
|
|
2030
|
+
if (envLight?.hasIrradiance()) {
|
|
2031
|
+
this.surfaceData.irradiance = envLight.getIrradiance(this, this.surfaceData.normal);
|
|
2032
|
+
} else {
|
|
2033
|
+
this.surfaceData.irradiance = pb.vec3(0);
|
|
2034
|
+
}
|
|
2035
|
+
if (envLight?.hasRadiance()) {
|
|
2036
|
+
this.$l.refl = pb.reflect(pb.neg(this.surfaceData.viewVec), this.surfaceData.normal);
|
|
2037
|
+
this.surfaceData.radiance = envLight.getRadiance(this, this.refl, this.surfaceData.roughness);
|
|
2038
|
+
if (that.useClearcoat) {
|
|
2039
|
+
this.$l.ccRefl = pb.reflect(pb.neg(this.surfaceData.viewVec), this.surfaceData.clearcoatNormal);
|
|
2040
|
+
this.surfaceData.radianceClearcoat = envLight.getRadiance(this, this.ccRefl, this.surfaceData.clearcoatFactor.y);
|
|
2041
|
+
}
|
|
2042
|
+
} else {
|
|
2043
|
+
this.surfaceData.radiance = pb.vec3(0);
|
|
2044
|
+
if (that.useClearcoat) {
|
|
2045
|
+
this.surfaceData.radianceClearcoat = pb.vec3(0);
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
});
|
|
2049
|
+
pb.getGlobalScope()[funcNameFillSurfaceDataMR]();
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* {@inheritDoc LightModel.createSurfaceDataType}
|
|
2053
|
+
* @override
|
|
2054
|
+
*/ createSurfaceDataType(env) {
|
|
2055
|
+
return super.createSurfaceDataType(env).extends('', [
|
|
2056
|
+
{
|
|
2057
|
+
name: 'specularWeight',
|
|
2058
|
+
type: typeF32
|
|
2059
|
+
}
|
|
2060
|
+
]);
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* {@inheritDoc LightModel.isTextureUsed}
|
|
2064
|
+
* @override
|
|
2065
|
+
*/ isTextureUsed(name) {
|
|
2066
|
+
if (!this._sheen && (name === TEX_NAME_SHEEN_COLOR || name === TEX_NAME_SHEEN_ROUGHNESS)) {
|
|
2067
|
+
return false;
|
|
2068
|
+
}
|
|
2069
|
+
return super.isTextureUsed(name);
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
export { BlinnLightModel, LambertLightModel, LightModel, PBRLightModelBase, PBRLightModelMR, PBRLightModelSG, UnlitLightModel };
|
|
2074
|
+
//# sourceMappingURL=lightmodel.js.map
|