@meimu/mutracer 0.1.4 → 0.1.5
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/assets/bvh.worker.js +1 -1
- package/dist/mutracer.umd.js +1425 -1421
- package/docs/api.md +2 -1
- package/docs/materials.md +17 -26
- package/docs/threejs.md +5 -5
- package/docs/viewer.md +36 -3
- package/lib/oidn.d.ts +1 -1
- package/lib/oidnBundledWeights.cdn.d.ts +2 -2
- package/lib/renderer/WGPUFullQuadPass.js +3 -3
- package/lib/renderer/WGPUJNLMDenoiser.js +35 -35
- package/lib/renderer/WGPURayTraceOutput.js +4 -4
- package/lib/renderer/WGPURayTracePass.js +5 -3
- package/lib/renderer/WGPURayTracePass.js.map +1 -1
- package/lib/renderer/WGPURenderingPipeline.js +7 -7
- package/lib/renderer/WebGLJNLMDenoiser.js +36 -36
- package/lib/renderer/WebGLRayTracePass.js +1 -0
- package/lib/renderer/WebGLRayTracePass.js.map +1 -1
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +8 -8
- package/lib/renderer/glsl/chunks/envMap.glsl.js +26 -26
- package/lib/renderer/glsl/chunks/intersect.glsl.js +141 -139
- package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +56 -55
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +144 -144
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/random.glsl.js +1 -1
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +14 -14
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js +19 -19
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +46 -46
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +6 -6
- package/lib/renderer/glsl/chunks/sampling.glsl.js +33 -33
- package/lib/renderer/glsl/chunks/sobol.glsl.js +7 -7
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js +1 -1
- package/lib/renderer/glsl/depthQuery.frag.js +2 -2
- package/lib/renderer/glsl/rayTrace.frag.js +67 -67
- package/lib/renderer/glsl/shadowCatcher.frag.js +3 -3
- package/lib/renderer/glsl/webglPipeline.frag.js +26 -26
- package/lib/renderer/scratchSampling.js +16 -16
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js +14 -14
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +178 -178
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +24 -23
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +160 -160
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +12 -12
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +5 -5
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +44 -44
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +69 -69
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js +33 -33
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js +7 -7
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +1 -1
- package/lib/renderer/wgsl/compose.frag.wgsl.js +54 -54
- package/lib/renderer/wgsl/customDenoise.wgsl.js +6 -6
- package/lib/renderer/wgsl/depthQuery.wgsl.js +2 -2
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +5 -5
- package/lib/renderer/wgsl/rayTrace.compute.js +103 -103
- package/lib/scene/OpenPBRMaterial.d.ts +1 -1
- package/lib/scene/OpenPBRMaterial.js +1 -1
- package/lib/scene/OpenPBRMaterial.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral
|
|
3
3
|
import { glsl } from '../../shader.js';
|
|
4
4
|
export default glsl `
|
|
5
|
-
vec3
|
|
6
|
-
float
|
|
7
|
-
vec3 ln = vec3(
|
|
5
|
+
vec3 mT(ad si, J mat, ag prepared, inout Path aa, vec3 ffnormal, bool gF) {
|
|
6
|
+
float mC = 1.0;
|
|
7
|
+
vec3 ln = vec3(fp(cw(LIGHT_POSITION)), dz(cw(LIGHT_SELECT)));
|
|
8
8
|
|
|
9
9
|
LightSampleRec lightSample;
|
|
10
10
|
sampleLight(si.position, ln, lightSample, false);
|
|
11
11
|
lightSample.emission = ai(lightSample.emission, bf);
|
|
12
12
|
|
|
13
13
|
vec3 lightDir = lightSample.direction;
|
|
14
|
-
vec3
|
|
14
|
+
vec3 oS = -aa.ray.d;
|
|
15
15
|
float fg = lightSample.pdf;
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
float cosThetaL = dot(ffnormal, lightDir);
|
|
21
|
-
#ifdef
|
|
22
|
-
if (
|
|
21
|
+
#ifdef USE_COAT_NORMAL_FRAMES
|
|
22
|
+
if (gF && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }
|
|
23
23
|
#endif
|
|
24
24
|
|
|
25
25
|
if (fg <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {
|
|
@@ -28,7 +28,7 @@ return vec3(0.0);
|
|
|
28
28
|
|
|
29
29
|
float scatteringPdf = 0.0;
|
|
30
30
|
vec3 f = vec3(0.0);
|
|
31
|
-
if (
|
|
31
|
+
if (gF) {
|
|
32
32
|
if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {
|
|
33
33
|
return vec3(0.0);
|
|
34
34
|
}
|
|
@@ -36,7 +36,7 @@ f = bI(prepared, lightDir, scatteringPdf);
|
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
38
38
|
scatteringPdf = bD(
|
|
39
|
-
dot(
|
|
39
|
+
dot(oS, lightDir),
|
|
40
40
|
si.mediumAnisotropy
|
|
41
41
|
);
|
|
42
42
|
f = vec3(scatteringPdf);
|
|
@@ -46,36 +46,36 @@ if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {
|
|
|
46
46
|
return vec3(0.0);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
Ray
|
|
49
|
+
Ray mz;
|
|
50
50
|
vec3 hi = si.position + EPS * lightDir;
|
|
51
|
-
if (
|
|
51
|
+
if (gF) {
|
|
52
52
|
const float bZ = 0.1;
|
|
53
53
|
float dr = dot(si.normal, lightDir);
|
|
54
|
-
#ifdef
|
|
54
|
+
#ifdef USE_COAT_NORMAL_FRAMES
|
|
55
55
|
if (mat.coatNormalEnabled) { dr = dot(si.faceNormal, lightDir); }
|
|
56
56
|
#endif
|
|
57
57
|
vec3 geometricNormal = dr < 0.0 ? -si.faceNormal : si.faceNormal;
|
|
58
58
|
dr = abs(dr);
|
|
59
59
|
float hS = dot(geometricNormal, lightDir);
|
|
60
|
-
float
|
|
60
|
+
float oB = dr < bZ
|
|
61
61
|
? clamp(
|
|
62
62
|
2.0 - (hS + dr) / bZ,
|
|
63
63
|
0.0,
|
|
64
64
|
1.0
|
|
65
65
|
)
|
|
66
66
|
: clamp(1.0 - hS / bZ, 0.0, 1.0);
|
|
67
|
-
hi += si.shadowOffset *
|
|
67
|
+
hi += si.shadowOffset * oB;
|
|
68
68
|
}
|
|
69
|
-
iC(
|
|
70
|
-
if (ex(
|
|
69
|
+
iC(mz, hi, lightDir);
|
|
70
|
+
if (ex(mz, lightSample.dist - EPS, si.triangleIndex)) {
|
|
71
71
|
return vec3(0.0);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
#ifdef USE_ENVMAP
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
if (
|
|
78
|
-
vec4 background = cx(
|
|
77
|
+
if (gF && cosThetaL < 0.0 && ln.z < envLightSelectionPmf) {
|
|
78
|
+
vec4 background = cx(mz.o, lightDir);
|
|
79
79
|
lightSample.emission = ai(background.rgb * background.a, bf);
|
|
80
80
|
}
|
|
81
81
|
#endif
|
|
@@ -90,8 +90,8 @@ return fa > 0.0
|
|
|
90
90
|
: vec3(0.0);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
#ifdef
|
|
94
|
-
vec3
|
|
93
|
+
#ifdef USE_COAT_NORMAL_FRAMES
|
|
94
|
+
vec3 fF(vec3 pG, vec3 tq, vec3 view) {
|
|
95
95
|
bool qY = dot(tq, view) >= 0.0;
|
|
96
96
|
vec3 uo = qY ? tq : -tq;
|
|
97
97
|
vec3 qX = qY ? pG : -pG;
|
|
@@ -99,11 +99,11 @@ if (dot(pG, tq) <= 0.0 || dot(qX, view) <= 1e-6) { return uo; }
|
|
|
99
99
|
return qX;
|
|
100
100
|
}
|
|
101
101
|
#endif
|
|
102
|
-
void
|
|
103
|
-
vec3 ur = vec3(
|
|
104
|
-
#ifdef
|
|
102
|
+
void mb(inout ad si, J mat, inout Path aa) {
|
|
103
|
+
vec3 ur = vec3(fp(cw(BSDF_DIRECTION)), dz(cw(BSDF_LOBE)));
|
|
104
|
+
#ifdef USE_COAT_NORMAL_FRAMES
|
|
105
105
|
vec3 bC = si.faceNormal;
|
|
106
|
-
vec3
|
|
106
|
+
vec3 mE = si.normal;
|
|
107
107
|
#endif
|
|
108
108
|
float rN = -dot(si.faceNormal, aa.ray.d);
|
|
109
109
|
float sG = -dot(si.normal, aa.ray.d);
|
|
@@ -128,15 +128,15 @@ mat.inside = ndv <= 0.0 && !mat.thinWalled;
|
|
|
128
128
|
|
|
129
129
|
mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;
|
|
130
130
|
vec3 ffnormal = ndv >= 0.0 ? normal : -normal;
|
|
131
|
-
#ifdef
|
|
131
|
+
#ifdef USE_COAT_NORMAL_FRAMES
|
|
132
132
|
if (mat.coatNormalEnabled) {
|
|
133
133
|
vec3 view = -aa.ray.d;
|
|
134
|
-
float
|
|
135
|
-
mat.geometricNormal =
|
|
136
|
-
ffnormal =
|
|
137
|
-
mat.coatNormal =
|
|
138
|
-
mat.inside =
|
|
139
|
-
mat.relativeIor = (
|
|
134
|
+
float gb = dot(bC, view);
|
|
135
|
+
mat.geometricNormal = gb >= 0.0 ? bC : -bC;
|
|
136
|
+
ffnormal = fF(mE, bC, view);
|
|
137
|
+
mat.coatNormal = fF(si.coatNormal, bC, view);
|
|
138
|
+
mat.inside = gb <= 0.0 && !mat.thinWalled;
|
|
139
|
+
mat.relativeIor = (gb > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;
|
|
140
140
|
}
|
|
141
141
|
#endif
|
|
142
142
|
|
|
@@ -151,7 +151,7 @@ ag prepared;
|
|
|
151
151
|
#ifdef HAS_MEDIUM
|
|
152
152
|
int mediumType = si.mediumType;
|
|
153
153
|
float d = distance(si.position, aa.ray.o);
|
|
154
|
-
vec3
|
|
154
|
+
vec3 nu = aa.ray.o;
|
|
155
155
|
vec3 extinction = si.mediumExtinction;
|
|
156
156
|
vec3 scattering = min(si.mediumScattering, extinction);
|
|
157
157
|
float sC = max(max(extinction.x, extinction.y), extinction.z);
|
|
@@ -160,32 +160,32 @@ if (mediumType > 0 && sC > 0.0) {
|
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
int
|
|
164
|
-
float
|
|
165
|
-
float ih =
|
|
166
|
-
? min(-log(max(dz(cw(MEDIUM_DISTANCE)), 1e-7)) /
|
|
163
|
+
int nj = min(int(dz(cw(MEDIUM_CHANNEL)) * 3.0), 2);
|
|
164
|
+
float fE = extinction[nj];
|
|
165
|
+
float ih = fE > 0.0
|
|
166
|
+
? min(-log(max(dz(cw(MEDIUM_DISTANCE)), 1e-7)) / fE, d)
|
|
167
167
|
: d;
|
|
168
168
|
bl = ih < d;
|
|
169
169
|
vec3 ew = exp(-extinction * ih);
|
|
170
|
-
vec3
|
|
170
|
+
vec3 nZ = bl
|
|
171
171
|
? extinction * ew
|
|
172
172
|
: ew;
|
|
173
|
-
float
|
|
174
|
-
(
|
|
173
|
+
float nK = max(
|
|
174
|
+
(nZ.x + nZ.y + nZ.z) / 3.0,
|
|
175
175
|
1e-8
|
|
176
176
|
);
|
|
177
177
|
if (bl) {
|
|
178
|
-
aa.beta *= ew * scattering /
|
|
178
|
+
aa.beta *= ew * scattering / nK;
|
|
179
179
|
|
|
180
|
-
aa.ray.o =
|
|
180
|
+
aa.ray.o = nu + ih * aa.ray.d;
|
|
181
181
|
si.position = aa.ray.o;
|
|
182
|
-
aa.li +=
|
|
182
|
+
aa.li += mT(si, mat, prepared, aa, ffnormal, false) * aa.beta;
|
|
183
183
|
|
|
184
184
|
|
|
185
|
-
cG =
|
|
185
|
+
cG = fq(
|
|
186
186
|
-aa.ray.d,
|
|
187
187
|
si.mediumAnisotropy,
|
|
188
|
-
|
|
188
|
+
fp(cw(PHASE_DIRECTION))
|
|
189
189
|
);
|
|
190
190
|
scatteringPdf = bD(
|
|
191
191
|
dot(cG, -aa.ray.d),
|
|
@@ -193,7 +193,7 @@ si.mediumAnisotropy
|
|
|
193
193
|
);
|
|
194
194
|
}
|
|
195
195
|
else {
|
|
196
|
-
aa.beta *= ew /
|
|
196
|
+
aa.beta *= ew / nK;
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
#endif
|
|
@@ -214,7 +214,7 @@ mat.directionBitangent = si.directionBitangent;
|
|
|
214
214
|
mat.geometryTangent = si.geometryTangent;
|
|
215
215
|
mat.geometryBitangent = si.geometryBitangent;
|
|
216
216
|
prepared = eH(pS, mat, -aa.ray.d, ffnormal);
|
|
217
|
-
aa.li +=
|
|
217
|
+
aa.li += mT(si, mat, prepared, aa, ffnormal, true) * aa.beta;
|
|
218
218
|
|
|
219
219
|
bool isNextRefraction;
|
|
220
220
|
vec3 f = dv(
|
|
@@ -244,7 +244,7 @@ aa.isNextRefraction = isNextRefraction;
|
|
|
244
244
|
|
|
245
245
|
|
|
246
246
|
aa.ray.o = si.position + EPS * cG;
|
|
247
|
-
#ifdef
|
|
247
|
+
#ifdef USE_COAT_NORMAL_FRAMES
|
|
248
248
|
if (mat.coatNormalEnabled) { aa.ray.o = si.position + EPS * (dot(bC, cG) >= 0.0 ? bC : -bC); }
|
|
249
249
|
#endif
|
|
250
250
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampleMaterial.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/sampleMaterial.glsl.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iIAAiI;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,eAAe,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkRlB,CAAC","sourcesContent":["// Estimate the direct lighting integral using multiple importance sampling\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral\n\nimport { glsl } from '../../shader.js';\nexport default glsl`\nvec3 DirectLight(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {\n float occluded = 1.0;\n vec3 lightRnd = vec3(sample2D(bounceDim(LIGHT_POSITION)), sample1D(bounceDim(LIGHT_SELECT)));\n\n LightSampleRec lightSample;\n sampleLight(si.position, lightRnd, lightSample, false);\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathWavelength);\n\n vec3 lightDir = lightSample.direction;\n vec3 viewDir = -path.ray.d;\n float lightPdf = lightSample.pdf;\n // Opaque surfaces are rendered two-sided by the core renderer. Use the\n // face-forward shading normal here as well, otherwise the early-out rejects\n // every direct-light sample seen from the back of a triangle (for example\n // the inside of an imported room wall).\n float cosThetaL = dot(ffnormal, lightDir);\n#ifdef NUM_COAT_NORMAL_MAPS\n if (isSurface && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }\n#endif\n\n if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {\n return vec3(0.0);\n }\n\n float scatteringPdf = 0.0;\n vec3 f = vec3(0.0);\n if (isSurface) {\n if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {\n return vec3(0.0);\n }\n f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);\n }\n else {\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(viewDir, lightDir),\n si.mediumAnisotropy\n );\n f = vec3(scatteringPdf);\n }\n\n if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {\n return vec3(0.0);\n }\n\n Ray lightRay;\n vec3 shadowOrigin = si.position + EPS * lightDir;\n if (isSurface) {\n const float shadowTerminatorCutoff = 0.1;\n float normalLight = dot(si.normal, lightDir);\n#ifdef NUM_COAT_NORMAL_MAPS\n if (mat.coatNormalEnabled) { normalLight = dot(si.faceNormal, lightDir); }\n#endif\n vec3 geometricNormal = normalLight < 0.0 ? -si.faceNormal : si.faceNormal;\n normalLight = abs(normalLight);\n float geometricLight = dot(geometricNormal, lightDir);\n float offsetAmount = normalLight < shadowTerminatorCutoff\n ? clamp(\n 2.0 - (geometricLight + normalLight) / shadowTerminatorCutoff,\n 0.0,\n 1.0\n )\n : clamp(1.0 - geometricLight / shadowTerminatorCutoff, 0.0, 1.0);\n shadowOrigin += si.shadowOffset * offsetAmount;\n }\n initRay(lightRay, shadowOrigin, lightDir);\n if (intersectSceneShadow(lightRay, lightSample.dist - EPS, si.triangleIndex)) {\n return vec3(0.0);\n }\n\n#ifdef USE_ENVMAP\n // Match the endpoint used by a BSDF-sampled surface transmission, including\n // a separately displayed or grounded background and its coverage.\n if (isSurface && cosThetaL < 0.0 && lightRnd.z < envLightSelectionPmf) {\n vec4 background = sampleBackgroundFromRay(lightRay.o, lightDir);\n lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathWavelength);\n }\n#endif\n\n // Delta lights cannot be sampled by the BSDF strategy, so their MIS weight\n // is exactly one even when their light-selection PMF is small.\n float misWeight = lightSample.isDelta\n ? 1.0\n : sampling_power_heuristic(lightPdf, scatteringPdf);\n return misWeight > 0.0\n ? misWeight * lightSample.emission * f / lightPdf\n : vec3(0.0);\n}\n\n#ifdef NUM_COAT_NORMAL_MAPS\nvec3 coat_frame_normal(vec3 inputNormal, vec3 face, vec3 view) {\n bool front = dot(face, view) >= 0.0;\n vec3 ffFace = front ? face : -face;\n vec3 ffInput = front ? inputNormal : -inputNormal;\n if (dot(inputNormal, face) <= 0.0 || dot(ffInput, view) <= 1e-6) { return ffFace; }\n return ffInput;\n}\n#endif\nvoid SampleMaterial(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {\n vec3 matRnd = vec3(sample2D(bounceDim(BSDF_DIRECTION)), sample1D(bounceDim(BSDF_LOBE)));\n#ifdef NUM_COAT_NORMAL_MAPS\n vec3 originalFace = si.faceNormal;\n vec3 originalNormal = si.normal;\n#endif\n float ndv1 = -dot(si.faceNormal, path.ray.d);\n float ndv2 = -dot(si.normal, path.ray.d);\n if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {\n // Always treat thin material as entering medium\n if (ndv1 < 0.0) {\n si.faceNormal = -si.faceNormal;\n ndv1 = -ndv1;\n }\n if (ndv2 < 0.0) {\n si.normal = -si.normal;\n ndv2 = -ndv2;\n }\n }\n // In same edge cases normal is not torwards the camera while we can still see the face.\n // We need to choose faceNormal in this case.\n bool useFaceN = ndv1 >= 0.0 && ndv2 < 0.0;\n float ndv = useFaceN ? ndv1 : ndv2;\n vec3 normal = useFaceN ? si.faceNormal : si.normal;\n\n mat.inside = ndv <= 0.0 && !mat.thinWalled;\n // In or out\n mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;\n vec3 ffnormal = ndv >= 0.0 ? normal : -normal;\n#ifdef NUM_COAT_NORMAL_MAPS\n if (mat.coatNormalEnabled) {\n vec3 view = -path.ray.d;\n float geometricView = dot(originalFace, view);\n mat.geometricNormal = geometricView >= 0.0 ? originalFace : -originalFace;\n ffnormal = coat_frame_normal(originalNormal, originalFace, view);\n mat.coatNormal = coat_frame_normal(si.coatNormal, originalFace, view);\n mat.inside = geometricView <= 0.0 && !mat.thinWalled;\n mat.relativeIor = (geometricView > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;\n }\n#endif\n\n\n float scatteringPdf;\n vec3 scatterDir;\n path.scatteringIsDelta = false;\n bool mediumSampled = false;\n bool crossedBoundary = false;\n OpenPbrPreparedBsdf prepared;\n\n#ifdef HAS_MEDIUM\n int mediumType = si.mediumType;\n float d = distance(si.position, path.ray.o);\n vec3 segmentOrigin = path.ray.o;\n vec3 extinction = si.mediumExtinction;\n vec3 scattering = min(si.mediumScattering, extinction);\n float majorant = max(max(extinction.x, extinction.y), extinction.z);\n if (mediumType > 0 && majorant > 0.0) {\n // Sample one RGB extinction channel and divide by the mixture PDF. This\n // is the homogeneous-medium estimator used by PBRT and avoids the very\n // large exp((majorant - extinction) * distance) weights produced by\n // majorant tracking when OpenPBR SSS radii differ strongly by channel.\n int mediumChannel = min(int(sample1D(bounceDim(MEDIUM_CHANNEL)) * 3.0), 2);\n float channelExtinction = extinction[mediumChannel];\n float scatterDist = channelExtinction > 0.0\n ? min(-log(max(sample1D(bounceDim(MEDIUM_DISTANCE)), 1e-7)) / channelExtinction, d)\n : d;\n mediumSampled = scatterDist < d;\n vec3 transmittance = exp(-extinction * scatterDist);\n vec3 density = mediumSampled\n ? extinction * transmittance\n : transmittance;\n float mediumPdf = max(\n (density.x + density.y + density.z) / 3.0,\n 1e-8\n );\n if (mediumSampled) {\n path.beta *= transmittance * scattering / mediumPdf;\n // Move from the start of the segment, not from its end surface.\n path.ray.o = segmentOrigin + scatterDist * path.ray.d;\n si.position = path.ray.o;\n path.li += DirectLight(si, mat, prepared, path, ffnormal, false) * path.beta;\n\n // Pick a new direction based on the phase function\n scatterDir = sampling_henyey_greenstein(\n -path.ray.d,\n si.mediumAnisotropy,\n sample2D(bounceDim(PHASE_DIRECTION))\n );\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(scatterDir, -path.ray.d),\n si.mediumAnisotropy\n );\n }\n else {\n path.beta *= transmittance / mediumPdf;\n }\n }\n#endif\n\n // Direct lighting\n if (!mediumSampled) {\n path.li += mat.emission * path.beta;\n if (mat.materialType == UNLIT) {\n path.abort = true;\n return;\n }\n vec3 surfaceTangent = vec3(0.0);\n#ifdef USE_TANGENT\n surfaceTangent = si.tangent;\n#endif\n mat.directionTangent = si.directionTangent;\n mat.directionBitangent = si.directionBitangent;\n mat.geometryTangent = si.geometryTangent;\n mat.geometryBitangent = si.geometryBitangent;\n prepared = openpbr_prepare(surfaceTangent, mat, -path.ray.d, ffnormal);\n path.li += DirectLight(si, mat, prepared, path, ffnormal, true) * path.beta;\n // Sample BSDF for color and outgoing direction\n bool isNextRefraction;\n vec3 f = openpbr_sample_prepared(\n prepared,\n matRnd,\n scatterDir,\n scatteringPdf,\n isNextRefraction\n );\n // Null-boundary transmission is discrete and has no NEE competitor.\n path.scatteringIsDelta = !prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;\n // Match WebGPU: rejected VNDF/refraction proposals have no continuation.\n // Tracing their fallback direction with the incoming throughput invents\n // light paths, especially after total internal reflection inside glass.\n if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||\n dot(scatterDir, scatterDir) < 0.5) {\n path.scatteringPdf = 0.0;\n path.abort = true;\n return;\n }\n path.beta *= f / scatteringPdf;\n crossedBoundary = !mat.thinWalled &&\n isNextRefraction;\n path.isNextRefraction = isNextRefraction;\n // TODO prefer the opaque surface when transmission surface and opaque surface are overlapped.\n // Or the ray go out from transmission material will miss the opque surface.\n path.ray.o = si.position + EPS * scatterDir;\n#ifdef NUM_COAT_NORMAL_MAPS\n if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(originalFace, scatterDir) >= 0.0 ? originalFace : -originalFace); }\n#endif\n }\n\n path.scatteringPdf = scatteringPdf;\n initRay(path.ray, path.ray.o, scatterDir);\n if (mediumSampled) {\n path.isNextRefraction = false;\n }\n path.fromEye = false;\n\n#ifdef HAS_MEDIUM\n // A reflected ray stays in its current medium. Only a sampled transmission\n // event crosses the boundary of a medium-bearing closed mesh.\n if (!mediumSampled && crossedBoundary && mat.mediumType > 0) {\n if (ndv1 >= 0.0) {\n si.mediumType = mat.mediumType;\n si.mediumExtinction = mat.mediumExtinction;\n si.mediumScattering = mat.mediumScattering;\n si.mediumAnisotropy = mat.mediumAnisotropy;\n }\n else {\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n }\n }\n#endif\n}\n`;\n"]}
|
|
1
|
+
{"version":3,"file":"sampleMaterial.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/sampleMaterial.glsl.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iIAAiI;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,eAAe,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkRlB,CAAC","sourcesContent":["// Estimate the direct lighting integral using multiple importance sampling\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral\n\nimport { glsl } from '../../shader.js';\nexport default glsl`\nvec3 DirectLight(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {\n float occluded = 1.0;\n vec3 lightRnd = vec3(sample2D(bounceDim(LIGHT_POSITION)), sample1D(bounceDim(LIGHT_SELECT)));\n\n LightSampleRec lightSample;\n sampleLight(si.position, lightRnd, lightSample, false);\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathWavelength);\n\n vec3 lightDir = lightSample.direction;\n vec3 viewDir = -path.ray.d;\n float lightPdf = lightSample.pdf;\n // Opaque surfaces are rendered two-sided by the core renderer. Use the\n // face-forward shading normal here as well, otherwise the early-out rejects\n // every direct-light sample seen from the back of a triangle (for example\n // the inside of an imported room wall).\n float cosThetaL = dot(ffnormal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (isSurface && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }\n#endif\n\n if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {\n return vec3(0.0);\n }\n\n float scatteringPdf = 0.0;\n vec3 f = vec3(0.0);\n if (isSurface) {\n if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {\n return vec3(0.0);\n }\n f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);\n }\n else {\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(viewDir, lightDir),\n si.mediumAnisotropy\n );\n f = vec3(scatteringPdf);\n }\n\n if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {\n return vec3(0.0);\n }\n\n Ray lightRay;\n vec3 shadowOrigin = si.position + EPS * lightDir;\n if (isSurface) {\n const float shadowTerminatorCutoff = 0.1;\n float normalLight = dot(si.normal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { normalLight = dot(si.faceNormal, lightDir); }\n#endif\n vec3 geometricNormal = normalLight < 0.0 ? -si.faceNormal : si.faceNormal;\n normalLight = abs(normalLight);\n float geometricLight = dot(geometricNormal, lightDir);\n float offsetAmount = normalLight < shadowTerminatorCutoff\n ? clamp(\n 2.0 - (geometricLight + normalLight) / shadowTerminatorCutoff,\n 0.0,\n 1.0\n )\n : clamp(1.0 - geometricLight / shadowTerminatorCutoff, 0.0, 1.0);\n shadowOrigin += si.shadowOffset * offsetAmount;\n }\n initRay(lightRay, shadowOrigin, lightDir);\n if (intersectSceneShadow(lightRay, lightSample.dist - EPS, si.triangleIndex)) {\n return vec3(0.0);\n }\n\n#ifdef USE_ENVMAP\n // Match the endpoint used by a BSDF-sampled surface transmission, including\n // a separately displayed or grounded background and its coverage.\n if (isSurface && cosThetaL < 0.0 && lightRnd.z < envLightSelectionPmf) {\n vec4 background = sampleBackgroundFromRay(lightRay.o, lightDir);\n lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathWavelength);\n }\n#endif\n\n // Delta lights cannot be sampled by the BSDF strategy, so their MIS weight\n // is exactly one even when their light-selection PMF is small.\n float misWeight = lightSample.isDelta\n ? 1.0\n : sampling_power_heuristic(lightPdf, scatteringPdf);\n return misWeight > 0.0\n ? misWeight * lightSample.emission * f / lightPdf\n : vec3(0.0);\n}\n\n#ifdef USE_COAT_NORMAL_FRAMES\nvec3 coat_frame_normal(vec3 inputNormal, vec3 face, vec3 view) {\n bool front = dot(face, view) >= 0.0;\n vec3 ffFace = front ? face : -face;\n vec3 ffInput = front ? inputNormal : -inputNormal;\n if (dot(inputNormal, face) <= 0.0 || dot(ffInput, view) <= 1e-6) { return ffFace; }\n return ffInput;\n}\n#endif\nvoid SampleMaterial(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {\n vec3 matRnd = vec3(sample2D(bounceDim(BSDF_DIRECTION)), sample1D(bounceDim(BSDF_LOBE)));\n#ifdef USE_COAT_NORMAL_FRAMES\n vec3 originalFace = si.faceNormal;\n vec3 originalNormal = si.normal;\n#endif\n float ndv1 = -dot(si.faceNormal, path.ray.d);\n float ndv2 = -dot(si.normal, path.ray.d);\n if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {\n // Always treat thin material as entering medium\n if (ndv1 < 0.0) {\n si.faceNormal = -si.faceNormal;\n ndv1 = -ndv1;\n }\n if (ndv2 < 0.0) {\n si.normal = -si.normal;\n ndv2 = -ndv2;\n }\n }\n // In same edge cases normal is not torwards the camera while we can still see the face.\n // We need to choose faceNormal in this case.\n bool useFaceN = ndv1 >= 0.0 && ndv2 < 0.0;\n float ndv = useFaceN ? ndv1 : ndv2;\n vec3 normal = useFaceN ? si.faceNormal : si.normal;\n\n mat.inside = ndv <= 0.0 && !mat.thinWalled;\n // In or out\n mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;\n vec3 ffnormal = ndv >= 0.0 ? normal : -normal;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) {\n vec3 view = -path.ray.d;\n float geometricView = dot(originalFace, view);\n mat.geometricNormal = geometricView >= 0.0 ? originalFace : -originalFace;\n ffnormal = coat_frame_normal(originalNormal, originalFace, view);\n mat.coatNormal = coat_frame_normal(si.coatNormal, originalFace, view);\n mat.inside = geometricView <= 0.0 && !mat.thinWalled;\n mat.relativeIor = (geometricView > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;\n }\n#endif\n\n\n float scatteringPdf;\n vec3 scatterDir;\n path.scatteringIsDelta = false;\n bool mediumSampled = false;\n bool crossedBoundary = false;\n OpenPbrPreparedBsdf prepared;\n\n#ifdef HAS_MEDIUM\n int mediumType = si.mediumType;\n float d = distance(si.position, path.ray.o);\n vec3 segmentOrigin = path.ray.o;\n vec3 extinction = si.mediumExtinction;\n vec3 scattering = min(si.mediumScattering, extinction);\n float majorant = max(max(extinction.x, extinction.y), extinction.z);\n if (mediumType > 0 && majorant > 0.0) {\n // Sample one RGB extinction channel and divide by the mixture PDF. This\n // is the homogeneous-medium estimator used by PBRT and avoids the very\n // large exp((majorant - extinction) * distance) weights produced by\n // majorant tracking when OpenPBR SSS radii differ strongly by channel.\n int mediumChannel = min(int(sample1D(bounceDim(MEDIUM_CHANNEL)) * 3.0), 2);\n float channelExtinction = extinction[mediumChannel];\n float scatterDist = channelExtinction > 0.0\n ? min(-log(max(sample1D(bounceDim(MEDIUM_DISTANCE)), 1e-7)) / channelExtinction, d)\n : d;\n mediumSampled = scatterDist < d;\n vec3 transmittance = exp(-extinction * scatterDist);\n vec3 density = mediumSampled\n ? extinction * transmittance\n : transmittance;\n float mediumPdf = max(\n (density.x + density.y + density.z) / 3.0,\n 1e-8\n );\n if (mediumSampled) {\n path.beta *= transmittance * scattering / mediumPdf;\n // Move from the start of the segment, not from its end surface.\n path.ray.o = segmentOrigin + scatterDist * path.ray.d;\n si.position = path.ray.o;\n path.li += DirectLight(si, mat, prepared, path, ffnormal, false) * path.beta;\n\n // Pick a new direction based on the phase function\n scatterDir = sampling_henyey_greenstein(\n -path.ray.d,\n si.mediumAnisotropy,\n sample2D(bounceDim(PHASE_DIRECTION))\n );\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(scatterDir, -path.ray.d),\n si.mediumAnisotropy\n );\n }\n else {\n path.beta *= transmittance / mediumPdf;\n }\n }\n#endif\n\n // Direct lighting\n if (!mediumSampled) {\n path.li += mat.emission * path.beta;\n if (mat.materialType == UNLIT) {\n path.abort = true;\n return;\n }\n vec3 surfaceTangent = vec3(0.0);\n#ifdef USE_TANGENT\n surfaceTangent = si.tangent;\n#endif\n mat.directionTangent = si.directionTangent;\n mat.directionBitangent = si.directionBitangent;\n mat.geometryTangent = si.geometryTangent;\n mat.geometryBitangent = si.geometryBitangent;\n prepared = openpbr_prepare(surfaceTangent, mat, -path.ray.d, ffnormal);\n path.li += DirectLight(si, mat, prepared, path, ffnormal, true) * path.beta;\n // Sample BSDF for color and outgoing direction\n bool isNextRefraction;\n vec3 f = openpbr_sample_prepared(\n prepared,\n matRnd,\n scatterDir,\n scatteringPdf,\n isNextRefraction\n );\n // Null-boundary transmission is discrete and has no NEE competitor.\n path.scatteringIsDelta = !prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;\n // Match WebGPU: rejected VNDF/refraction proposals have no continuation.\n // Tracing their fallback direction with the incoming throughput invents\n // light paths, especially after total internal reflection inside glass.\n if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||\n dot(scatterDir, scatterDir) < 0.5) {\n path.scatteringPdf = 0.0;\n path.abort = true;\n return;\n }\n path.beta *= f / scatteringPdf;\n crossedBoundary = !mat.thinWalled &&\n isNextRefraction;\n path.isNextRefraction = isNextRefraction;\n // TODO prefer the opaque surface when transmission surface and opaque surface are overlapped.\n // Or the ray go out from transmission material will miss the opque surface.\n path.ray.o = si.position + EPS * scatterDir;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(originalFace, scatterDir) >= 0.0 ? originalFace : -originalFace); }\n#endif\n }\n\n path.scatteringPdf = scatteringPdf;\n initRay(path.ray, path.ray.o, scatterDir);\n if (mediumSampled) {\n path.isNextRefraction = false;\n }\n path.fromEye = false;\n\n#ifdef HAS_MEDIUM\n // A reflected ray stays in its current medium. Only a sampled transmission\n // event crosses the boundary of a medium-bearing closed mesh.\n if (!mediumSampled && crossedBoundary && mat.mediumType > 0) {\n if (ndv1 >= 0.0) {\n si.mediumType = mat.mediumType;\n si.mediumExtinction = mat.mediumExtinction;\n si.mediumScattering = mat.mediumScattering;\n si.mediumAnisotropy = mat.mediumAnisotropy;\n }\n else {\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n }\n }\n#endif\n}\n`;\n"]}
|
|
@@ -16,28 +16,28 @@ return candidate == 0u ? cw(slot) : cw(9u + (candidate - 1u) * 3u + slot);
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
void sampleShadowCatcher(ad si, int bounce, inout Path aa) {
|
|
19
|
-
vec3
|
|
19
|
+
vec3 oS = -aa.ray.d;
|
|
20
20
|
|
|
21
21
|
#if defined(NUM_LIGHTS) || defined(USE_ENVMAP)
|
|
22
22
|
float visibility = 0.0;
|
|
23
23
|
for (uint candidate = 0u; candidate < SHADOW_CATCHER_LIGHT_SAMPLES; candidate++) {
|
|
24
24
|
LightSampleRec lightSample;
|
|
25
25
|
vec3 ln = vec3(
|
|
26
|
-
|
|
26
|
+
fp(ky(candidate, LIGHT_POSITION)),
|
|
27
27
|
dz(ky(candidate, LIGHT_SELECT))
|
|
28
28
|
);
|
|
29
29
|
sampleLight(si.position, ln, lightSample, false);
|
|
30
30
|
|
|
31
31
|
vec3 lightDir = lightSample.direction;
|
|
32
32
|
float cosThetaL = dot(si.normal, lightDir);
|
|
33
|
-
float pM = dot(si.normal,
|
|
34
|
-
bool
|
|
33
|
+
float pM = dot(si.normal, oS) * cosThetaL;
|
|
34
|
+
bool mC = false;
|
|
35
35
|
if (pM >= 0.0) {
|
|
36
36
|
Ray ray;
|
|
37
37
|
iC(ray, si.position + EPS * lightDir, lightDir);
|
|
38
|
-
|
|
38
|
+
mC = ex(ray, lightSample.dist - EPS, si.triangleIndex);
|
|
39
39
|
}
|
|
40
|
-
visibility +=
|
|
40
|
+
visibility += mC ? 0.0 : 1.0;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
aa.alpha = visibility / float(SHADOW_CATCHER_LIGHT_SAMPLES);
|
|
@@ -6,27 +6,27 @@ export default glsl `
|
|
|
6
6
|
|
|
7
7
|
vec3 aQ(vec3 view, vec2 alpha, vec2 samplePoint) {
|
|
8
8
|
vec3 rm = vec3(alpha, 1.0);
|
|
9
|
-
vec3
|
|
10
|
-
float uh = min(
|
|
9
|
+
vec3 gk = normalize(rm * view);
|
|
10
|
+
float uh = min(gk.z, 1.0);
|
|
11
11
|
float qQ = 1.0 + uh;
|
|
12
12
|
float rh = (1.0 - samplePoint.y) * qQ;
|
|
13
13
|
float rR = samplePoint.y * qQ;
|
|
14
14
|
float sI = rh + (1.0 - uh);
|
|
15
15
|
float fl = sqrt(max(0.0, sI * rR));
|
|
16
16
|
float br = TWOPI * samplePoint.x;
|
|
17
|
-
vec3
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
vec3 lI = vec3(
|
|
18
|
+
gk.x + fl * cos(br),
|
|
19
|
+
gk.y + fl * sin(br),
|
|
20
20
|
rh
|
|
21
21
|
);
|
|
22
|
-
return normalize(rm *
|
|
22
|
+
return normalize(rm * lI);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
float
|
|
25
|
+
float gL(vec3 oo, vec2 alpha) {
|
|
26
26
|
vec3 hr = vec3(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
oo.x / alpha.x,
|
|
28
|
+
oo.y / alpha.y,
|
|
29
|
+
oo.z
|
|
30
30
|
);
|
|
31
31
|
float ap = dot(hr, hr);
|
|
32
32
|
return 1.0 / (
|
|
@@ -40,9 +40,9 @@ if (eF <= 1e-8) {
|
|
|
40
40
|
return 0.0;
|
|
41
41
|
}
|
|
42
42
|
vec2 ic = alpha * direction.xy;
|
|
43
|
-
float
|
|
43
|
+
float lJ = dot(ic, ic)
|
|
44
44
|
/ (eF * eF);
|
|
45
|
-
return 2.0 / (1.0 + sqrt(1.0 +
|
|
45
|
+
return 2.0 / (1.0 + sqrt(1.0 + lJ));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
float aE(float au) {
|
|
@@ -58,17 +58,17 @@ if (kl >= 1.0) {
|
|
|
58
58
|
return 1.0;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
float
|
|
62
|
-
float ba = (iA - cJ *
|
|
63
|
-
/ max(iA + cJ *
|
|
64
|
-
float pN = (cJ * iA -
|
|
65
|
-
/ max(cJ * iA +
|
|
61
|
+
float lT = sqrt(max(0.0, 1.0 - kl));
|
|
62
|
+
float ba = (iA - cJ * lT)
|
|
63
|
+
/ max(iA + cJ * lT, 1e-8);
|
|
64
|
+
float pN = (cJ * iA - lT)
|
|
65
|
+
/ max(cJ * iA + lT, 1e-8);
|
|
66
66
|
return 0.5 * (
|
|
67
67
|
ba * ba + pN * pN
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
vec2
|
|
71
|
+
vec2 gi(vec2 samplePoint) {
|
|
72
72
|
vec2 offset = 2.0 * samplePoint - vec2(1.0);
|
|
73
73
|
if (offset.x == 0.0 && offset.y == 0.0) {
|
|
74
74
|
return vec2(0.0);
|
|
@@ -88,21 +88,21 @@ return radius * vec2(cos(angle), sin(angle));
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
vec3 bi(vec2 samplePoint) {
|
|
91
|
-
vec2 kF =
|
|
91
|
+
vec2 kF = gi(samplePoint);
|
|
92
92
|
return vec3(
|
|
93
93
|
kF,
|
|
94
94
|
sqrt(max(0.0, 1.0 - dot(kF, kF)))
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
float aG(float pr, float
|
|
99
|
-
float scale = max(pr,
|
|
98
|
+
float aG(float pr, float nN) {
|
|
99
|
+
float scale = max(pr, nN);
|
|
100
100
|
if (scale <= 0.0) {
|
|
101
101
|
return 0.0;
|
|
102
102
|
}
|
|
103
|
-
vec2 normalized = vec2(pr,
|
|
104
|
-
vec2
|
|
105
|
-
return
|
|
103
|
+
vec2 normalized = vec2(pr, nN) / scale;
|
|
104
|
+
vec2 oO = normalized * normalized;
|
|
105
|
+
return oO.x / (oO.x + oO.y);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
void aL(in vec3 normal, out vec3 tangent, out vec3 bitangent) {
|
|
@@ -135,12 +135,12 @@ return rgb * tN;
|
|
|
135
135
|
|
|
136
136
|
float eN(
|
|
137
137
|
float wavelength,
|
|
138
|
-
float
|
|
138
|
+
float hh,
|
|
139
139
|
float hp,
|
|
140
140
|
float qs
|
|
141
141
|
) {
|
|
142
142
|
if (wavelength == 0.0 || hp <= 0.0) {
|
|
143
|
-
return
|
|
143
|
+
return hh;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
const float FRAUNHOFER_C = 656.3;
|
|
@@ -150,15 +150,15 @@ float jR = 1.0 / (
|
|
|
150
150
|
1.0 / (FRAUNHOFER_F * FRAUNHOFER_F)
|
|
151
151
|
- 1.0 / (FRAUNHOFER_C * FRAUNHOFER_C)
|
|
152
152
|
);
|
|
153
|
-
float
|
|
154
|
-
float qR = (
|
|
155
|
-
float tl =
|
|
153
|
+
float ng = max(qs / hp, 1e-6);
|
|
154
|
+
float qR = (hh - 1.0) * jR / ng;
|
|
155
|
+
float tl = hh
|
|
156
156
|
- qR / (FRAUNHOFER_D * FRAUNHOFER_D);
|
|
157
157
|
return tl + qR / (wavelength * wavelength);
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
vec3
|
|
161
|
-
vec3
|
|
160
|
+
vec3 fq(
|
|
161
|
+
vec3 gz,
|
|
162
162
|
float anisotropy,
|
|
163
163
|
vec2 samplePoint
|
|
164
164
|
) {
|
|
@@ -178,10 +178,10 @@ float ud = sqrt(max(0.0, 1.0 - au * au));
|
|
|
178
178
|
float br = TWOPI * samplePoint.x;
|
|
179
179
|
vec3 tangent;
|
|
180
180
|
vec3 bitangent;
|
|
181
|
-
aL(
|
|
181
|
+
aL(gz, tangent, bitangent);
|
|
182
182
|
return tangent * (ud * cos(br))
|
|
183
183
|
+ bitangent * (ud * sin(br))
|
|
184
|
-
+
|
|
184
|
+
+ gz * au;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
float bD(float au, float anisotropy) {
|
|
@@ -99,18 +99,18 @@ return CAMERA_BEVEL_BASE + uint(BEVEL_SAMPLES) + cF * BOUNCE_STRIDE + slot;
|
|
|
99
99
|
|
|
100
100
|
uvec4 hl;
|
|
101
101
|
uint hm;
|
|
102
|
-
bool
|
|
102
|
+
bool fC = false;
|
|
103
103
|
bool dg = false;
|
|
104
104
|
uint dF;
|
|
105
|
-
uint
|
|
105
|
+
uint gv;
|
|
106
106
|
vec2 eQ;
|
|
107
107
|
void dw(uint dim) {
|
|
108
108
|
|
|
109
109
|
uint kd = bc.x + bc.y * uint(round(1.0 / pixelSize.x));
|
|
110
110
|
uvec4 key = uvec4(dim, bd, kd, uint(sequenceSeed));
|
|
111
|
-
if (
|
|
111
|
+
if (fC && all(equal(hl, key)) && hm == uint(zSobolLogSPP)) { return; }
|
|
112
112
|
hl = key; hm = uint(zSobolLogSPP);
|
|
113
|
-
|
|
113
|
+
fC = true; dg = false;
|
|
114
114
|
uint ij = aq(aq(kd, dim), uint(sequenceSeed));
|
|
115
115
|
uint index = bd;
|
|
116
116
|
if (samplingPattern == 1) {
|
|
@@ -129,14 +129,14 @@ if (bd != 0u) { jb += 1u; }
|
|
|
129
129
|
ij = aq(ij, jb);
|
|
130
130
|
}
|
|
131
131
|
dF = sK(index, aq(ij, 0u));
|
|
132
|
-
|
|
132
|
+
gv = ij;
|
|
133
133
|
uint x = reverseBits(iE(dF, aq(ij, 1u)));
|
|
134
134
|
eQ.x = float(x >> 8u) * (1.0 / 16777216.0);
|
|
135
135
|
}
|
|
136
136
|
vec2 kS(uint dim) {
|
|
137
137
|
dw(dim);
|
|
138
138
|
if (!dg) {
|
|
139
|
-
uint y = sK(rl(dF), aq(
|
|
139
|
+
uint y = sK(rl(dF), aq(gv, 2u));
|
|
140
140
|
eQ.y = float(y >> 8u) * (1.0 / 16777216.0);
|
|
141
141
|
dg = true;
|
|
142
142
|
}
|
|
@@ -147,7 +147,7 @@ if (samplingPattern == 2) { return EPS + (1.0 - 2.0*EPS)*rand(); }
|
|
|
147
147
|
dw(dim);
|
|
148
148
|
return EPS + (1.0 - 2.0*EPS) * eQ.x;
|
|
149
149
|
}
|
|
150
|
-
vec2
|
|
150
|
+
vec2 fp(uint dim) {
|
|
151
151
|
if (samplingPattern == 2) {
|
|
152
152
|
float x = dz(dim); float y = dz(dim);
|
|
153
153
|
return vec2(x,y);
|
|
@@ -58,7 +58,7 @@ float theta = atan(pos.z, pos.x) / (2.0 * PI) + 0.5;
|
|
|
58
58
|
return vec2(theta, pos.y);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
vec2
|
|
61
|
+
vec2 gI(int fk, vec3 pos, vec3 normal, vec2 uvScale) {
|
|
62
62
|
if (fk == ${uvProjectionConstants.triplanar + ''}) {
|
|
63
63
|
return iR(pos, normal, uvScale);
|
|
64
64
|
} else if (fk == ${uvProjectionConstants.spherical + ''}) {
|
|
@@ -35,7 +35,7 @@ vec4 target = viewProjectionInv * vec4(uv * 2.0 - 1.0, 1.0, 1.0);
|
|
|
35
35
|
Ray ray;
|
|
36
36
|
iC(ray, origin.xyz / origin.w, normalize(target.xyz * origin.w - origin.xyz * target.w));
|
|
37
37
|
vec3 eye = viewInv[3].xyz;
|
|
38
|
-
vec3
|
|
38
|
+
vec3 oj = -normalize(viewInv[2].xyz);
|
|
39
39
|
ad si;
|
|
40
40
|
si.triangleIndex = -1;
|
|
41
41
|
for (int layer = 0; layer < 32; layer++) {
|
|
@@ -44,7 +44,7 @@ if (!si.hit) return;
|
|
|
44
44
|
J material;
|
|
45
45
|
eX(material, si.materialIndex, si.uv, si.uv1, si.instanceIndex, si.vertexColor);
|
|
46
46
|
if (material.materialType != SHADOW_CATCHER && material.alpha > 0.0) {
|
|
47
|
-
out_depth.r = max(dot(si.position - eye,
|
|
47
|
+
out_depth.r = max(dot(si.position - eye, oj), 0.0);
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
ray.o = si.position + ray.d * (EPS * 0.02);
|