@call-me-sensei/toonlab 0.4.21 → 0.4.23
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 +87 -27
- package/README.md +11 -10
- package/agents/PROMPTS.md +17 -3
- package/agents/README.md +13 -3
- package/agents/claude/CLAUDE.md +3 -0
- package/agents/codex/AGENTS.md +112 -159
- package/agents/cursor/toonlab.mdc +7 -3
- package/agents/examples/game-foundation.mjs +104 -0
- package/agents/references/game-lifecycle.md +57 -0
- package/agents/references/runtime-entry-points.md +26 -0
- package/agents/references/style-bundles.md +4 -1
- package/agents/skills/claude/asset-sourcing/SKILL.md +7 -4
- package/agents/skills/claude/environment/SKILL.md +4 -0
- package/agents/skills/claude/game-dev/SKILL.md +63 -87
- package/agents/skills/claude/lighting/SKILL.md +36 -0
- package/agents/skills/claude/post-processing/SKILL.md +8 -3
- package/agents/skills/claude/rock-ground-shaders/SKILL.md +10 -15
- package/agents/skills/claude/rockgen/SKILL.md +52 -21
- package/agents/skills/claude/scene-style-application/SKILL.md +4 -0
- package/agents/skills/claude/style-presets/SKILL.md +11 -8
- package/agents/skills/claude/toon-shading/SKILL.md +4 -0
- package/agents/skills/claude/vegetation-sky/SKILL.md +13 -7
- package/agents/skills/claude/visual-verification/SKILL.md +45 -119
- package/agents/skills/claude/water/SKILL.md +6 -2
- package/agents/skills/codex/asset-sourcing/SKILL.md +7 -4
- package/agents/skills/codex/environment/SKILL.md +4 -0
- package/agents/skills/codex/game-dev/SKILL.md +63 -87
- package/agents/skills/codex/lighting/SKILL.md +36 -0
- package/agents/skills/codex/post-processing/SKILL.md +8 -3
- package/agents/skills/codex/rock-ground-shaders/SKILL.md +10 -15
- package/agents/skills/codex/rockgen/SKILL.md +52 -21
- package/agents/skills/codex/scene-style-application/SKILL.md +4 -0
- package/agents/skills/codex/style-presets/SKILL.md +11 -8
- package/agents/skills/codex/toon-shading/SKILL.md +4 -0
- package/agents/skills/codex/vegetation-sky/SKILL.md +13 -7
- package/agents/skills/codex/visual-verification/SKILL.md +45 -119
- package/agents/skills/codex/water/SKILL.md +6 -2
- package/database/apply-one-catalog-seed.mjs +63 -0
- package/database/providers.mjs +1 -0
- package/database/seeds/catalog/0005_2026-08-c8-first12.sql +1101 -0
- package/database/seeds/catalog/0006_2026-09-c8-first100.sql +14245 -0
- package/database/seeds/catalog/0007_2026-09-c8-first100-primary-model.sql +14845 -0
- package/mcp/lab-management.mjs +11 -8
- package/mcp/public-catalog.mjs +0 -16
- package/mcp/tree-lab-contract.mjs +2381 -0
- package/mcp/vite-plugin.mjs +5 -1
- package/package.json +29 -18
- package/src/catalog/officialCatalog.js +1 -0
- package/src/catalog/officialCatalogAssetRuntime.js +98 -1
- package/src/catalog/officialCatalogLod.js +160 -16
- package/src/catalog/officialCatalogPlacement.js +52 -12
- package/src/catalog/officialCatalogProvider.js +79 -8
- package/src/catalog/officialCatalogRockPackage.js +172 -0
- package/src/cloud/cloudReprojection.js +40 -7
- package/src/cloud/cloudVolume.js +44 -7
- package/src/cloud/noise/baseShapeVolume.js +8 -6
- package/src/cloud/noise/cirrusMap.js +2 -1
- package/src/cloud/noise/curlNoise.js +2 -1
- package/src/cloud/noise/erosionVolume.js +2 -1
- package/src/cloud/noise/textureCache.js +77 -0
- package/src/cloud/noise/weatherMap.js +2 -1
- package/src/core/sha256.js +83 -0
- package/src/ground-shader/groundShaderMaterial.js +12 -3
- package/src/rock-shader/rockMaterial.js +205 -28
- package/src/rock-shader/rockShaderRuntime.js +17 -1
- package/src/rock-shader/rockShaderSettings.js +16 -0
- package/src/rockgen/index.js +9 -0
- package/src/rockgen/lod/index.js +1 -0
- package/src/rockgen/lod/rockDenseFieldPolicy.js +143 -0
- package/src/rockgen/rockDocument.js +899 -35
- package/src/rockgen/surface/c7GeologySurface.js +39 -9
- package/src/rockgen/surface/naturalRockSurface.js +1948 -0
- package/src/shaders-tsl/chunks/projected-water-caustics.js +14 -2
- package/src/shaders-tsl/chunks/water-foam.js +6 -6
- package/src/shaders-tsl/chunks/water-lighting.js +28 -5
- package/src/shaders-tsl/chunks/water-shore-state.js +5 -2
- package/src/shaders-tsl/chunks/water-waves.js +10 -5
- package/src/shaders-tsl/flower.js +7 -4
- package/src/shaders-tsl/grass.js +4 -3
- package/src/shaders-tsl/water-shore-state-simulation.js +3 -2
- package/src/shaders-tsl/water.js +209 -41
- package/src/sky/skySystem.js +30 -7
- package/src/toon/settings/perspectiveRemovalSettings.js +1 -1
- package/src/toon/toonSettings.js +74 -0
- package/src/vegetation/stylizedFlower.js +6 -0
- package/src/version.js +1 -1
- package/src/water/waterDetailSpectrum.js +91 -0
- package/src/water/waterDynamics.js +422 -0
- package/src/water/waterFoamParticles.js +196 -0
- package/src/water/waterFoamTexture.js +57 -0
- package/src/water/waterHydrodynamics.js +209 -0
- package/src/water/waterMaterial.js +1 -0
- package/src/water/waterRenderExtension.js +107 -0
- package/src/water/waterScenePasses.js +14 -6
- package/src/water/waterSettings.js +53 -26
- package/src/water/waterShoreMaterial.js +38 -14
- package/src/water/waterSpectralOcean.js +137 -0
- package/src/water/waterStageSettings.js +19 -1
- package/src/water/waterSurface.js +62 -18
- package/src/water/waterUnderwaterAtmosphere.js +30 -3
- package/types/catalog/officialCatalog.d.ts +1 -0
- package/types/catalog/officialCatalogPlacement.d.ts +4 -0
- package/types/catalog/officialCatalogRockPackage.d.ts +68 -0
- package/types/cloud/noise/baseShapeVolume.d.ts +1 -1
- package/types/cloud/noise/textureCache.d.ts +12 -0
- package/types/core/sha256.d.ts +2 -0
- package/types/index.d.ts +30 -0
- package/types/rock-shader/rockMaterial.d.ts +3 -0
- package/types/rock-shader/rockShaderSettings.d.ts +2 -0
- package/types/rockgen/index.d.ts +1 -0
- package/types/rockgen/lod/index.d.ts +1 -0
- package/types/rockgen/lod/rockDenseFieldPolicy.d.ts +181 -0
- package/types/rockgen/rockDocument.d.ts +654 -71
- package/types/rockgen/surface/naturalRockSurface.d.ts +100 -0
- package/types/shaders-tsl/chunks/projected-water-caustics.d.ts +7 -1
- package/types/shaders-tsl/chunks/water-lighting.d.ts +4 -3
- package/types/shaders-tsl/water.d.ts +2 -1
- package/types/version.d.ts +1 -1
- package/types/water/waterDetailSpectrum.d.ts +13 -0
- package/types/water/waterDynamics.d.ts +89 -0
- package/types/water/waterFoamParticles.d.ts +32 -0
- package/types/water/waterFoamTexture.d.ts +1 -0
- package/types/water/waterHydrodynamics.d.ts +49 -0
- package/types/water/waterRenderExtension.d.ts +16 -0
- package/types/water/waterScenePasses.d.ts +1 -1
- package/types/water/waterSettings.d.ts +1 -0
- package/types/water/waterSpectralOcean.d.ts +17 -0
- package/types/water/waterStageSettings.d.ts +1 -1
- package/types/water/waterUnderwaterAtmosphere.d.ts +19 -4
|
@@ -104,6 +104,9 @@ const causticTexture = createCausticCellTexture();
|
|
|
104
104
|
|
|
105
105
|
export const projectedWaterCausticUniforms = {
|
|
106
106
|
map: texture(causticTexture),
|
|
107
|
+
surfaceMap: texture(causticTexture),
|
|
108
|
+
useSurfaceMap: uniform(0),
|
|
109
|
+
surfaceRegion: uniform(new THREE.Vector4(0,0,1,1)),
|
|
107
110
|
enabled: uniform(0.0),
|
|
108
111
|
time: uniform(0.0),
|
|
109
112
|
waterLevel: uniform(0.0),
|
|
@@ -147,9 +150,14 @@ export function updateProjectedWaterCaustics({
|
|
|
147
150
|
flowDirection,
|
|
148
151
|
waveDistortion,
|
|
149
152
|
depthAttenuation,
|
|
153
|
+
surfaceMap = null,
|
|
154
|
+
surfaceRegion = null,
|
|
150
155
|
} = {}) {
|
|
151
156
|
const u = projectedWaterCausticUniforms;
|
|
152
157
|
u.enabled.value = enabled ? 1 : 0;
|
|
158
|
+
u.useSurfaceMap.value = surfaceMap ? 1 : 0;
|
|
159
|
+
if (surfaceMap) u.surfaceMap.value = surfaceMap;
|
|
160
|
+
if (surfaceRegion) u.surfaceRegion.value.copy(surfaceRegion);
|
|
153
161
|
if (Number.isFinite(time)) u.time.value = time;
|
|
154
162
|
if (Number.isFinite(waterLevel)) u.waterLevel.value = waterLevel;
|
|
155
163
|
if ([centerX, centerZ, halfWidth, halfDepth].every(Number.isFinite)) {
|
|
@@ -227,13 +235,17 @@ export function projectedWaterCaustics(worldPosition, worldNormal) {
|
|
|
227
235
|
const cellA = u.map.sample(uvA).level(0).r;
|
|
228
236
|
const cellB = u.map.sample(uvB).level(0).r;
|
|
229
237
|
const web = min(cellA, cellB).oneMinus();
|
|
230
|
-
const
|
|
238
|
+
const fieldUv = worldPosition.xz.sub(u.surfaceRegion.xy).div(u.surfaceRegion.zw.mul(2.0)).add(0.5);
|
|
239
|
+
const edge = smoothstep(vec2(0.0), vec2(0.08), fieldUv)
|
|
240
|
+
.mul(smoothstep(vec2(0.92), vec2(1.0), fieldUv).oneMinus());
|
|
241
|
+
const solvedLight = u.surfaceMap.sample(clamp(fieldUv, vec2(0.0), vec2(1.0))).level(0).r.mul(edge.x).mul(edge.y);
|
|
242
|
+
const strands = mix(smoothstep(0.2, 0.9, web).pow(1.7), solvedLight, u.useSurfaceMap);
|
|
231
243
|
const pulse = sin(phase.mul(0.9).add(worldPosition.x.mul(0.11)))
|
|
232
244
|
.mul(0.5).add(0.5);
|
|
233
245
|
return u.color
|
|
234
246
|
.mul(u.intensity)
|
|
235
247
|
.mul(strands)
|
|
236
|
-
.mul(mix(0.76, 1.0, pulse))
|
|
248
|
+
.mul(mix(mix(0.76, 1.0, pulse), 1.0, u.useSurfaceMap))
|
|
237
249
|
.mul(submerged)
|
|
238
250
|
.mul(depthFade)
|
|
239
251
|
.mul(receivingFace)
|
|
@@ -26,8 +26,8 @@ export function createWaterFoamChunk({ u, foamOctaves }) {
|
|
|
26
26
|
const shoreFoam = (columnDepth, viewDepthDiff, restXZ, time, pierce) => {
|
|
27
27
|
const result = float(0.0).toVar();
|
|
28
28
|
If(u.uUseSceneDepth.greaterThanEqual(0.5), () => {
|
|
29
|
-
const flowOffset = u.uFlowDirection.mul(time).mul(u.uFlowSpeed).
|
|
30
|
-
const breakup = waterFbm(restXZ.mul(u.uFoamNoiseScale)
|
|
29
|
+
const flowOffset = u.uFlowDirection.mul(time).mul(u.uFlowSpeed).toVar();
|
|
30
|
+
const breakup = waterFbm(restXZ.sub(flowOffset).mul(u.uFoamNoiseScale), foamOctaves).toVar();
|
|
31
31
|
|
|
32
32
|
// A tight ungated core keeps a crisp waterline rim on any contact.
|
|
33
33
|
const contactTight = smoothstep(0.0, min(u.uFoamContactDistance.mul(0.5), 0.07), columnDepth).oneMinus();
|
|
@@ -51,7 +51,7 @@ export function createWaterFoamChunk({ u, foamOctaves }) {
|
|
|
51
51
|
const line = smoothstep(0.8, 0.93, lineBand)
|
|
52
52
|
.mul(smoothstep(0.93, 1.0, lineBand).oneMinus()).toVar();
|
|
53
53
|
const lineFalloff = smoothstep(1.3, 2.4, columnDepth.div(max(u.uFoamLineSpacing, 1e-3))).oneMinus();
|
|
54
|
-
const dashes = waterValueNoise(restXZ.mul(u.uFoamNoiseScale).mul(2.6)
|
|
54
|
+
const dashes = waterValueNoise(restXZ.sub(flowOffset).mul(u.uFoamNoiseScale).mul(2.6));
|
|
55
55
|
line.mulAssign(lineFalloff.mul(smoothstep(0.36, 0.6, breakup)).mul(smoothstep(0.3, 0.55, dashes)));
|
|
56
56
|
|
|
57
57
|
result.assign(clamp(
|
|
@@ -68,8 +68,8 @@ export function createWaterFoamChunk({ u, foamOctaves }) {
|
|
|
68
68
|
const whitecaps = (crest, gerstnerNormalY, restXZ, time) => {
|
|
69
69
|
const result = float(0.0).toVar();
|
|
70
70
|
If(u.uWhitecapAmount.greaterThan(0.002), () => {
|
|
71
|
-
const drift = u.uFlowDirection.mul(time).mul(u.uFlowSpeed
|
|
72
|
-
const patches = waterFbm(restXZ.mul(u.uFoamNoiseScale).mul(0.6)
|
|
71
|
+
const drift = u.uFlowDirection.mul(time).mul(u.uFlowSpeed);
|
|
72
|
+
const patches = waterFbm(restXZ.sub(drift).mul(u.uFoamNoiseScale).mul(0.6), foamOctaves).toVar();
|
|
73
73
|
const steepness = clamp(gerstnerNormalY.oneMinus().mul(9.0), 0.0, 1.0);
|
|
74
74
|
const energy = crest.mul(steepness.mul(0.45).add(0.55)).mul(patches.mul(0.85).add(0.45)).toVar();
|
|
75
75
|
const threshold = mix(float(0.985), float(0.32), clamp(u.uWhitecapAmount, 0.0, 1.0)).toVar();
|
|
@@ -82,7 +82,7 @@ export function createWaterFoamChunk({ u, foamOctaves }) {
|
|
|
82
82
|
// foam edges read as hand-drawn dots rather than a soft alpha gradient.
|
|
83
83
|
const foamShape = (rawMask, restXZ, time) => {
|
|
84
84
|
const dotNoise = waterValueNoise(
|
|
85
|
-
restXZ.
|
|
85
|
+
restXZ.sub(u.uFlowDirection.mul(time).mul(u.uFlowSpeed)).mul(u.uFoamNoiseScale).mul(5.2),
|
|
86
86
|
);
|
|
87
87
|
const solid = waterToonStep(0.56, 0.12, rawMask);
|
|
88
88
|
const dots = waterToonStep(0.74, 0.06, rawMask.mul(dotNoise.mul(0.75).add(0.35)));
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
clamp,
|
|
13
|
+
float,
|
|
13
14
|
dot,
|
|
14
15
|
If,
|
|
15
16
|
fract,
|
|
@@ -27,21 +28,43 @@ import {
|
|
|
27
28
|
|
|
28
29
|
import { waterHash12, waterToonStep, waterVoronoi2 } from './water-common.js';
|
|
29
30
|
|
|
30
|
-
export function createWaterLightingChunk({ u }) {
|
|
31
|
+
export function createWaterLightingChunk({ u, physicalSurface = false }) {
|
|
32
|
+
const reference = u.uReferenceView ?? float(0.0);
|
|
31
33
|
// Schlick-style fresnel with a stylized floor: uFresnelBias keeps some sky
|
|
32
34
|
// reflection alive even looking straight down.
|
|
33
35
|
const fresnelFactor = (viewDir, surfaceNormal) => {
|
|
34
36
|
const facing = clamp(dot(viewDir, surfaceNormal), 0.0, 1.0);
|
|
35
|
-
|
|
37
|
+
const stylized = clamp(
|
|
36
38
|
u.uFresnelBias.add(pow(facing.oneMinus(), u.uFresnelPower).mul(u.uFresnelStrength)),
|
|
37
39
|
0.0,
|
|
38
40
|
1.0,
|
|
39
41
|
);
|
|
42
|
+
const eta = u.uIndexOfRefraction ?? float(1.333);
|
|
43
|
+
const f0 = eta.sub(1.0).div(eta.add(1.0)).pow2();
|
|
44
|
+
const physical = f0.add(f0.oneMinus().mul(pow(facing.oneMinus(), 5.0)));
|
|
45
|
+
return physicalSurface ? physical : mix(stylized, physical, reference);
|
|
40
46
|
};
|
|
41
47
|
|
|
42
48
|
// Toon-banded Blinn-Phong glint. The normal is anisotropically squashed
|
|
43
49
|
// along the sun azimuth so low sun angles draw the long sparkling sun path.
|
|
44
50
|
const specular = (viewDir, surfaceNormal, shadowFactor) => {
|
|
51
|
+
if (physicalSurface) {
|
|
52
|
+
const half = normalize(viewDir.add(u.uSunDirection));
|
|
53
|
+
const nv = max(dot(surfaceNormal, viewDir), 0.001);
|
|
54
|
+
const nl = max(dot(surfaceNormal, u.uSunDirection), 0.0);
|
|
55
|
+
const nh = max(dot(surfaceNormal, half), 0.0);
|
|
56
|
+
const vh = max(dot(viewDir, half), 0.0);
|
|
57
|
+
const roughness = clamp(float(2.0).div(u.uSpecularShininess.add(2.0)).sqrt(), 0.055, 0.35);
|
|
58
|
+
const alpha2 = roughness.mul(roughness).toVar();
|
|
59
|
+
const denominator = nh.mul(nh).mul(alpha2.sub(1.0)).add(1.0);
|
|
60
|
+
const distribution = alpha2.div(max(denominator.mul(denominator).mul(Math.PI), 1e-5));
|
|
61
|
+
const masking = (cosine) => cosine.mul(2.0).div(max(cosine.add(alpha2.add(alpha2.oneMinus().mul(cosine.mul(cosine))).sqrt()), 1e-4));
|
|
62
|
+
const eta = u.uIndexOfRefraction ?? float(1.333);
|
|
63
|
+
const f0 = eta.sub(1.0).div(eta.add(1.0)).pow2();
|
|
64
|
+
const fresnel = f0.add(f0.oneMinus().mul(vh.oneMinus().pow(5)));
|
|
65
|
+
const specularBRDF = distribution.mul(masking(nv)).mul(masking(nl)).mul(fresnel).div(max(nv.mul(4.0), 1e-4));
|
|
66
|
+
return u.uSunColor.mul(specularBRDF).mul(u.uSpecularStrength).mul(shadowFactor);
|
|
67
|
+
}
|
|
45
68
|
const sunAzimuth = normalize(u.uSunDirection.xz.add(vec2(1e-5, 0.0))).toVar();
|
|
46
69
|
const sunPerp = vec2(sunAzimuth.y.negate(), sunAzimuth.x).toVar();
|
|
47
70
|
const stretched = sunAzimuth.mul(dot(surfaceNormal.xz, sunAzimuth))
|
|
@@ -52,7 +75,7 @@ export function createWaterLightingChunk({ u }) {
|
|
|
52
75
|
const alignment = pow(max(dot(glintNormal, halfDir), 0.0), u.uSpecularShininess).toVar();
|
|
53
76
|
const core = waterToonStep(0.5, 0.1, alignment);
|
|
54
77
|
const halo = waterToonStep(0.18, 0.16, alignment).mul(0.3);
|
|
55
|
-
return u.uSunColor.mul(u.uSpecularStrength).mul(core.add(halo)).mul(shadowFactor);
|
|
78
|
+
return u.uSunColor.mul(u.uSpecularStrength).mul(mix(core.add(halo), alignment, reference)).mul(shadowFactor);
|
|
56
79
|
};
|
|
57
80
|
|
|
58
81
|
// Twinkling star glints: sparse voronoi feature points with per-cell phase.
|
|
@@ -78,7 +101,7 @@ export function createWaterLightingChunk({ u }) {
|
|
|
78
101
|
.mul(alignment).mul(distanceFade).mul(3.2),
|
|
79
102
|
);
|
|
80
103
|
});
|
|
81
|
-
return result;
|
|
104
|
+
return result.mul(reference.oneMinus());
|
|
82
105
|
};
|
|
83
106
|
|
|
84
107
|
// Procedural sky used when no planar reflection target is bound: a vertical
|
|
@@ -105,7 +128,7 @@ export function createWaterLightingChunk({ u }) {
|
|
|
105
128
|
const planar = u.uReflectionMap.sample(reflectionUv).level(0).rgb;
|
|
106
129
|
// Milky painterly reflections: soften the mirror image toward the
|
|
107
130
|
// smooth procedural sky instead of showing a sharp flipped scene.
|
|
108
|
-
result.assign(mix(planar, fallback, clamp(u.uReflectionSoftness, 0.0, 1.0)));
|
|
131
|
+
result.assign(mix(planar, fallback, clamp(u.uReflectionSoftness, 0.0, 1.0).mul(reference.oneMinus()).mul(physicalSurface ? 0.25 : 1.0)));
|
|
109
132
|
});
|
|
110
133
|
});
|
|
111
134
|
});
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
clamp,
|
|
6
|
+
float,
|
|
7
|
+
mix,
|
|
6
8
|
smoothstep,
|
|
7
9
|
vec2,
|
|
8
10
|
} from 'three/tsl';
|
|
@@ -19,7 +21,8 @@ export function createWaterShoreStateChunk({ u }) {
|
|
|
19
21
|
// edge when a world uses a finite shore-state tile.
|
|
20
22
|
const border = smoothstep(vec2(0.0), vec2(0.02), fieldUv)
|
|
21
23
|
.mul(smoothstep(vec2(0.98), vec2(1.0), fieldUv).oneMinus());
|
|
22
|
-
const
|
|
24
|
+
const side = mix(border.x,1.0,u.uContinueShoreAlongX ?? float(0));
|
|
25
|
+
const mask = side.mul(border.y).mul(u.uUseShoreState).toVar();
|
|
23
26
|
return u.uShoreStateMap
|
|
24
27
|
.sample(clamp(fieldUv, vec2(0.0), vec2(1.0)))
|
|
25
28
|
.level(0)
|
|
@@ -31,7 +34,7 @@ export function createWaterShoreStateChunk({ u }) {
|
|
|
31
34
|
const fieldUv = shoreStateUv(worldXZ).toVar();
|
|
32
35
|
const border = smoothstep(vec2(0.0), vec2(0.02), fieldUv)
|
|
33
36
|
.mul(smoothstep(vec2(0.98), vec2(1.0), fieldUv).oneMinus());
|
|
34
|
-
return border.x.mul(border.y).mul(u.uUseShoreState).toVar();
|
|
37
|
+
return mix(border.x,1.0,u.uContinueShoreAlongX ?? float(0)).mul(border.y).mul(u.uUseShoreState).toVar();
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
return { shoreStateCoverage, shoreStateSample, shoreStateUv };
|
|
@@ -24,6 +24,8 @@ import {
|
|
|
24
24
|
float,
|
|
25
25
|
fract,
|
|
26
26
|
mix,
|
|
27
|
+
length,
|
|
28
|
+
max,
|
|
27
29
|
normalize,
|
|
28
30
|
sin,
|
|
29
31
|
vec3,
|
|
@@ -85,7 +87,7 @@ export function createWaterWavesChunk({ wavesA, wavesB, waveCount }) {
|
|
|
85
87
|
const cosTheta = cos(theta);
|
|
86
88
|
displacement.y.addAssign(amplitude.mul(sinTheta));
|
|
87
89
|
displacement.xz.addAssign(
|
|
88
|
-
phaseFrame.orbitDirection.mul(steepness.mul(amplitude).mul(cosTheta)),
|
|
90
|
+
phaseFrame.orbitDirection.mul(steepness.div(max(length(phaseFrame.gradient), 1.0)).mul(amplitude).mul(cosTheta)),
|
|
89
91
|
);
|
|
90
92
|
}
|
|
91
93
|
return displacement;
|
|
@@ -139,22 +141,25 @@ export function createWaterWavesChunk({ wavesA, wavesB, waveCount }) {
|
|
|
139
141
|
.sub(omega.mul(time)).add(phase).toVar();
|
|
140
142
|
const sinTheta = sin(theta).toVar();
|
|
141
143
|
const cosTheta = cos(theta).toVar();
|
|
144
|
+
// Shortening wavelength must not amplify horizontal compression.
|
|
145
|
+
// Match the orbital reduction in the displacement evaluation.
|
|
146
|
+
const localSteepness = steepness.div(max(length(phaseFrame.gradient), 1.0));
|
|
142
147
|
const waveKA = waveNumber.mul(amplitude).toVar();
|
|
143
148
|
const phaseGradient = phaseFrame.gradient;
|
|
144
149
|
const orbitDirection = phaseFrame.orbitDirection;
|
|
145
150
|
tangent.x.subAssign(
|
|
146
|
-
|
|
151
|
+
localSteepness.mul(orbitDirection.x).mul(phaseGradient.x).mul(waveKA).mul(sinTheta),
|
|
147
152
|
);
|
|
148
153
|
tangent.y.addAssign(phaseGradient.x.mul(waveKA).mul(cosTheta));
|
|
149
154
|
tangent.z.subAssign(
|
|
150
|
-
|
|
155
|
+
localSteepness.mul(orbitDirection.y).mul(phaseGradient.x).mul(waveKA).mul(sinTheta),
|
|
151
156
|
);
|
|
152
157
|
bitangent.x.subAssign(
|
|
153
|
-
|
|
158
|
+
localSteepness.mul(orbitDirection.x).mul(phaseGradient.y).mul(waveKA).mul(sinTheta),
|
|
154
159
|
);
|
|
155
160
|
bitangent.y.addAssign(phaseGradient.y.mul(waveKA).mul(cosTheta));
|
|
156
161
|
bitangent.z.subAssign(
|
|
157
|
-
|
|
162
|
+
localSteepness.mul(orbitDirection.y).mul(phaseGradient.y).mul(waveKA).mul(sinTheta),
|
|
158
163
|
);
|
|
159
164
|
const crestPeak = sinTheta.mul(0.5).add(0.5).toVar();
|
|
160
165
|
crestSum.addAssign(crestWeight.mul(amplitude).mul(crestPeak).mul(crestPeak));
|
|
@@ -112,6 +112,8 @@ function shadeFlowerHead({
|
|
|
112
112
|
);
|
|
113
113
|
const styledPetalColor = petalBaseColor.mul(flowerTint);
|
|
114
114
|
const styledCenterColor = centerBaseColor.mul(flowerTint);
|
|
115
|
+
// Shadow-side lift is reflected light, distinct from authored emission.
|
|
116
|
+
const sceneFill = clamp(u.uSunIntensity.add(u.uSkyIntensity).mul(0.5), 0, 1.5);
|
|
115
117
|
const petal = shadeVegetationSurface({
|
|
116
118
|
baseColor: styledPetalColor,
|
|
117
119
|
bandSoftness: u.uStyleFlowerBandSoftness,
|
|
@@ -133,7 +135,8 @@ function shadeFlowerHead({
|
|
|
133
135
|
worldPosition,
|
|
134
136
|
});
|
|
135
137
|
petal.color.addAssign(
|
|
136
|
-
styledPetalColor.mul(petal.band.oneMinus()).mul(u.uStyleFlowerUnlitPetalLift)
|
|
138
|
+
styledPetalColor.mul(petal.band.oneMinus()).mul(u.uStyleFlowerUnlitPetalLift)
|
|
139
|
+
.mul(sceneFill),
|
|
137
140
|
);
|
|
138
141
|
|
|
139
142
|
// Centers are opaque botanical structures, not thin petals. They share the
|
|
@@ -163,7 +166,7 @@ function shadeFlowerHead({
|
|
|
163
166
|
worldPosition,
|
|
164
167
|
});
|
|
165
168
|
const centerColor = mix(
|
|
166
|
-
styledCenterColor,
|
|
169
|
+
styledCenterColor.mul(sceneFill),
|
|
167
170
|
center.color,
|
|
168
171
|
u.uStyleFlowerCenterLightResponse,
|
|
169
172
|
);
|
|
@@ -174,7 +177,7 @@ function shadeFlowerHead({
|
|
|
174
177
|
const highlight = pow(
|
|
175
178
|
clamp(dot(normal, halfVector), 0, 1),
|
|
176
179
|
highlightPower,
|
|
177
|
-
).mul(sceneShadow).mul(u.uStyleFlowerSpecularStrength);
|
|
180
|
+
).mul(sceneShadow).mul(u.uStyleFlowerSpecularStrength).mul(u.uSunIntensity);
|
|
178
181
|
result.addAssign(u.uSunColor.mul(highlight));
|
|
179
182
|
result.addAssign(
|
|
180
183
|
mix(styledPetalColor, styledCenterColor, centerMask)
|
|
@@ -549,7 +552,7 @@ export function createFlowerStemNodeMaterial({
|
|
|
549
552
|
clamp(dot(normal, halfVector), 0, 1),
|
|
550
553
|
highlightPower,
|
|
551
554
|
).mul(u.uStyleStemSpecularStrength);
|
|
552
|
-
shaded.color.addAssign(u.uSunColor.mul(highlight));
|
|
555
|
+
shaded.color.addAssign(u.uSunColor.mul(highlight).mul(u.uSunIntensity));
|
|
553
556
|
shaded.color.addAssign(stemColor.mul(u.uStyleStemEmissiveStrength));
|
|
554
557
|
return vec4(shaded.color, 1.0);
|
|
555
558
|
})();
|
package/src/shaders-tsl/grass.js
CHANGED
|
@@ -337,7 +337,8 @@ export function createGrassNodeMaterial(
|
|
|
337
337
|
|
|
338
338
|
const sheen = smoothstep(u.uStyleGrassGustSheenThreshold, 1.0, vGust).mul(tipMix);
|
|
339
339
|
shaded.color.addAssign(
|
|
340
|
-
u.uSunColor.mul(sheen).mul(u.uStyleGrassGustSheenStrength).mul(shaded.band)
|
|
340
|
+
u.uSunColor.mul(sheen).mul(u.uStyleGrassGustSheenStrength).mul(shaded.band)
|
|
341
|
+
.mul(u.uSunIntensity),
|
|
341
342
|
);
|
|
342
343
|
const viewDirection = normalize(cameraPosition.sub(vWorldPosition));
|
|
343
344
|
const halfVector = normalize(sunDirection.add(viewDirection));
|
|
@@ -345,7 +346,7 @@ export function createGrassNodeMaterial(
|
|
|
345
346
|
const highlight = pow(
|
|
346
347
|
clamp(dot(normal, halfVector), 0, 1),
|
|
347
348
|
highlightPower,
|
|
348
|
-
).mul(sceneShadow).mul(u.uStyleGrassSpecularStrength);
|
|
349
|
+
).mul(sceneShadow).mul(u.uStyleGrassSpecularStrength).mul(u.uSunIntensity);
|
|
349
350
|
shaded.color.addAssign(u.uSunColor.mul(highlight));
|
|
350
351
|
shaded.color.addAssign(color.mul(u.uStyleGrassEmissiveStrength));
|
|
351
352
|
|
|
@@ -368,7 +369,7 @@ export function createGrassNodeMaterial(
|
|
|
368
369
|
// flat ground albedo here would undo the shared scene-light response a
|
|
369
370
|
// second time.
|
|
370
371
|
const washTarget = shaded.color.mul(1.18).add(
|
|
371
|
-
u.uSunColor.mul(0.035).mul(groundCoverage.oneMinus()),
|
|
372
|
+
u.uSunColor.mul(0.035).mul(groundCoverage.oneMinus()).mul(u.uSunIntensity),
|
|
372
373
|
);
|
|
373
374
|
shaded.color.assign(mix(shaded.color, washTarget, u.uWashLift));
|
|
374
375
|
const strokeAlpha = mix(
|
|
@@ -277,12 +277,13 @@ export function createWaterShoreStateSimulationNodeMaterial({
|
|
|
277
277
|
)
|
|
278
278
|
.mul(u.uSwashEdgeShape.z)
|
|
279
279
|
.toVar();
|
|
280
|
+
const swashActivity = smoothstep(0.0, 0.05, u.uWaveEnergy).toVar();
|
|
280
281
|
const edgeOffset = edgeTilt.add(edgeScallop).mul(edgeEnvelope)
|
|
281
|
-
.add(macroBase.mul(macroEnvelope)).toVar();
|
|
282
|
+
.add(macroBase.mul(macroEnvelope)).mul(swashActivity).toVar();
|
|
282
283
|
const edgeOffsetSpeed = scallopSpeed.mul(edgeEnvelope)
|
|
283
284
|
.add(edgeTilt.add(edgeScallop).mul(envelopeSpeed))
|
|
284
285
|
.add(macroBase.mul(macroEnvelopeSpeed))
|
|
285
|
-
.toVar();
|
|
286
|
+
.mul(swashActivity).toVar();
|
|
286
287
|
|
|
287
288
|
// In automatic mode the horizontal distance contains 1/slope, so its
|
|
288
289
|
// vertical head reduces to shorelineRunup * energy * progress.
|