@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
package/docs/api.md
CHANGED
|
@@ -333,7 +333,8 @@ one. See [thin-film textures](./materials.md#textures) for range behavior.
|
|
|
333
333
|
`undefined`. Channels and color decoding are listed in [material textures](./materials.md#textures).
|
|
334
334
|
They follow the existing material/texture update mechanism.
|
|
335
335
|
|
|
336
|
-
`coatNormalMap` defaults to `undefined
|
|
336
|
+
`coatNormalMap` defaults to `undefined`; `coatNormalScale` defaults to `[1, 1]`.
|
|
337
|
+
See [coat normals](./materials.md#coat-normals) for independent base and coat normal mapping.
|
|
337
338
|
|
|
338
339
|
Raw texture sources contain exactly `width * height * 4` RGBA values, with
|
|
339
340
|
rows ordered from top to bottom. `Uint8Array` and `Uint8ClampedArray` store
|
package/docs/materials.md
CHANGED
|
@@ -260,41 +260,32 @@ with coat, and the finite path-event budget can truncate deep glass paths.
|
|
|
260
260
|
## Coat normals
|
|
261
261
|
|
|
262
262
|
Set `coatNormalMap` to give the coat a tangent-space normal independently of
|
|
263
|
-
`normalMap`.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
shading normal, including the base normal map.
|
|
267
|
-
|
|
268
|
-
The coat TBN starts from the interpolated geometry normal before base normal
|
|
269
|
-
mapping. It uses the coat texture's UV0/UV1 selection and geometric
|
|
270
|
-
tangent handedness; generated tangents use UV1 differentials when that set is
|
|
271
|
-
selected. Degenerate frames and zero decoded vectors use stable fallbacks.
|
|
272
|
-
The texture's scale, offset and `flipY` follow the ordinary atlas sampling
|
|
273
|
-
rules. As with other slots, sharing an image never changes its color space.
|
|
274
|
-
|
|
275
|
-
Base lobes keep their base frame. Coat reflection, its sampling PDF, directional
|
|
276
|
-
albedo and passage absorption use the coat frame; the renderer combines their
|
|
277
|
-
responses and densities for the same world direction. Each frame is corrected
|
|
278
|
-
against the geometric/view hemisphere independently. Triangle normals still
|
|
279
|
-
control reflection versus transmission, medium boundaries and ray offsets.
|
|
280
|
-
A coat reflection can contribute below the base shading hemisphere when it
|
|
281
|
-
remains above the coat and geometric hemispheres. As before, solid interior
|
|
282
|
-
hits omit coat reflection; thin surfaces are treated as exterior hits.
|
|
263
|
+
`normalMap`. Without a coat map (the default), the coat uses the interpolated
|
|
264
|
+
surface normal before base normal mapping. A bumpy base can therefore have a
|
|
265
|
+
smooth coat. Assign the same texture to both maps to perturb both layers.
|
|
283
266
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
267
|
+
The map decodes linear RGB as `2 * RGB - 1`, multiplies XY by
|
|
268
|
+
`coatNormalScale`, then normalizes. The scale defaults to `[1, 1]` and can be
|
|
269
|
+
negative or zero. UV0/UV1 selection, scale, offset and `flipY` follow the
|
|
270
|
+
ordinary texture rules. Zero coat weight or zero sampled coat coverage
|
|
271
|
+
disables the coat without changing the base normal.
|
|
287
272
|
|
|
288
273
|
Replacing the map or editing its scale is detected by `engine.update()`. Call
|
|
289
274
|
`texture.markUpdated()` after pixel or UV-array element edits; see [scene updates](./updates.md).
|
|
290
|
-
|
|
291
|
-
|
|
275
|
+
|
|
276
|
+
Coat reflections can remain visible where the base normal points away from
|
|
277
|
+
the light. Solid interior hits omit coat reflection; thin surfaces are
|
|
278
|
+
treated as exterior hits.
|
|
279
|
+
|
|
280
|
+
Strongly tilted shading normals lose some lobe support when clipped to the
|
|
281
|
+
geometric hemisphere. A unit white environment can therefore render below
|
|
282
|
+
unit radiance; the renderer does not renormalize the clipped lobes.
|
|
292
283
|
|
|
293
284
|
## Anisotropy directions
|
|
294
285
|
|
|
295
286
|
Set `specularAnisotropyRotation` or provide `anisotropyMap` to orient the base specular lobe. The map reads linear `2 * RG - 1`, normalizes the direction, multiplies strength by B, and then applies the rotation. A decoded squared length at or below `1e-4` falls back to `(1, 0)` before rotation (including the two central RGBA8 codes). Without a map the direction is `(1, 0)` and the strength multiplier is one. The rotation defaults to zero; the map defaults to undefined.
|
|
296
287
|
|
|
297
|
-
`coatAnisotropyRotation` defaults to zero and uses the geometry tangent independently of the base map. Base and coat
|
|
288
|
+
`coatAnisotropyRotation` defaults to zero and uses the geometry tangent independently of the base map. Base and coat use their respective directions and [normals](#coat-normals). Zero anisotropy strength ignores the direction.
|
|
298
289
|
|
|
299
290
|
Provided tangent XYZ and optional W handedness are preserved. For XYZ tangents the sign comes from triangle UV derivatives. Missing or degenerate tangents use UV derivatives and then a stable orthonormal fallback; missing tangents produce one diagnostic per geometry. The direction texture's selected UV set is used for derivative fallback, including UV1. A provided XYZW tangent remains authoritative. Directions are reorthogonalized against the final shading normal, including normal maps and back faces, and instance transforms preserve mirrored handedness. UV scale, offset and flipY affect texel lookup; they do not rotate the encoded direction.
|
|
300
291
|
|
package/docs/threejs.md
CHANGED
|
@@ -108,12 +108,12 @@ or a source `THREE.Texture`. `THREESync` converts parameter edits without
|
|
|
108
108
|
rewriting texture pixels. The iridescence strength texture is not supported;
|
|
109
109
|
`thinFilmMap` represents thickness only.
|
|
110
110
|
|
|
111
|
-
The six layer maps
|
|
112
|
-
|
|
111
|
+
The six layer maps preserve the source UV channel, scale, offset and `flipY`.
|
|
112
|
+
`mutracerOpenPBR` can override them with a MuTracer
|
|
113
113
|
`Texture` or `THREE.Texture`; explicit `null` clears an imported map, while
|
|
114
|
-
unknown JSON objects are ignored. `THREESync` follows texture edits
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
unknown JSON objects are ignored. `THREESync` follows texture edits.
|
|
115
|
+
General `KHR_texture_transform` rotation remains unsupported.
|
|
116
|
+
See [coat normal conversion](#coat-normal-conversion) for clearcoat normal maps.
|
|
117
117
|
Anisotropy direction and source-model mapping are described [below](#anisotropy-source-conversion). The conversion preserves OpenPBR layering: glTF sheen
|
|
118
118
|
layer order differs, and specular weight/color also affect metals in OpenPBR;
|
|
119
119
|
these imports do not imply identical glTF BRDFs. A fully metallic material
|
package/docs/viewer.md
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Using the viewer
|
|
2
|
+
|
|
3
|
+
Open **Examples → MuTracer collection** for models curated for this viewer, or
|
|
4
|
+
**Examples → glTF Research Scenes** for the independently maintained
|
|
5
|
+
[glTF Research Scenes](https://github.com/ErfanMo77/gltf-research-scenes) collection.
|
|
6
|
+
Scenes download on demand from GitHub; cards show approximate download sizes
|
|
7
|
+
and link to each scene's source and license. Large scenes need more memory.
|
|
8
|
+
|
|
9
|
+
glTF/GLB imports include directional, point and spot lights and emissive meshes.
|
|
10
|
+
Benchmark scenes also load their sunlight and available environment maps.
|
|
11
|
+
Under **Lighting → Environment**, **Scene lighting** is available only when the
|
|
12
|
+
model provides lights or environment lighting. Choose it to use the imported
|
|
13
|
+
lighting alone, or select an HDRI or Studio to add lighting. Emissive materials
|
|
14
|
+
still work with HDRI and Studio. Environment maps add download time and are
|
|
15
|
+
resampled to at most 2K width. If a source map is missing, the model still opens
|
|
16
|
+
and the Lighting panel explains which map is unavailable; choose an environment
|
|
17
|
+
there to replace it.
|
|
18
|
+
|
|
19
|
+
When an imported glTF/GLB contains cameras, a toast offers **Apply camera** to
|
|
20
|
+
use its first camera.
|
|
21
|
+
Dismiss the toast to keep the Orbit view. You can select any imported camera
|
|
22
|
+
in the separate camera toolbar at the bottom right; it appears only for models
|
|
23
|
+
with cameras. Drag, pan or zoom after selecting a camera to continue in **Orbit**
|
|
24
|
+
from that view.
|
|
25
|
+
Hover over a camera in the scene tree and click its camera action to apply it
|
|
26
|
+
directly. **Fit to model** in the bottom toolbar (or **F**) returns to Orbit
|
|
27
|
+
and frames the model.
|
|
28
|
+
Reloading the current model restores your saved camera selection without
|
|
29
|
+
showing the prompt again.
|
|
30
|
+
|
|
31
|
+
Picking an object in the viewport reveals it in the scene tree and scrolls it
|
|
32
|
+
into view. Material rows start collapsed; expand a mesh to see its materials.
|
|
33
|
+
|
|
34
|
+
## Sharing viewer settings
|
|
2
35
|
|
|
3
36
|
Add settings to a viewer link to override the recipient's saved preferences.
|
|
4
37
|
For example, open the viewer with HDR output enabled:
|
|
@@ -17,7 +50,7 @@ The viewer updates the URL as lighting, render and display settings change.
|
|
|
17
50
|
Copy the address bar to share those settings and the selected example model.
|
|
18
51
|
Settings also work in the hash, such as `#model=dragon&hdrOutputEnabled=true`.
|
|
19
52
|
|
|
20
|
-
|
|
53
|
+
### Options
|
|
21
54
|
|
|
22
55
|
Parameter names match the viewer settings and are case-sensitive:
|
|
23
56
|
|
|
@@ -42,7 +75,7 @@ can override a recipient's different preference. When the viewer updates the
|
|
|
42
75
|
address, settings move into the hash; unrelated query parameters, including
|
|
43
76
|
`?webgl`, are preserved.
|
|
44
77
|
|
|
45
|
-
|
|
78
|
+
### Caveats
|
|
46
79
|
|
|
47
80
|
HDR output requires WebGPU, an HDR display and a compatible browser. Unsupported
|
|
48
81
|
devices fall back to SDR. `?webgl` forces WebGL 2, which does not support HDR output.
|
package/lib/oidn.d.ts
CHANGED
|
@@ -40,6 +40,6 @@ export declare const DEFAULT_OIDN_WEIGHTS_PACKAGE_BASE_URL = "https://cdn.jsdeli
|
|
|
40
40
|
* Fallback for bundled standard/small weights when application assets fail.
|
|
41
41
|
* Defaults to jsDelivr's `@meimu/mutracer@VERSION/oidn/weights/` directory.
|
|
42
42
|
*/
|
|
43
|
-
export declare const DEFAULT_OIDN_WEIGHTS_BASE_URL = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.1.
|
|
43
|
+
export declare const DEFAULT_OIDN_WEIGHTS_BASE_URL = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.1.5/oidn/weights/";
|
|
44
44
|
export declare function resolveOIDNModelUrl(model: OIDNModel, weightsBaseUrl?: string | URL): string;
|
|
45
45
|
export declare function resolveOIDNAuxiliaryModelUrls(weightsBaseUrl?: string | URL): OIDNAuxiliaryModelUrls;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const standardWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.1.
|
|
2
|
-
export declare const smallWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.1.
|
|
1
|
+
export declare const standardWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.1.5/oidn/weights/rt_hdr_alb_nrm.tza";
|
|
2
|
+
export declare const smallWeightsUrl = "https://cdn.jsdelivr.net/npm/@meimu/mutracer@0.1.5/oidn/weights/rt_hdr_alb_nrm_small.tza";
|
|
@@ -282,10 +282,10 @@ ${scratchWGSLFunctions(this._reserveCapacity ? this._regionNames : inputs.filter
|
|
|
282
282
|
${this._fsDefine ?? ''}
|
|
283
283
|
@fragment
|
|
284
284
|
fn main(
|
|
285
|
-
@builtin(position)
|
|
285
|
+
@builtin(position) fH: vec4f
|
|
286
286
|
) -> pd {
|
|
287
|
-
let uv = vec2i(floor(
|
|
288
|
-
let uv2 =
|
|
287
|
+
let uv = vec2i(floor(fH.xy));
|
|
288
|
+
let uv2 = fH.xy / viewportSize;
|
|
289
289
|
var output: pd;
|
|
290
290
|
${this._fsMain}
|
|
291
291
|
return output;
|
|
@@ -55,13 +55,13 @@ if (id.x >= size.x || id.y >= size.y) { return; }
|
|
|
55
55
|
let center = rawGuide[id.x + id.y * size.x];
|
|
56
56
|
var lu = 0.0;
|
|
57
57
|
var jc = 0.0;
|
|
58
|
-
var
|
|
58
|
+
var mY = 0.0;
|
|
59
59
|
var iX = 0.0;
|
|
60
60
|
for (var dy = -1; dy <= 1; dy++) {
|
|
61
61
|
for (var dx = -1; dx <= 1; dx++) {
|
|
62
62
|
let q = clamp(vec2i(id.xy) + vec2i(dx, dy), vec2i(0), vec2i(size) - 1);
|
|
63
63
|
let value = rawGuide[u32(q.x) + u32(q.y) * size.x];
|
|
64
|
-
|
|
64
|
+
mY += value.x;
|
|
65
65
|
iX += value.x * value.x;
|
|
66
66
|
if (value.y >= 0.0) {
|
|
67
67
|
lu += value.y;
|
|
@@ -73,7 +73,7 @@ var variance: f32;
|
|
|
73
73
|
if (center.y >= 0.0) {
|
|
74
74
|
variance = lu / jc;
|
|
75
75
|
} else {
|
|
76
|
-
let lt =
|
|
76
|
+
let lt = mY / 9.0;
|
|
77
77
|
variance = max(iX / 9.0 - lt * lt, 0.0) * 9.0 / 8.0;
|
|
78
78
|
}
|
|
79
79
|
guide[id.x + id.y * size.x] = vec2f(center.x, variance);
|
|
@@ -122,19 +122,19 @@ const INV_NORMAL_BANDWIDTH2 = ${(1 / normalBandwidth ** 2).toFixed(6)};
|
|
|
122
122
|
|
|
123
123
|
const CENTER_WEIGHT_MIN = 0.01;
|
|
124
124
|
|
|
125
|
-
fn
|
|
125
|
+
fn hg(p: vec2i) -> u32 {
|
|
126
126
|
let q = clamp(p, vec2i(0), vec2i(params.size) - 1);
|
|
127
127
|
return u32(q.x) + u32(q.y) * params.size.x;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
fn
|
|
130
|
+
fn lw(q: vec2i, bs: vec4f, gT: vec3f) -> f32 {
|
|
131
131
|
let albedo = textureLoad(albedoTex, q, 0);
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
let pf = max((albedo.rgb + bs.rgb) * 0.5, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
135
135
|
let ld = (albedo.rgb - bs.rgb) / pf;
|
|
136
136
|
let iU = albedo.a - bs.a;
|
|
137
|
-
let lp = textureLoad(normalTex, q, 0).rgb -
|
|
137
|
+
let lp = textureLoad(normalTex, q, 0).rgb - gT;
|
|
138
138
|
return max(
|
|
139
139
|
dot(ld, ld) * INV_ALBEDO_BANDWIDTH2
|
|
140
140
|
+ iU * iU * INV_COVERAGE_BANDWIDTH2,
|
|
@@ -153,12 +153,12 @@ let p = vec2i(id.xy);
|
|
|
153
153
|
if (p.x >= size.x || p.y >= size.y) { return; }
|
|
154
154
|
let step = i32(params.dilation);
|
|
155
155
|
let bs = textureLoad(albedoTex, p, 0);
|
|
156
|
-
let
|
|
157
|
-
let
|
|
158
|
-
let index =
|
|
156
|
+
let fD = textureLoad(normalTex, p, 0);
|
|
157
|
+
let gT = fD.rgb;
|
|
158
|
+
let index = hg(p);
|
|
159
159
|
|
|
160
160
|
|
|
161
|
-
if (
|
|
161
|
+
if (fD.a <= 0.0 && textureLoad(shadowCatcherTex, p, 0).r <= 0.0) {
|
|
162
162
|
outColor[index] = color[index];
|
|
163
163
|
outGuide[index] = guide[index];
|
|
164
164
|
return;
|
|
@@ -168,20 +168,20 @@ var lf: array<vec2f, PATCH_SIZE>;
|
|
|
168
168
|
var k = 0;
|
|
169
169
|
for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
|
|
170
170
|
for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
|
|
171
|
-
lf[k] = guide[
|
|
171
|
+
lf[k] = guide[hg(p + vec2i(dx, dy) * step)];
|
|
172
172
|
k++;
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
let k2 = params.colorSensitivity * params.colorSensitivity;
|
|
176
176
|
|
|
177
177
|
var sum = vec4f(0.0);
|
|
178
|
-
let
|
|
179
|
-
var
|
|
180
|
-
var
|
|
178
|
+
let gW = max(bs.rgb, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
179
|
+
var mp = vec3f(0.0);
|
|
180
|
+
var gy = vec3f(0.0);
|
|
181
181
|
var hs = vec3f(0.0);
|
|
182
182
|
var ps = 0.0;
|
|
183
|
-
var
|
|
184
|
-
var
|
|
183
|
+
var gA = 0.0;
|
|
184
|
+
var nU = 0.0;
|
|
185
185
|
var kM = 0.0;
|
|
186
186
|
for (var sy = -SEARCH_RADIUS; sy <= SEARCH_RADIUS; sy++) {
|
|
187
187
|
for (var sx = -SEARCH_RADIUS; sx <= SEARCH_RADIUS; sx++) {
|
|
@@ -191,38 +191,38 @@ if (
|
|
|
191
191
|
q.x < 0 || q.y < 0 || q.x >= size.x || q.y >= size.y
|
|
192
192
|
) { continue; }
|
|
193
193
|
|
|
194
|
-
let features =
|
|
194
|
+
let features = lw(q, bs, gT);
|
|
195
195
|
if (features > 16.0) { continue; }
|
|
196
196
|
|
|
197
|
-
var
|
|
197
|
+
var fY = 0.0;
|
|
198
198
|
k = 0;
|
|
199
199
|
for (var dy = -PATCH_RADIUS; dy <= PATCH_RADIUS; dy++) {
|
|
200
200
|
for (var dx = -PATCH_RADIUS; dx <= PATCH_RADIUS; dx++) {
|
|
201
201
|
let a = lf[k];
|
|
202
|
-
let b = guide[
|
|
202
|
+
let b = guide[hg(q + vec2i(dx, dy) * step)];
|
|
203
203
|
let qU = a.x - b.x;
|
|
204
|
-
|
|
204
|
+
fY += (qU * qU
|
|
205
205
|
- VARIANCE_CANCELLATION * (a.y + min(a.y, b.y)))
|
|
206
206
|
/ (1e-10 + k2 * (a.y + b.y));
|
|
207
207
|
k++;
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
-
|
|
210
|
+
fY /= f32(PATCH_SIZE);
|
|
211
211
|
|
|
212
|
-
let weight = exp(-max(max(
|
|
213
|
-
let index =
|
|
212
|
+
let weight = exp(-max(max(fY, 0.0), features));
|
|
213
|
+
let index = hg(q);
|
|
214
214
|
let c = color[index];
|
|
215
215
|
let g = guide[index];
|
|
216
216
|
|
|
217
|
-
let a = (textureLoad(albedoTex, q, 0).rgb - bs.rgb) /
|
|
217
|
+
let a = (textureLoad(albedoTex, q, 0).rgb - bs.rgb) / gW;
|
|
218
218
|
let value = premultiplied(c);
|
|
219
219
|
sum += value * weight;
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
mp += a * weight;
|
|
221
|
+
gy += a * a * weight;
|
|
222
222
|
hs += a * value.rgb * weight;
|
|
223
223
|
ps += g.x * weight;
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
gA += g.y * weight * weight;
|
|
225
|
+
nU += weight;
|
|
226
226
|
kM = max(kM, weight);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -232,20 +232,20 @@ kM = max(kM, weight);
|
|
|
232
232
|
let center = color[index];
|
|
233
233
|
let le = guide[index];
|
|
234
234
|
let dG = max(kM, CENTER_WEIGHT_MIN);
|
|
235
|
-
let totalWeight =
|
|
235
|
+
let totalWeight = nU + dG;
|
|
236
236
|
let tM = premultiplied(center);
|
|
237
237
|
let mean = (sum + tM * dG) / totalWeight;
|
|
238
238
|
|
|
239
239
|
|
|
240
|
-
let ez =
|
|
241
|
-
let
|
|
240
|
+
let ez = mp / totalWeight;
|
|
241
|
+
let lA = max(gy / totalWeight - ez * ez, vec3f(0.0));
|
|
242
242
|
let qu = hs / totalWeight - ez * mean.rgb;
|
|
243
243
|
|
|
244
244
|
|
|
245
245
|
|
|
246
|
-
let qE = bs.rgb + ez *
|
|
247
|
-
let
|
|
248
|
-
let vB = clamp(qu / (
|
|
246
|
+
let qE = bs.rgb + ez * gW;
|
|
247
|
+
let oz = mean.rgb * gW / max(qE, vec3f(${JNLM_ALBEDO_FLOOR}));
|
|
248
|
+
let vB = clamp(qu / (lA + vec3f(${JNLM_ALBEDO_REGULARIZATION})), vec3f(0.0), oz);
|
|
249
249
|
let rD = mean.rgb - vB * ez;
|
|
250
250
|
let filtered = vec4f(max(rD, vec3f(0.0)), max(mean.a, 0.0));
|
|
251
251
|
let rgb = select(
|
|
@@ -256,7 +256,7 @@ filtered.a > 1e-6
|
|
|
256
256
|
outColor[index] = vec4f(rgb, filtered.a);
|
|
257
257
|
outGuide[index] = vec2f(
|
|
258
258
|
(ps + le.x * dG) / totalWeight,
|
|
259
|
-
(
|
|
259
|
+
(gA + le.y * dG * dG)
|
|
260
260
|
/ (totalWeight * totalWeight)
|
|
261
261
|
);
|
|
262
262
|
}
|
|
@@ -23,10 +23,10 @@ ${layers ? `@location(0) foreground: vec4f,
|
|
|
23
23
|
@location(2) albedo: vec4f${catcher ? ',\n @location(3) shadowCatcher: vec4f' : ''}`}
|
|
24
24
|
}
|
|
25
25
|
@fragment
|
|
26
|
-
fn main(@builtin(position)
|
|
26
|
+
fn main(@builtin(position) fH: vec4f) -> pd {
|
|
27
27
|
let size = vec2u(u32(outputWidth), u32(outputHeight));
|
|
28
|
-
let
|
|
29
|
-
var idx =
|
|
28
|
+
let fQ = vec2u(u32(fH.x), size.y - u32(fH.y) - 1u);
|
|
29
|
+
var idx = fQ.x + fQ.y * size.x;
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
|
|
@@ -34,7 +34,7 @@ var idx = fP.x + fP.y * size.x;
|
|
|
34
34
|
if (sampleCount < 1.0 && normalBuffer[idx].a <= 0.0) {
|
|
35
35
|
let vc = max(sampleTileGrid, vec2u(1u));
|
|
36
36
|
let uM = min(
|
|
37
|
-
((
|
|
37
|
+
((fQ + vc / 2u) / vc) * vc,
|
|
38
38
|
((size - vec2u(1u)) / vc) * vc
|
|
39
39
|
);
|
|
40
40
|
let sH = uM.x + uM.y * size.x;
|
|
@@ -1916,6 +1916,9 @@ ${rayTraceCompute({
|
|
|
1916
1916
|
// Retain the atlas uniform capacity when a stage/material is removed.
|
|
1917
1917
|
// Shrinking the array would rebuild every pipeline again on the next edit.
|
|
1918
1918
|
const NUM_MAPS = Math.max(Math.ceil(+materialData.defines.NUM_MAPS / 10) * 10, Number(this._constants.NUM_MAPS ?? 0), 20);
|
|
1919
|
+
// Either layer's map requires independent normals, including a smooth
|
|
1920
|
+
// coat over a mapped base. Unmapped materials retain the shared path.
|
|
1921
|
+
const USE_COAT_NORMAL_FRAMES = materials.some(m => m.coatWeight > 0 && (!!m.normalMap || !!m.coatNormalMap));
|
|
1919
1922
|
Object.assign(this._constants, {
|
|
1920
1923
|
// Match the atlas UV selector. Keep the second set when any texture
|
|
1921
1924
|
// needs it; material/texture edits already rebuild these constants.
|
|
@@ -1924,9 +1927,8 @@ ${rayTraceCompute({
|
|
|
1924
1927
|
// triangle UV differentials rather than this vertex tangent.
|
|
1925
1928
|
USE_TANGENT: mergedGeometry.tangent != null &&
|
|
1926
1929
|
materials.some(material => material.specularAnisotropy > 0 || material.coatAnisotropy > 0 || (!!material.coatNormalMap && material.coatWeight > 0)),
|
|
1927
|
-
USE_COAT_NORMAL_FRAMES
|
|
1928
|
-
USE_ANISOTROPY_DIRECTIONS: materials.some(m => (!!m.
|
|
1929
|
-
m.specularAnisotropy > 0 && (m.specularAnisotropyModel === 'gltf' || !!m.anisotropyMap || m.specularAnisotropyRotation !== 0) ||
|
|
1930
|
+
USE_COAT_NORMAL_FRAMES,
|
|
1931
|
+
USE_ANISOTROPY_DIRECTIONS: USE_COAT_NORMAL_FRAMES || materials.some(m => m.specularAnisotropy > 0 && (m.specularAnisotropyModel === 'gltf' || !!m.anisotropyMap || m.specularAnisotropyRotation !== 0) ||
|
|
1930
1932
|
m.coatAnisotropy > 0 && m.coatAnisotropyRotation !== 0),
|
|
1931
1933
|
HAS_MEDIUM,
|
|
1932
1934
|
HAS_SHADOW_CATCHER: this._hasShadowCatcher,
|