@call-me-sensei/toonlab 0.4.24 → 0.5.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/NPM-LIBRARY.md +7 -6
- package/README.md +4 -4
- package/agents/PROMPTS.md +1 -1
- package/agents/skills/claude/toon-shading/SKILL.md +1 -1
- package/agents/skills/codex/toon-shading/SKILL.md +1 -1
- package/package.json +4 -2
- package/src/character/modelLoader.js +42 -1
- package/src/core/materialRoles.js +40 -5
- package/src/environment/environmentMaterialAdapter.js +3 -3
- package/src/post/postProcessing.js +12 -0
- package/src/shaders-tsl/character/castShadows.js +147 -0
- package/src/shaders-tsl/character/characterMaterial.js +764 -0
- package/src/shaders-tsl/character/characterState.js +90 -0
- package/src/shaders-tsl/character/debugViews.js +34 -0
- package/src/shaders-tsl/character/displayColor.js +71 -0
- package/src/shaders-tsl/character/highlightsRim.js +123 -0
- package/src/shaders-tsl/character/paintedDetails.js +86 -0
- package/src/shaders-tsl/character/sceneLights.js +229 -0
- package/src/shaders-tsl/character/surfaceLight.js +148 -0
- package/src/shaders-tsl/chunks/character-roles.js +10 -3
- package/src/shaders-tsl/chunks/environment-lighting.js +2 -2
- package/src/shaders-tsl/chunks/pass-depth-color.js +11 -2
- package/src/shaders-tsl/environment.js +2 -2
- package/src/shaders-tsl/flower.js +14 -2
- package/src/shaders-tsl/post-composite.js +14 -4
- package/src/styles/neutralStylePresets.js +12 -42
- package/src/toon/alphaCoverage.js +82 -0
- package/src/toon/autoRoles.js +589 -0
- package/src/toon/bakeAttribute.js +86 -0
- package/src/toon/characterParameters.js +269 -0
- package/src/toon/characterRenderPasses.js +430 -549
- package/src/toon/faceShadowBake.js +547 -0
- package/src/toon/featureBakes.js +353 -0
- package/src/toon/headBone.js +139 -0
- package/src/toon/occlusionBake.js +236 -0
- package/src/toon/settings/alphaSettings.js +68 -7
- package/src/toon/settings/autoRolesSettings.js +24 -0
- package/src/toon/settings/baseTextureSettings.js +21 -3
- package/src/toon/settings/faceSettings.js +56 -0
- package/src/toon/settings/fieldSchema.js +324 -0
- package/src/toon/settings/furSettings.js +1 -1
- package/src/toon/settings/highlightSettings.js +67 -0
- package/src/toon/settings/lightSettings.js +44 -0
- package/src/toon/settings/mapsSettings.js +132 -0
- package/src/toon/settings/outlineSettings.js +61 -254
- package/src/toon/settings/rampSettings.js +38 -0
- package/src/toon/settings/rimSettings.js +46 -0
- package/src/toon/settings/shadingSettings.js +42 -0
- package/src/toon/settings/shadowSettings.js +54 -0
- package/src/toon/skinEvidence.js +102 -0
- package/src/toon/sourceShading.js +176 -0
- package/src/toon/texturePixels.js +196 -0
- package/src/toon/toonMaterialAdapter.js +992 -1697
- package/src/toon/toonSettings.js +345 -923
- package/src/version.js +1 -1
- package/types/cloud/noise/weatherMap.d.ts +1 -1
- package/types/index.d.ts +18 -61
- package/types/post/postGenerator.d.ts +1 -0
- package/types/shaders-tsl/character/castShadows.d.ts +29 -0
- package/types/shaders-tsl/character/characterMaterial.d.ts +61 -0
- package/types/shaders-tsl/character/characterState.d.ts +27 -0
- package/types/shaders-tsl/character/debugViews.d.ts +6 -0
- package/types/shaders-tsl/character/displayColor.d.ts +13 -0
- package/types/shaders-tsl/character/highlightsRim.d.ts +43 -0
- package/types/shaders-tsl/character/paintedDetails.d.ts +20 -0
- package/types/shaders-tsl/character/sceneLights.d.ts +67 -0
- package/types/shaders-tsl/character/surfaceLight.d.ts +28 -0
- package/types/shaders-tsl/chunks/character-roles.d.ts +3 -2
- package/types/shaders-tsl/chunks/pass-depth-color.d.ts +3 -1
- package/types/shaders-tsl/post-composite.d.ts +0 -4
- package/types/styles/neutralStylePresets.d.ts +22 -415
- package/types/toon/alphaCoverage.d.ts +28 -0
- package/types/toon/autoRoles.d.ts +60 -0
- package/types/toon/bakeAttribute.d.ts +18 -0
- package/types/toon/characterParameters.d.ts +103 -0
- package/types/toon/characterRenderPasses.d.ts +45 -3
- package/types/toon/faceShadowBake.d.ts +31 -0
- package/types/toon/featureBakes.d.ts +20 -0
- package/types/toon/headBone.d.ts +34 -0
- package/types/toon/occlusionBake.d.ts +18 -0
- package/types/toon/settings/alphaSettings.d.ts +29 -3
- package/types/toon/settings/autoRolesSettings.d.ts +12 -0
- package/types/toon/settings/faceSettings.d.ts +43 -0
- package/types/toon/settings/fieldSchema.d.ts +101 -0
- package/types/toon/settings/highlightSettings.d.ts +77 -0
- package/types/toon/settings/lightSettings.d.ts +30 -0
- package/types/toon/settings/mapsSettings.d.ts +62 -0
- package/types/toon/settings/outlineSettings.d.ts +70 -124
- package/types/toon/settings/rampSettings.d.ts +26 -0
- package/types/toon/settings/rimSettings.d.ts +34 -0
- package/types/toon/settings/shadingSettings.d.ts +30 -0
- package/types/toon/settings/shadowSettings.d.ts +37 -0
- package/types/toon/skinEvidence.d.ts +14 -0
- package/types/toon/sourceShading.d.ts +36 -0
- package/types/toon/texturePixels.d.ts +25 -0
- package/types/toon/toonMaterialAdapter.d.ts +103 -855
- package/types/toon/toonSettings.d.ts +193 -1101
- package/types/version.d.ts +1 -1
- package/src/shaders-tsl/anime.js +0 -970
- package/src/shaders-tsl/chunks/character-color.js +0 -64
- package/src/shaders-tsl/chunks/character-highlights.js +0 -174
- package/src/shaders-tsl/chunks/character-lighting.js +0 -309
- package/src/shaders-tsl/chunks/character-material-maps.js +0 -146
- package/src/shaders-tsl/chunks/character-scene-lights.js +0 -270
- package/src/shaders-tsl/chunks/character-shadow-color.js +0 -61
- package/src/toon/settings/averageShadowSettings.js +0 -181
- package/src/toon/settings/celShadeSettings.js +0 -96
- package/src/toon/settings/contactShadowSettings.js +0 -114
- package/src/toon/settings/eyeHighlightSettings.js +0 -187
- package/src/toon/settings/faceLightingSettings.js +0 -135
- package/src/toon/settings/glitterSettings.js +0 -102
- package/src/toon/settings/hairHighlightSettings.js +0 -325
- package/src/toon/settings/indirectLightSettings.js +0 -244
- package/src/toon/settings/localLightSettings.js +0 -176
- package/src/toon/settings/materialMapSettings.js +0 -299
- package/src/toon/settings/perspectiveRemovalSettings.js +0 -60
- package/src/toon/settings/rimLightSettings.js +0 -268
- package/src/toon/settings/sceneShadowSettings.js +0 -147
- package/src/toon/settings/selfShadowSettings.js +0 -221
- package/src/toon/settings/shadowColorSettings.js +0 -238
- package/src/toon/settings/skinToneSettings.js +0 -150
- package/src/toon/settings/specularSettings.js +0 -314
- package/types/shaders-tsl/anime.d.ts +0 -9
- package/types/shaders-tsl/chunks/character-color.d.ts +0 -6
- package/types/shaders-tsl/chunks/character-highlights.d.ts +0 -12
- package/types/shaders-tsl/chunks/character-lighting.d.ts +0 -20
- package/types/shaders-tsl/chunks/character-material-maps.d.ts +0 -18
- package/types/shaders-tsl/chunks/character-scene-lights.d.ts +0 -48
- package/types/shaders-tsl/chunks/character-shadow-color.d.ts +0 -5
- package/types/toon/settings/averageShadowSettings.d.ts +0 -39
- package/types/toon/settings/celShadeSettings.d.ts +0 -37
- package/types/toon/settings/contactShadowSettings.d.ts +0 -30
- package/types/toon/settings/eyeHighlightSettings.d.ts +0 -55
- package/types/toon/settings/faceLightingSettings.d.ts +0 -32
- package/types/toon/settings/glitterSettings.d.ts +0 -43
- package/types/toon/settings/hairHighlightSettings.d.ts +0 -89
- package/types/toon/settings/indirectLightSettings.d.ts +0 -43
- package/types/toon/settings/localLightSettings.d.ts +0 -46
- package/types/toon/settings/materialMapSettings.d.ts +0 -86
- package/types/toon/settings/perspectiveRemovalSettings.d.ts +0 -14
- package/types/toon/settings/rimLightSettings.d.ts +0 -79
- package/types/toon/settings/sceneShadowSettings.d.ts +0 -32
- package/types/toon/settings/selfShadowSettings.d.ts +0 -44
- package/types/toon/settings/shadowColorSettings.d.ts +0 -77
- package/types/toon/settings/skinToneSettings.d.ts +0 -30
- package/types/toon/settings/specularSettings.d.ts +0 -96
package/NPM-LIBRARY.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ToonLab npm library guide
|
|
2
2
|
|
|
3
3
|
This guide is included in `@call-me-sensei/toonlab`. It is the package-first
|
|
4
|
-
reference for version 0.
|
|
4
|
+
reference for version 0.5.0 and does not require access to the source
|
|
5
5
|
repository.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
@@ -89,9 +89,10 @@ import {
|
|
|
89
89
|
} from '@call-me-sensei/toonlab/toon';
|
|
90
90
|
|
|
91
91
|
const settings = createToonSettings({
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
preset: 'call_me_sensei',
|
|
93
|
+
rim: { intensity: { hair: 0.35 }, mode: 'depth' },
|
|
94
|
+
outline: { width: { cloth: 0.006 } },
|
|
95
|
+
ramp: { tone: { skin: [0.93, 0.74, 0.68] } },
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
applyToonShader(characterRoot, { settings });
|
|
@@ -142,7 +143,7 @@ surface detail, not displacement that replaces a geometric high-to-low bake.
|
|
|
142
143
|
|
|
143
144
|
## Load Nature Reference Rocks
|
|
144
145
|
|
|
145
|
-
Version 0.
|
|
146
|
+
Version 0.5.0 understands both the original `rock-0001`–`rock-0480`
|
|
146
147
|
identities and the Nature Reference Rocks catalog. Acquiring an asset
|
|
147
148
|
directly returns its realistic PBR GLB. The one-call placement path additionally
|
|
148
149
|
loads that asset's reviewed geology maps and `call_me_sensei` material settings
|
|
@@ -228,7 +229,7 @@ it uses the disk workspace passed through `--workspace`; no account is needed.
|
|
|
228
229
|
"command": "npx",
|
|
229
230
|
"args": [
|
|
230
231
|
"-y",
|
|
231
|
-
"--package=@call-me-sensei/toonlab@0.
|
|
232
|
+
"--package=@call-me-sensei/toonlab@0.5.0",
|
|
232
233
|
"toonlab-mcp",
|
|
233
234
|
"--workspace",
|
|
234
235
|
"/absolute/path/to/your-game/.toonlab"
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Use ToonLab as a focused runtime library (`@call-me-sensei/toonlab` on npm), as
|
|
|
19
19
|
an asset/preset authoring workspace, or as an asset-discovery service—not as a
|
|
20
20
|
one-shot world generator.
|
|
21
21
|
|
|
22
|
-
## Versioned expectation: 0.
|
|
22
|
+
## Versioned expectation: 0.5.0
|
|
23
23
|
|
|
24
24
|
For a correctly constructed and semantically labeled scene, one strict Call Me
|
|
25
25
|
Sensei bundle application is expected to establish the supported visual
|
|
@@ -376,7 +376,7 @@ camera behavior, and game feel remain host-owned or pre-beta.
|
|
|
376
376
|
| Cluster | Import | What you get |
|
|
377
377
|
|---|---|---|
|
|
378
378
|
| Styles and bundles | `@call-me-sensei/toonlab/styles` | Local, versioned style-bundle documents that coordinate domain profiles without storing asset identity or current scene state. Create, validate, serialize, parse, and resolve JSON with no account or database; hosts currently route explicitly labeled assets through each owning runtime. [Contract](https://github.com/call-me-sensei-app/toonlab/blob/main/docs/styles-and-bundles.md) |
|
|
379
|
-
| Toon character shading | `@call-me-sensei/toonlab/toon` |
|
|
379
|
+
| Toon character shading | `@call-me-sensei/toonlab/toon` | Anime-game character shader: flat lit colour, per-surface shadow tones with a warm band at the terminator, face maps baked automatically from the face, a nose shadow, eye-white shade and stocking sheen derived from the model, environment-aware light (sun, sky, cast shade), scenery, character and hair-on-face shadows, depth rim, hair ring and masked specular, ink outlines coloured from the surface, source map routing (normal/AO/emissive/MatCap/detail), stickers, shell fur, dither fades — 14 settings groups, all preset-serializable. [Docs](https://github.com/call-me-sensei-app/toonlab/blob/main/docs/toon-shading.md) |
|
|
380
380
|
| Environment shading | `@call-me-sensei/toonlab/environment` | Modern anime-style scene shader for texture packs, standard glTF, and untextured scenes: material-role classification, wrapped lighting, packed-map hints, window cutouts, sun/lamp rigs, time-of-day, six-direction ambient probe, planar floor reflections, BVH vertex-AO baking, height fog, cloud shadows. [Docs](https://github.com/call-me-sensei-app/toonlab/blob/main/docs/environment.md) |
|
|
381
381
|
| Water | `@call-me-sensei/toonlab/water` | Focused water treatment for a host-authored water footprint, continuous shore, and closed seabed: Gerstner waves, absorption color, refraction/caustics/foam, ripples, splashes, wakes, kelp, underwater treatment, and CPU buoyancy sampling. It does not design the coast or underwater habitat. [Docs](https://github.com/call-me-sensei-app/toonlab/blob/main/docs/water.md) |
|
|
382
382
|
| Vegetation | `@call-me-sensei/toonlab/vegetation` | Tree/grass/flower construction and shader runtimes, including the focused procedural broadleaf `BranchTree` with deterministic branching, eight leaf silhouettes, caller-supplied leaf/bark textures, and a portable recipe. No authored tree asset collection is bundled or exported: reviewed tree recipes remain searchable Gallery assets delivered through MCP with their CC0 metadata. Package-generated trees preserve authored bark first and otherwise select a registered deterministic bark surface instead of a bare trunk. The experimental species roster remains repository-only. [Docs](https://github.com/call-me-sensei-app/toonlab/blob/main/docs/vegetation-sky.md) |
|
|
@@ -583,8 +583,8 @@ import { applyToonShader, createToonSettings } from '@call-me-sensei/toonlab/too
|
|
|
583
583
|
|
|
584
584
|
const settings = createToonSettings({
|
|
585
585
|
preset: 'default',
|
|
586
|
-
|
|
587
|
-
|
|
586
|
+
ramp: {
|
|
587
|
+
tone: { skin: [0.94, 0.82, 0.76] },
|
|
588
588
|
},
|
|
589
589
|
});
|
|
590
590
|
|
package/agents/PROMPTS.md
CHANGED
|
@@ -11,7 +11,7 @@ References beginning `agents/` resolve from the installed ToonLab package root
|
|
|
11
11
|
|
|
12
12
|
Use this skill when a developer wants ToonLab character toon materials, toon
|
|
13
13
|
settings, preset documents, material-role handling, outlines, hair highlights,
|
|
14
|
-
rim light, shadows,
|
|
14
|
+
rim light, shadows, shadow tones, face maps, stickers, fur, or debug views in their app.
|
|
15
15
|
|
|
16
16
|
Public imports:
|
|
17
17
|
- `@call-me-sensei/toonlab/toon`
|
|
@@ -11,7 +11,7 @@ References beginning `agents/` resolve from the installed ToonLab package root
|
|
|
11
11
|
|
|
12
12
|
Use this skill when a developer wants ToonLab character toon materials, toon
|
|
13
13
|
settings, preset documents, material-role handling, outlines, hair highlights,
|
|
14
|
-
rim light, shadows,
|
|
14
|
+
rim light, shadows, shadow tones, face maps, stickers, fur, or debug views in their app.
|
|
15
15
|
|
|
16
16
|
Public imports:
|
|
17
17
|
- `@call-me-sensei/toonlab/toon`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@call-me-sensei/toonlab",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Anime-style game toolkit for Three.js with cel shading, vegetation, rocks, water, sky, clouds, procedural textures, and portable Lab artifacts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Hyperbond Studio PTE. LTD. (Call Me Sensei)",
|
|
@@ -340,6 +340,8 @@
|
|
|
340
340
|
"verify:grass": "node scripts/verify-grass-palettes.mjs",
|
|
341
341
|
"verify:grass-package": "node scripts/verify-packaged-grass.mjs",
|
|
342
342
|
"verify:character-package": "node scripts/verify-packaged-character.mjs",
|
|
343
|
+
"verify:toon-shading": "node scripts/verify-toon-character-shading.mjs",
|
|
344
|
+
"verify:provenance": "node scripts/verify-provenance.mjs",
|
|
343
345
|
"verify:ground-stabilizer": "node scripts/verify-ground-stabilizer.mjs",
|
|
344
346
|
"verify:locomotion-state": "node scripts/verify-locomotion-state-machine.mjs",
|
|
345
347
|
"verify:water-interaction": "node scripts/verify-water-interaction-controller.mjs",
|
|
@@ -371,7 +373,7 @@
|
|
|
371
373
|
"verify:collision-package": "node scripts/verify-packaged-world-collision.mjs",
|
|
372
374
|
"verify:official-catalog": "node scripts/verify-official-catalog-provider.mjs && node scripts/verify-official-catalog-rock-package.mjs && node scripts/verify-official-catalog-runtime.mjs && node scripts/verify-official-catalog-lod.mjs && node scripts/verify-official-catalog-placement.mjs && node scripts/verify-playground-official-catalog.mjs && node scripts/verify-packaged-official-catalog.mjs",
|
|
373
375
|
"verify:system-style": "node scripts/verify-system-style-policy.mjs",
|
|
374
|
-
"verify:release": "npm run verify:repository && npm run verify:system-style && npm run verify:style-contract && npm run verify:style-labels-package && npm run verify:collision-package && npm run verify:scene-collision && npm run verify:official-catalog && npm run verify:public-labs && npm run verify:live-labs && npm run verify:natural-rock-surfaces && npm run verify:rock-shader && npm run verify:rock-generation-lab && npm run verify:rock-lab-lifecycle && npm run verify:ground-shader && npm run verify:manufactured-materials && npm run verify:material-labeling:agent && npm run verify:material-labeling:mcp && npm run verify:water-lab && npm run verify:water && npm run verify:vegetation-labs && npm run verify:texgen && npm run verify:cloud-shader && npm run verify:sky-cloud-lab && npm run verify:world-quality && npm run verify:scatter && npm run verify:branch-tree && npm run verify:grass-package && npm run verify:character-package && npm run verify:locomotion-state && npm run verify:ground-stabilizer && npm run verify:water-interaction && npm run verify:walkable-character && npm run verify:playground-walkable && npm run verify:renderer-configuration && npm run verify:scene-scheduler && npm run verify:scene-surface && npm run verify:shared-shadow-receivers && npm run verify:scene-quality && npm run verify:quality-integration && npm run verify:lab-asset-provenance && npm run verify:api && npm run verify:types && npm run verify:mcp && npm run verify:skills && npm run verify:docs && npm run verify:local-database && npm run verify:package",
|
|
376
|
+
"verify:release": "npm run verify:repository && npm run verify:system-style && npm run verify:style-contract && npm run verify:style-labels-package && npm run verify:collision-package && npm run verify:scene-collision && npm run verify:official-catalog && npm run verify:public-labs && npm run verify:live-labs && npm run verify:natural-rock-surfaces && npm run verify:rock-shader && npm run verify:rock-generation-lab && npm run verify:rock-lab-lifecycle && npm run verify:ground-shader && npm run verify:manufactured-materials && npm run verify:material-labeling:agent && npm run verify:material-labeling:mcp && npm run verify:water-lab && npm run verify:water && npm run verify:vegetation-labs && npm run verify:texgen && npm run verify:cloud-shader && npm run verify:sky-cloud-lab && npm run verify:world-quality && npm run verify:scatter && npm run verify:branch-tree && npm run verify:grass-package && npm run verify:character-package && npm run verify:toon-shading && npm run verify:locomotion-state && npm run verify:ground-stabilizer && npm run verify:water-interaction && npm run verify:walkable-character && npm run verify:playground-walkable && npm run verify:renderer-configuration && npm run verify:scene-scheduler && npm run verify:scene-surface && npm run verify:shared-shadow-receivers && npm run verify:scene-quality && npm run verify:quality-integration && npm run verify:lab-asset-provenance && npm run verify:api && npm run verify:types && npm run verify:mcp && npm run verify:skills && npm run verify:docs && npm run verify:local-database && npm run verify:package",
|
|
375
377
|
"verify:generation": "node scripts/verify-generation.mjs",
|
|
376
378
|
"verify:post": "node scripts/verify-post.mjs",
|
|
377
379
|
"verify:camera": "node scripts/verify-camera.mjs",
|
|
@@ -5,6 +5,7 @@ import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader.js';
|
|
|
5
5
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
6
6
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
7
7
|
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
|
|
8
|
+
import { TGALoader } from 'three/examples/jsm/loaders/TGALoader.js';
|
|
8
9
|
import { USDZLoader } from 'three/examples/jsm/loaders/USDZLoader.js';
|
|
9
10
|
import { unzipSync } from 'three/examples/jsm/libs/fflate.module.js';
|
|
10
11
|
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
@@ -248,6 +249,9 @@ function createModelLoadingManager() {
|
|
|
248
249
|
manager.setURLModifier((url) => {
|
|
249
250
|
return resolveKnownModelAssetUrl(url) ?? url;
|
|
250
251
|
});
|
|
252
|
+
// FBX and OBJ exports from Max/Maya commonly reference TGA textures, which
|
|
253
|
+
// the browser's image decoder cannot read.
|
|
254
|
+
manager.addHandler(/\.tga$/i, new TGALoader(manager));
|
|
251
255
|
|
|
252
256
|
return manager;
|
|
253
257
|
}
|
|
@@ -331,7 +335,20 @@ function configureGltfLoader(loader, {
|
|
|
331
335
|
}
|
|
332
336
|
}
|
|
333
337
|
|
|
338
|
+
// Records the source format on every material so conversion can apply the
|
|
339
|
+
// format's colour semantics (glTF records more detail itself).
|
|
340
|
+
function tagMaterialSourceFormat(root, format) {
|
|
341
|
+
root?.traverse?.((obj) => {
|
|
342
|
+
if (!obj.isMesh || !obj.material) return;
|
|
343
|
+
for (const material of toMaterialArray(obj.material)) {
|
|
344
|
+
if (!material || material.userData?.toonSource?.format) continue;
|
|
345
|
+
material.userData.toonSource = { ...(material.userData.toonSource || {}), format };
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
334
350
|
function createModelAsset({ clips = [], format, materialUrl = null, resourcePath, root, url, vrm = null }) {
|
|
351
|
+
tagMaterialSourceFormat(root, format);
|
|
335
352
|
return {
|
|
336
353
|
clips,
|
|
337
354
|
format,
|
|
@@ -378,6 +395,7 @@ function annotateGltfSourceMetadata(gltf, url) {
|
|
|
378
395
|
|
|
379
396
|
material.userData.toonSource = {
|
|
380
397
|
...(material.userData.toonSource || {}),
|
|
398
|
+
alphaMode: materialDef.alphaMode || 'OPAQUE',
|
|
381
399
|
baseColorTextureIndex: Number.isInteger(baseColorTextureIndex) ? baseColorTextureIndex : null,
|
|
382
400
|
format: 'gltf',
|
|
383
401
|
imageCount: json.images?.length ?? 0,
|
|
@@ -399,6 +417,24 @@ function annotateGltfSourceMetadata(gltf, url) {
|
|
|
399
417
|
}
|
|
400
418
|
}
|
|
401
419
|
|
|
420
|
+
// Records on each MMD toon ramp (material.gradientMap) its file and whether it
|
|
421
|
+
// is one of MMD's shared toon01–10 presets or a ramp the model's author
|
|
422
|
+
// shipped: only authored ramps are imported as the material's shadow tone.
|
|
423
|
+
// Wraps three-stdlib's material builder; without it ramps simply stay
|
|
424
|
+
// unimported.
|
|
425
|
+
function tagMmdToonTextures(loader) {
|
|
426
|
+
const materialBuilder = loader.meshBuilder?.materialBuilder;
|
|
427
|
+
const loadTexture = materialBuilder?._loadTexture;
|
|
428
|
+
if (typeof loadTexture !== 'function') return;
|
|
429
|
+
materialBuilder._loadTexture = function loadTaggedTexture(filePath, textures, params, ...rest) {
|
|
430
|
+
const texture = loadTexture.call(this, filePath, textures, params, ...rest);
|
|
431
|
+
if (params?.isToonTexture && texture?.isTexture) {
|
|
432
|
+
texture.userData.mmdToon = { file: String(filePath ?? ''), shared: params.isDefaultToonTexture === true };
|
|
433
|
+
}
|
|
434
|
+
return texture;
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
402
438
|
export async function loadModelAsset(url, {
|
|
403
439
|
decoderBasePath = null,
|
|
404
440
|
materialUrl = null,
|
|
@@ -413,6 +449,7 @@ export async function loadModelAsset(url, {
|
|
|
413
449
|
const { MMDLoader } = await loadMmdSupport();
|
|
414
450
|
const loader = new MMDLoader(manager);
|
|
415
451
|
loader.setResourcePath(resourcePath);
|
|
452
|
+
tagMmdToonTextures(loader);
|
|
416
453
|
const root = await loadAsync(loader, url);
|
|
417
454
|
|
|
418
455
|
return createModelAsset({
|
|
@@ -453,8 +490,12 @@ export async function loadModelAsset(url, {
|
|
|
453
490
|
|
|
454
491
|
const vrm = gltf.userData?.vrm ?? null;
|
|
455
492
|
if (vrm) {
|
|
456
|
-
// VRM0 models face +Z after this, matching VRM1/three convention.
|
|
493
|
+
// VRM0 models face +Z after this, matching VRM1/three convention. The
|
|
494
|
+
// turn is a 180° rotation on the root itself, so in the root's own frame
|
|
495
|
+
// a VRM0 character faces −Z; record that for head-frame consumers
|
|
496
|
+
// (automatic roles, the face shadow bake, head tracking).
|
|
457
497
|
vrmUtils.rotateVRM0(vrm);
|
|
498
|
+
if (vrm.meta?.metaVersion === '0') gltf.scene.userData.toonForward = [0, 0, -1];
|
|
458
499
|
// Clips animate the raw scene bones directly; without this vrm.update()
|
|
459
500
|
// would overwrite them from the untouched normalized rig every frame.
|
|
460
501
|
vrm.humanoid.autoUpdateHumanBones = false;
|
|
@@ -87,8 +87,10 @@ const FACE_TOKENS = [
|
|
|
87
87
|
'mouth',
|
|
88
88
|
'tooth',
|
|
89
89
|
'teeth',
|
|
90
|
+
'tongue',
|
|
90
91
|
'brow',
|
|
91
92
|
'lash',
|
|
93
|
+
'eyelid',
|
|
92
94
|
'颜',
|
|
93
95
|
'顏',
|
|
94
96
|
'面',
|
|
@@ -171,6 +173,36 @@ export function hasAnyToken(text, tokens) {
|
|
|
171
173
|
return tokens.some((token) => text.includes(token));
|
|
172
174
|
}
|
|
173
175
|
|
|
176
|
+
// Words that contain a role token without meaning that role. They are blanked
|
|
177
|
+
// out before that role's tokens are tested, so "armor" never reads as an arm,
|
|
178
|
+
// "headphones" never as a head, and a hair clip is an accessory, not hair.
|
|
179
|
+
const SEPARATOR = '[\\s_-]*';
|
|
180
|
+
const EYE_EXCLUSIONS = [
|
|
181
|
+
new RegExp(`eye${SEPARATOR}(brow|lash|line|liner|lid|shadow)`, 'g'),
|
|
182
|
+
];
|
|
183
|
+
const FACE_EXCLUSIONS = [
|
|
184
|
+
/surface|interface|facet/g,
|
|
185
|
+
new RegExp(`head${SEPARATOR}(phone|set|band|gear|wear|piece|dress|acc|scarf|lamp|light)`, 'g'),
|
|
186
|
+
/splash|flash/g,
|
|
187
|
+
];
|
|
188
|
+
const SKIN_EXCLUSIONS = [
|
|
189
|
+
new RegExp(`(arm|leg)${SEPARATOR}warmer`, 'g'),
|
|
190
|
+
/armou?r|charm|alarm|warm|farm|harm/g,
|
|
191
|
+
new RegExp(`arm${SEPARATOR}(band|let|guard|ring)`, 'g'),
|
|
192
|
+
/legging|legend|elegan/g,
|
|
193
|
+
/handle|handkerchief|handbag/g,
|
|
194
|
+
new RegExp(`body${SEPARATOR}suit|bodice`, 'g'),
|
|
195
|
+
];
|
|
196
|
+
const HAIR_EXCLUSIONS = [
|
|
197
|
+
/chair/g,
|
|
198
|
+
new RegExp(`hair${SEPARATOR}(pin|clip|band|tie|ornament|acc|ribbon|bow|flower|stick|comb|ring|clasp|jewel|net)`, 'g'),
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
function hasRoleToken(text, tokens, exclusions = []) {
|
|
202
|
+
const cleaned = exclusions.reduce((value, pattern) => value.replace(pattern, ' '), text);
|
|
203
|
+
return hasAnyToken(cleaned, tokens);
|
|
204
|
+
}
|
|
205
|
+
|
|
174
206
|
export function normalizeMaterialRole(value, fallback = 'default') {
|
|
175
207
|
if (Number.isFinite(value)) {
|
|
176
208
|
return MATERIAL_ROLE_NAMES_BY_VALUE[Math.round(value)] ?? fallback;
|
|
@@ -315,7 +347,10 @@ function flagsForPrimaryRole(primaryRole) {
|
|
|
315
347
|
function classifyMaterialHeuristics(mat) {
|
|
316
348
|
const text = materialText(mat);
|
|
317
349
|
const isCatchlight = hasAnyToken(text, CATCHLIGHT_TOKENS);
|
|
318
|
-
|
|
350
|
+
// "highlight" alone is ambiguous: a hair highlight overlay is not an eye.
|
|
351
|
+
const namesHairOnly = hasRoleToken(text, HAIR_TOKENS, HAIR_EXCLUSIONS) &&
|
|
352
|
+
!hasRoleToken(text, EYE_TOKENS, EYE_EXCLUSIONS);
|
|
353
|
+
const isEyeHighlight = hasAnyToken(text, EYE_HIGHLIGHT_TOKENS) && !namesHairOnly;
|
|
319
354
|
const isBlush = hasAnyToken(text, BLUSH_TOKENS);
|
|
320
355
|
const isTransparentOverlay = isEyeHighlight ||
|
|
321
356
|
isCatchlight ||
|
|
@@ -324,10 +359,10 @@ function classifyMaterialHeuristics(mat) {
|
|
|
324
359
|
const isIris = hasAnyToken(text, IRIS_TOKENS);
|
|
325
360
|
const isPupil = hasAnyToken(text, PUPIL_TOKENS);
|
|
326
361
|
const isSclera = hasAnyToken(text, SCLERA_TOKENS);
|
|
327
|
-
const isEye =
|
|
328
|
-
const isFace =
|
|
329
|
-
const isSkin =
|
|
330
|
-
const isHair =
|
|
362
|
+
const isEye = hasRoleToken(text, EYE_TOKENS, EYE_EXCLUSIONS);
|
|
363
|
+
const isFace = hasRoleToken(text, FACE_TOKENS, FACE_EXCLUSIONS);
|
|
364
|
+
const isSkin = hasRoleToken(text, SKIN_TOKENS, SKIN_EXCLUSIONS);
|
|
365
|
+
const isHair = hasRoleToken(text, HAIR_TOKENS, HAIR_EXCLUSIONS);
|
|
331
366
|
const isMetal = hasAnyToken(text, METAL_TOKENS);
|
|
332
367
|
const isCostume = hasAnyToken(text, COSTUME_TOKENS);
|
|
333
368
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { syncToonSceneLights } from '../shaders-tsl/
|
|
1
|
+
import { syncToonSceneLights } from '../shaders-tsl/character/sceneLights.js';
|
|
2
2
|
import {
|
|
3
3
|
classifyEnvironmentMaterialRole,
|
|
4
4
|
toMaterialArray,
|
|
@@ -13,12 +13,12 @@ import {
|
|
|
13
13
|
} from './manufacturedMaterialContract.js';
|
|
14
14
|
|
|
15
15
|
// Environment node materials read scene lights from the shared toon light
|
|
16
|
-
// uniforms (shaders-tsl/
|
|
16
|
+
// uniforms (shaders-tsl/character/sceneLights.js) instead of three's
|
|
17
17
|
// classic light blocks; converted meshes mirror the light state right before
|
|
18
18
|
// they render, exactly like the toon adapter's toonNodeLightSync. Both
|
|
19
19
|
// renderers invoke Object3D.onBeforeRender.
|
|
20
20
|
function environmentNodeLightSync(renderer, scene, camera) {
|
|
21
|
-
syncToonSceneLights(scene, camera);
|
|
21
|
+
syncToonSceneLights(scene, camera, renderer);
|
|
22
22
|
}
|
|
23
23
|
import {
|
|
24
24
|
applyEnvironmentSettingsToMaterial,
|
|
@@ -37,6 +37,10 @@ export const DEFAULT_POST_PROCESSING_PARAMETERS = Object.freeze({
|
|
|
37
37
|
// Defaults of 1/1 reproduce plain bloom.
|
|
38
38
|
bloomBackgroundSuppress: 1.0,
|
|
39
39
|
bloomCharacterBoost: 1.0,
|
|
40
|
+
// Saturation of bloom gathered from character pixels. Bloom is additive and
|
|
41
|
+
// pushes skin toward white; above 1 it keeps the glow the character's own
|
|
42
|
+
// hue (warm skin glows warm). 1 = unchanged.
|
|
43
|
+
bloomCharacterSaturation: 1.0,
|
|
40
44
|
// 'single' = the original one-pass 9-tap bloom. 'pyramid' = multi-pass
|
|
41
45
|
// dual-filter mip chain: wider, softer glow for roughly the same cost at
|
|
42
46
|
// high radii, at the price of extra render targets.
|
|
@@ -160,6 +164,7 @@ export const POST_PROCESSING_PRESETS = Object.freeze({
|
|
|
160
164
|
},
|
|
161
165
|
parameters: {
|
|
162
166
|
bloomCharacterBoost: 1.6,
|
|
167
|
+
bloomCharacterSaturation: 1.4,
|
|
163
168
|
bloomLevels: 5,
|
|
164
169
|
bloomMode: 'pyramid',
|
|
165
170
|
bloomRadius: 0.5,
|
|
@@ -275,6 +280,11 @@ const POST_PROCESSING_FIELD_DEFINITIONS = Object.freeze({
|
|
|
275
280
|
label: 'Bloom Character Boost',
|
|
276
281
|
range: { max: 4, min: 0, step: 0.05 },
|
|
277
282
|
},
|
|
283
|
+
bloomCharacterSaturation: {
|
|
284
|
+
description: 'Scales the saturation of bloom gathered from character pixels when a character mask is connected.',
|
|
285
|
+
label: 'Bloom Character Saturation',
|
|
286
|
+
range: { max: 3, min: 0, step: 0.05 },
|
|
287
|
+
},
|
|
278
288
|
bloomLevels: {
|
|
279
289
|
description: 'Number of mip levels in the pyramid bloom chain (pyramid mode only).',
|
|
280
290
|
label: 'Bloom Levels',
|
|
@@ -879,6 +889,7 @@ function applyCompositeSettings(material, settings, camera, depthTexture, width,
|
|
|
879
889
|
const uniforms = material.uniforms;
|
|
880
890
|
uniforms.bloomBackgroundSuppress.value = parameters.bloomBackgroundSuppress;
|
|
881
891
|
uniforms.bloomCharacterBoost.value = parameters.bloomCharacterBoost;
|
|
892
|
+
uniforms.bloomCharacterSaturation.value = parameters.bloomCharacterSaturation;
|
|
882
893
|
uniforms.bloomRadius.value = parameters.bloomRadius;
|
|
883
894
|
uniforms.bloomStrength.value = features.bloom ? parameters.bloomStrength : 0.0;
|
|
884
895
|
uniforms.bloomThreshold.value = parameters.bloomThreshold;
|
|
@@ -1028,6 +1039,7 @@ export function createPostProcessingPipeline({
|
|
|
1028
1039
|
bloomPrefilterMaterial.uniforms.tInput.value = target.texture;
|
|
1029
1040
|
bloomPrefilterMaterial.uniforms.bloomThreshold.value = settings.parameters.bloomThreshold;
|
|
1030
1041
|
bloomPrefilterMaterial.uniforms.bloomCharacterBoost.value = settings.parameters.bloomCharacterBoost;
|
|
1042
|
+
bloomPrefilterMaterial.uniforms.bloomCharacterSaturation.value = settings.parameters.bloomCharacterSaturation;
|
|
1031
1043
|
bloomPrefilterMaterial.uniforms.bloomBackgroundSuppress.value = settings.parameters.bloomBackgroundSuppress;
|
|
1032
1044
|
bloomPrefilterMaterial.uniforms.tCharacterMask.value = compositeMaterial.uniforms.tCharacterMask.value;
|
|
1033
1045
|
bloomPrefilterMaterial.uniforms.useCharacterMask.value = compositeMaterial.uniforms.useCharacterMask.value;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Cast shadows on the character (spec §5.5). Each returns a visibility
|
|
2
|
+
// (1 lit, 0 shadowed) that multiplies the lit amount — a cast shadow moves a
|
|
3
|
+
// pixel into the shadow tone, it never darkens the tone.
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
abs,
|
|
7
|
+
mix,
|
|
8
|
+
cameraFar,
|
|
9
|
+
cameraNear,
|
|
10
|
+
cameraProjectionMatrix,
|
|
11
|
+
cameraViewMatrix,
|
|
12
|
+
clamp,
|
|
13
|
+
dot,
|
|
14
|
+
float,
|
|
15
|
+
If,
|
|
16
|
+
max,
|
|
17
|
+
min,
|
|
18
|
+
orthographicDepthToViewZ,
|
|
19
|
+
perspectiveDepthToViewZ,
|
|
20
|
+
screenUV,
|
|
21
|
+
select,
|
|
22
|
+
smoothstep,
|
|
23
|
+
step,
|
|
24
|
+
vec2,
|
|
25
|
+
vec4,
|
|
26
|
+
} from 'three/tsl';
|
|
27
|
+
|
|
28
|
+
// Screen UV (top-left origin, like screenUV) of a view-space point.
|
|
29
|
+
export function viewToScreenUV(viewPosition) {
|
|
30
|
+
const clip = cameraProjectionMatrix.mul(vec4(viewPosition, 1));
|
|
31
|
+
const ndc = clip.xy.div(max(clip.w, 1e-6));
|
|
32
|
+
return vec2(ndc.x.mul(0.5).add(0.5), ndc.y.mul(-0.5).add(0.5));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Screen UV of this pixel shifted by a view-space offset at `viewPosition`. */
|
|
36
|
+
export function offsetScreenUV(viewPosition, viewOffset, baseUV = viewToScreenUV(viewPosition)) {
|
|
37
|
+
return screenUV.add(viewToScreenUV(viewPosition.add(viewOffset)).sub(baseUV));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Screen-UV change per metre of a lateral (view-plane) offset at this
|
|
42
|
+
* pixel's depth: exact for perspective and orthographic cameras.
|
|
43
|
+
*/
|
|
44
|
+
export function uvPerMetre(viewPosition) {
|
|
45
|
+
const orthographic = cameraProjectionMatrix.element(3).w.equal(1);
|
|
46
|
+
const w = select(orthographic, float(1), viewPosition.z.negate().max(1e-4));
|
|
47
|
+
return vec2(cameraProjectionMatrix.element(0).x, cameraProjectionMatrix.element(1).y.negate()).mul(0.5).div(w);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The character passes store window depth in [0, 1], plus 2 on face (and
|
|
51
|
+
// eye) surfaces so face receivers can ignore them; node materials clamp
|
|
52
|
+
// their output at 0, so the flag must stay positive.
|
|
53
|
+
export const FACE_DEPTH_OFFSET = 2;
|
|
54
|
+
|
|
55
|
+
/** `{ depth, face }` from a value stored by the character passes. */
|
|
56
|
+
export function decodeStoredDepth(stored) {
|
|
57
|
+
const face = stored.greaterThan(1.5);
|
|
58
|
+
return { depth: select(face, stored.sub(FACE_DEPTH_OFFSET), stored), face };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Window depth written by the depth prepass → distance in front of the camera. */
|
|
62
|
+
export function prepassDistance(windowDepth) {
|
|
63
|
+
const orthographic = cameraProjectionMatrix.element(3).w.equal(1);
|
|
64
|
+
const viewZ = select(
|
|
65
|
+
orthographic,
|
|
66
|
+
orthographicDepthToViewZ(windowDepth, cameraNear, cameraFar),
|
|
67
|
+
perspectiveDepthToViewZ(windowDepth, cameraNear, cameraFar),
|
|
68
|
+
);
|
|
69
|
+
return viewZ.negate();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The character's own orthographic shadow map (characterRenderPasses.js):
|
|
74
|
+
* normal-offset and slope-scaled bias, bilinear filtering, and a fade toward the
|
|
75
|
+
* edge of the map's coverage.
|
|
76
|
+
*/
|
|
77
|
+
export function characterShadowVisibility(u, state, worldPosition, geometryNormal, faceLike, gate) {
|
|
78
|
+
const visibility = float(1).toVar('toonCharacterShadow');
|
|
79
|
+
If(state.shadowReady.greaterThan(0.5).and(gate), () => {
|
|
80
|
+
// Offset along the normal side that faces the light (thin, two-sided
|
|
81
|
+
// cards such as hair are lit from either side).
|
|
82
|
+
const facingSigned = dot(geometryNormal, state.shadowDirection);
|
|
83
|
+
const towardLight = geometryNormal.mul(select(facingSigned.lessThan(0), float(-1), float(1)));
|
|
84
|
+
const facing = abs(facingSigned).clamp(0, 1);
|
|
85
|
+
const receiver = worldPosition.add(towardLight.mul(u.characterShadowNormalBias));
|
|
86
|
+
const clip = state.shadowMatrix.mul(vec4(receiver, 1));
|
|
87
|
+
const coord = clip.xyz.div(clip.w).mul(0.5).add(0.5).toVar();
|
|
88
|
+
const inside = coord.x.greaterThanEqual(0).and(coord.x.lessThanEqual(1))
|
|
89
|
+
.and(coord.y.greaterThanEqual(0)).and(coord.y.lessThanEqual(1))
|
|
90
|
+
.and(coord.z.greaterThanEqual(0)).and(coord.z.lessThanEqual(1));
|
|
91
|
+
If(inside, () => {
|
|
92
|
+
const slope = float(1).add(float(1).sub(facing).mul(3));
|
|
93
|
+
const reference = coord.z.sub(u.characterShadowDepthBias.mul(slope).div(max(state.shadowDepthRange, 1e-4)));
|
|
94
|
+
// Bilinearly weighted comparisons of the 2×2 (softness-scaled) texels
|
|
95
|
+
// around the receiver: smooth edges from four taps.
|
|
96
|
+
const grid = state.shadowMapSize.div(max(u.characterShadowSoftness, 0.25));
|
|
97
|
+
const cell = coord.xy.mul(grid).sub(0.5);
|
|
98
|
+
const base = cell.floor();
|
|
99
|
+
const blend = cell.sub(base);
|
|
100
|
+
// Faces and eyes ignore face occluders (layered lashes, brows and
|
|
101
|
+
// eye whites a few millimetres apart must not shadow each other).
|
|
102
|
+
const ignoreFace = faceLike.greaterThan(0.5);
|
|
103
|
+
const tap = (x, y) => {
|
|
104
|
+
const stored = decodeStoredDepth(state.shadowMap.sample(base.add(vec2(x, y)).add(0.5).div(grid)).level(0).x);
|
|
105
|
+
return select(stored.face.and(ignoreFace), float(1), step(reference, stored.depth));
|
|
106
|
+
};
|
|
107
|
+
const lit = mix(
|
|
108
|
+
mix(tap(0, 0), tap(1, 0), blend.x),
|
|
109
|
+
mix(tap(0, 1), tap(1, 1), blend.x),
|
|
110
|
+
blend.y,
|
|
111
|
+
);
|
|
112
|
+
const edge = max(abs(coord.x.sub(0.5)), abs(coord.y.sub(0.5))).mul(2);
|
|
113
|
+
const coverage = float(1).sub(smoothstep(0.9, 1, edge));
|
|
114
|
+
visibility.assign(mix1(lit, coverage));
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
return visibility;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function mix1(value, amount) {
|
|
121
|
+
return float(1).add(value.sub(1).mul(amount));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Screen-space shadow toward the light against the depth prepass: something
|
|
126
|
+
* in front of the short ray toward the light (bangs over the forehead, hair
|
|
127
|
+
* on the cheek) shadows the pixel. Face receivers ignore face occluders
|
|
128
|
+
* (`faceWeight`), so a face never shadows itself.
|
|
129
|
+
*/
|
|
130
|
+
export function screenSpaceShadowVisibility(u, state, viewPosition, lightDirectionWorld, faceWeight, gate) {
|
|
131
|
+
const occlusion = float(0).toVar('toonScreenShadow');
|
|
132
|
+
If(state.depthReady.greaterThan(0.5).and(gate), () => {
|
|
133
|
+
const lightView = cameraViewMatrix.mul(vec4(lightDirectionWorld, 0)).xyz;
|
|
134
|
+
const baseUV = viewToScreenUV(viewPosition);
|
|
135
|
+
for (const fraction of [0.5, 1]) {
|
|
136
|
+
const rayPoint = viewPosition.add(lightView.mul(u.screenShadowWidth.mul(fraction)));
|
|
137
|
+
const stored = decodeStoredDepth(state.depthMap.sample(offsetScreenUV(viewPosition, lightView.mul(u.screenShadowWidth.mul(fraction)), baseUV)).level(0).x);
|
|
138
|
+
const nearer = rayPoint.z.negate().sub(prepassDistance(stored.depth));
|
|
139
|
+
const faceOccluder = select(stored.face, float(1), float(0));
|
|
140
|
+
const hit = smoothstep(0.002, 0.006, nearer)
|
|
141
|
+
.mul(float(1).sub(smoothstep(0.12, 0.25, nearer)))
|
|
142
|
+
.mul(float(1).sub(faceOccluder.mul(min(faceWeight.mul(2), 1))));
|
|
143
|
+
occlusion.assign(max(occlusion, hit));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return float(1).sub(occlusion);
|
|
147
|
+
}
|