@call-me-sensei/toonlab 0.2.0 → 0.3.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/AGENTS.md +127 -4
- package/ATTRIBUTION.md +41 -3
- package/README.md +234 -34
- package/docs/characters.md +144 -0
- package/docs/debug-panel.md +126 -0
- package/docs/docs.css +589 -0
- package/docs/environment.md +186 -0
- package/docs/getting-started.md +180 -0
- package/docs/index.html +14 -0
- package/docs/lab-architecture.md +100 -0
- package/docs/lighting.md +825 -0
- package/docs/main.jsx +739 -0
- package/docs/mcp.md +97 -0
- package/docs/post-processing.md +98 -0
- package/docs/settings-reference.md +1878 -0
- package/docs/shader-constants.md +77 -0
- package/docs/sky.md +182 -0
- package/docs/style-labs.md +309 -0
- package/docs/texture-lab.md +135 -0
- package/docs/toon-shading.md +183 -0
- package/docs/tsl-conventions.md +167 -0
- package/docs/vegetation-sky.md +275 -0
- package/docs/water.md +430 -0
- package/docs/weather.md +200 -0
- package/docs/world-scale.md +111 -0
- package/mcp/server.mjs +610 -0
- package/mcp/style-lab-tools.mjs +371 -0
- package/mcp/vite-plugin.mjs +174 -0
- package/mcp/workspace.mjs +397 -0
- package/package.json +64 -5
- package/src/ambientfx/INTEGRATION.md +164 -0
- package/src/ambientfx/ambientFxPresets.js +83 -0
- package/src/ambientfx/ambientFxSettings.js +368 -0
- package/src/ambientfx/emitters.js +169 -0
- package/src/ambientfx/index.js +5 -0
- package/src/ambientfx/particleBackbone.js +493 -0
- package/src/ambientfx/stylizedAmbientFx.js +450 -0
- package/src/assetlib/ambientcg.js +117 -0
- package/src/assetlib/assetRef.js +91 -0
- package/src/assetlib/importedEntry.js +40 -0
- package/src/assetlib/index.js +23 -0
- package/src/assetlib/kaykit.js +192 -0
- package/src/assetlib/kaykitStaticIndex.js +700 -0
- package/src/assetlib/loadImported.js +143 -0
- package/src/assetlib/opensource3d.js +113 -0
- package/src/assetlib/polyhaven.js +182 -0
- package/src/assetlib/polypizza.js +115 -0
- package/src/assetlib/smithsonian.js +214 -0
- package/src/assetlib/sources.js +279 -0
- package/src/assetlib/zip.js +58 -0
- package/src/biome/biomeGenerator.js +385 -0
- package/src/biome/biomeRuntime.js +299 -0
- package/src/biome/index.js +2 -0
- package/src/buildinggen/buildingAsset.js +44 -0
- package/src/buildinggen/buildingGrammar.js +311 -0
- package/src/buildinggen/buildingMesh.js +451 -0
- package/src/buildinggen/buildingPresets.js +46 -0
- package/src/buildinggen/buildingRecipe.js +100 -0
- package/src/buildinggen/buildingSettings.js +238 -0
- package/src/buildinggen/index.js +6 -0
- package/src/camera/cameraDirector.js +157 -0
- package/src/camera/cameraGenerator.js +367 -0
- package/src/camera/cameraRig.js +570 -0
- package/src/camera/cameraSettings.js +236 -0
- package/src/camera/index.js +7 -0
- package/src/catalog/builtinEntries.js +245 -0
- package/src/catalog/catalog.js +210 -0
- package/src/catalog/index.js +3 -0
- package/src/catalog/manifest.js +84 -0
- package/src/core/generation.js +529 -0
- package/src/environment/environmentRigs.js +21 -1
- package/src/environment/environmentSettings.js +4 -0
- package/src/environment/environmentSunShadowPass.js +8 -0
- package/src/fauna/INTEGRATION.md +174 -0
- package/src/fauna/boids.js +861 -0
- package/src/fauna/faunaBodies.js +492 -0
- package/src/fauna/faunaPresets.js +52 -0
- package/src/fauna/faunaSettings.js +525 -0
- package/src/fauna/index.js +5 -0
- package/src/fauna/stylizedFauna.js +395 -0
- package/src/game-feel/gameFeelGenerator.js +402 -0
- package/src/game-feel/gameFeelRuntime.js +549 -0
- package/src/game-feel/index.js +2 -0
- package/src/index.js +17 -6
- package/src/lighting/colorIntensity.js +177 -0
- package/src/lighting/index.js +161 -0
- package/src/lighting/lightDescriptors.js +249 -0
- package/src/lighting/lightingCapabilities.js +79 -0
- package/src/lighting/lightingDocuments.js +247 -0
- package/src/lighting/lightingFixtures.js +446 -0
- package/src/lighting/lightingGenerator.js +449 -0
- package/src/lighting/lightingPresets.js +319 -0
- package/src/lighting/lightingRuntime.js +723 -0
- package/src/lighting/lightingStyle.js +386 -0
- package/src/lighting/lightingSystem.js +774 -0
- package/src/lighting/unrealExport.js +186 -0
- package/src/lighting/utils.js +87 -0
- package/src/motion/index.js +5 -0
- package/src/motion/motionClip.js +441 -0
- package/src/motion/motionController.js +628 -0
- package/src/motion/motionDocuments.js +225 -0
- package/src/motion/motionGraph.js +307 -0
- package/src/motion/motionSettings.js +222 -0
- package/src/pathgen/index.js +7 -0
- package/src/pathgen/pathBridge.js +232 -0
- package/src/pathgen/pathPresets.js +35 -0
- package/src/pathgen/pathRibbon.js +410 -0
- package/src/pathgen/pathRouter.js +380 -0
- package/src/pathgen/pathSettings.js +335 -0
- package/src/pathgen/pathTextures.js +123 -0
- package/src/pathgen/stylizedPaths.js +453 -0
- package/src/post/index.js +1 -0
- package/src/post/postGenerator.js +177 -0
- package/src/post/postProcessing.js +41 -0
- package/src/propgen/generatorsWave1.js +379 -0
- package/src/propgen/generatorsWave2.js +462 -0
- package/src/propgen/index.js +5 -0
- package/src/propgen/propAsset.js +323 -0
- package/src/propgen/propParts.js +170 -0
- package/src/propgen/propPlacement.js +459 -0
- package/src/propgen/propPresets.js +82 -0
- package/src/propgen/propSettings.js +395 -0
- package/src/shaders-tsl/chunks/projected-water-caustics.js +242 -0
- package/src/shaders-tsl/chunks/vegetation-style.js +360 -0
- package/src/shaders-tsl/chunks/water-shore-state.js +31 -0
- package/src/shaders-tsl/chunks/water-waves.js +90 -11
- package/src/shaders-tsl/environment.js +15 -1
- package/src/shaders-tsl/flower.js +279 -30
- package/src/shaders-tsl/grass.js +60 -33
- package/src/shaders-tsl/sky.js +125 -31
- package/src/shaders-tsl/tree-leaf.js +61 -25
- package/src/shaders-tsl/water-breaker.js +7 -4
- package/src/shaders-tsl/water-shore-state-simulation.js +523 -0
- package/src/shaders-tsl/water.js +439 -49
- package/src/shaders-tsl/woody-surface.js +154 -0
- package/src/sky/sceneOverrideLayers.js +10 -0
- package/src/sky/skyQuality.js +26 -0
- package/src/sky/stylizedSky.js +753 -45
- package/src/soundscape/index.js +4 -0
- package/src/soundscape/soundscapeGenerator.js +179 -0
- package/src/soundscape/soundscapeRuntime.js +806 -0
- package/src/soundscape/soundscapeSettings.js +292 -0
- package/src/styles/index.js +13 -0
- package/src/styles/styleBundle.js +325 -0
- package/src/stylizedTerrain.js +32 -2
- package/src/stylizedWorld.js +423 -20
- package/src/texgen/evaluateTexture.js +675 -0
- package/src/texgen/index.js +60 -0
- package/src/texgen/noise2.js +210 -0
- package/src/texgen/textureAi.js +436 -0
- package/src/texgen/textureGenerators.js +516 -0
- package/src/texgen/texturePresets.js +490 -0
- package/src/texgen/textureSettings.js +342 -0
- package/src/texgen/textureThree.js +59 -0
- package/src/vegetation/flowerSpecies.js +15 -3
- package/src/vegetation/grassPalettes.js +153 -0
- package/src/vegetation/index.js +6 -0
- package/src/vegetation/stylizedBush.js +2 -0
- package/src/vegetation/stylizedFlower.js +82 -0
- package/src/vegetation/stylizedFlowers.js +48 -7
- package/src/vegetation/stylizedForest.js +29 -1
- package/src/vegetation/stylizedGrass.js +291 -56
- package/src/vegetation/stylizedTree.js +38 -2
- package/src/vegetation/stylizedTreeFoliage.js +2 -1
- package/src/vegetation/vegetationShaders.js +1110 -0
- package/src/vfxgen/INTEGRATION.md +145 -0
- package/src/vfxgen/core/burstBackbone.js +380 -0
- package/src/vfxgen/core/projectileCore.js +92 -0
- package/src/vfxgen/core/spriteShapes.js +98 -0
- package/src/vfxgen/core/trailRibbon.js +272 -0
- package/src/vfxgen/core/vfxRandom.js +29 -0
- package/src/vfxgen/effects/emitHelpers.js +37 -0
- package/src/vfxgen/effects/magicEffects.js +162 -0
- package/src/vfxgen/effects/movementEffects.js +87 -0
- package/src/vfxgen/effects/weaponEffects.js +118 -0
- package/src/vfxgen/index.js +18 -0
- package/src/vfxgen/moves/moveController.js +146 -0
- package/src/vfxgen/moves/moveLibrary.js +335 -0
- package/src/vfxgen/vfxPresets.js +98 -0
- package/src/vfxgen/vfxSettings.js +384 -0
- package/src/vfxgen/vfxSystem.js +449 -0
- package/src/vfxgen/weapons/stylizedWeapons.js +137 -0
- package/src/villagegen/index.js +4 -0
- package/src/villagegen/stylizedVillage.js +490 -0
- package/src/villagegen/villageArchetypes.js +160 -0
- package/src/villagegen/villageNames.js +40 -0
- package/src/villagegen/villageSites.js +105 -0
- package/src/water/sceneOverrideLayers.js +23 -0
- package/src/water/water.js +5 -0
- package/src/water/waterBreakerSystem.js +15 -1
- package/src/water/waterCurrentField.js +447 -0
- package/src/water/waterMaterial.js +12 -0
- package/src/water/waterNearshorePhase.js +320 -0
- package/src/water/waterScenePasses.js +83 -30
- package/src/water/waterSettings.js +325 -13
- package/src/water/waterShoreMaterial.js +322 -0
- package/src/water/waterShoreStateField.js +605 -0
- package/src/water/waterSurface.js +797 -28
- package/src/weather/index.js +6 -0
- package/src/weather/weatherPrecipitation.js +221 -0
- package/src/weather/weatherPresets.js +258 -0
- package/src/weather/weatherSettings.js +269 -0
- package/src/weather/weatherSystem.js +871 -0
- package/src/worldMinimap.js +62 -0
- package/src/worldPresets.js +4 -1
|
@@ -17,13 +17,18 @@ import {
|
|
|
17
17
|
Fn,
|
|
18
18
|
instanceIndex,
|
|
19
19
|
length,
|
|
20
|
+
floor,
|
|
21
|
+
max,
|
|
20
22
|
mix,
|
|
21
23
|
modelWorldMatrix,
|
|
22
24
|
normalize,
|
|
25
|
+
normalWorld,
|
|
23
26
|
positionLocal,
|
|
27
|
+
positionWorld,
|
|
24
28
|
pow,
|
|
25
29
|
sin,
|
|
26
30
|
smoothstep,
|
|
31
|
+
step,
|
|
27
32
|
texture,
|
|
28
33
|
time,
|
|
29
34
|
uniform,
|
|
@@ -35,12 +40,148 @@ import {
|
|
|
35
40
|
vec4,
|
|
36
41
|
attribute,
|
|
37
42
|
} from 'three/tsl';
|
|
38
|
-
import { MeshBasicNodeMaterial,
|
|
43
|
+
import { MeshBasicNodeMaterial, NodeMaterial } from 'three/webgpu';
|
|
39
44
|
|
|
40
45
|
import { sampleEnvironmentSunShadow } from './chunks/environment-sun-shadow.js';
|
|
46
|
+
import { stylizedCloudShadow } from './chunks/stylized-cloud-shadow.js';
|
|
47
|
+
import {
|
|
48
|
+
createVegetationStyleUniforms,
|
|
49
|
+
shadeVegetationSurface,
|
|
50
|
+
tagVegetationRole,
|
|
51
|
+
} from './chunks/vegetation-style.js';
|
|
52
|
+
|
|
53
|
+
const FLOWER_HEAD_ROLES = Object.freeze(['flowerPetal', 'flowerCenter']);
|
|
54
|
+
|
|
55
|
+
function flowerSurfaceUniforms(vegetationShader, role = FLOWER_HEAD_ROLES) {
|
|
56
|
+
const style = createVegetationStyleUniforms(vegetationShader, role);
|
|
57
|
+
return {
|
|
58
|
+
uCloudShadowCoverage: uniform(0.45),
|
|
59
|
+
uCloudShadowScale: uniform(0.012),
|
|
60
|
+
uCloudShadowStrength: uniform(0),
|
|
61
|
+
uCloudShadowVelocity: uniform(new THREE.Vector2(0.02, 0.006)),
|
|
62
|
+
uSkyColor: uniform(new THREE.Color().setRGB(0.62, 0.78, 0.95, THREE.SRGBColorSpace)),
|
|
63
|
+
uSunColor: uniform(new THREE.Color().setRGB(1, 0.96, 0.84, THREE.SRGBColorSpace)),
|
|
64
|
+
uSunDirection: uniform(new THREE.Vector3(0.35, 0.72, 0.42).normalize()),
|
|
65
|
+
...style,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
41
68
|
|
|
42
|
-
|
|
43
|
-
const
|
|
69
|
+
function resolveFlowerCenterRadius(map, centerRadius) {
|
|
70
|
+
const value = centerRadius
|
|
71
|
+
?? map?.userData?.toonlabFlower?.centerRadius
|
|
72
|
+
?? map?.userData?.toonlabFlowerCenterRadius
|
|
73
|
+
?? 0;
|
|
74
|
+
return THREE.MathUtils.clamp(Number(value) || 0, 0, 0.5);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function flowerCloudShadow(u, worldPosition) {
|
|
78
|
+
return stylizedCloudShadow(
|
|
79
|
+
worldPosition.xz,
|
|
80
|
+
time,
|
|
81
|
+
u.uCloudShadowStrength,
|
|
82
|
+
u.uCloudShadowCoverage,
|
|
83
|
+
u.uCloudShadowScale,
|
|
84
|
+
u.uCloudShadowVelocity,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function aliasLegacyFlowerUniforms(u) {
|
|
89
|
+
// The old one-field Flower shader remains a compatibility adapter, but all
|
|
90
|
+
// petal variants now share the same underlying style uniform.
|
|
91
|
+
u.uUnlitLift = u.uStyleFlowerUnlitPetalLift;
|
|
92
|
+
return u;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function shadeFlowerHead({
|
|
96
|
+
centerBaseColor,
|
|
97
|
+
centerMask,
|
|
98
|
+
normal,
|
|
99
|
+
petalBaseColor,
|
|
100
|
+
sceneShadow,
|
|
101
|
+
u,
|
|
102
|
+
worldPosition,
|
|
103
|
+
}) {
|
|
104
|
+
const cloudShadow = flowerCloudShadow(u, worldPosition);
|
|
105
|
+
const petal = shadeVegetationSurface({
|
|
106
|
+
baseColor: petalBaseColor,
|
|
107
|
+
bandSoftness: u.uStyleFlowerBandSoftness,
|
|
108
|
+
bandThreshold: u.uStyleFlowerBandThreshold,
|
|
109
|
+
cloudShadow,
|
|
110
|
+
cloudShadowResponse: 1,
|
|
111
|
+
normal,
|
|
112
|
+
sceneShadow,
|
|
113
|
+
sceneShadowResponse: u.uStyleFlowerSceneShadowResponse,
|
|
114
|
+
shadowFloor: u.uStyleThinSurfaceTransmissionShadowFloor,
|
|
115
|
+
skyColor: u.uSkyColor,
|
|
116
|
+
sunColor: u.uSunColor,
|
|
117
|
+
sunDirection: u.uSunDirection,
|
|
118
|
+
transmissionMultiplier: u.uStyleFlowerBacklitStrength.div(0.35)
|
|
119
|
+
.mul(u.uStyleFlowerPetalTransmissionMultiplier),
|
|
120
|
+
u,
|
|
121
|
+
worldPosition,
|
|
122
|
+
});
|
|
123
|
+
petal.color.addAssign(
|
|
124
|
+
petalBaseColor.mul(petal.band.oneMinus()).mul(u.uStyleFlowerUnlitPetalLift),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Centers are opaque botanical structures, not thin petals. They share the
|
|
128
|
+
// IP lighting/weather and flower band treatment, but explicitly opt out of
|
|
129
|
+
// diffuse-wrap, two-sided, normal-bias, and transmission profile controls.
|
|
130
|
+
const centerSceneShadow = mix(1.0, sceneShadow, u.uStyleFlowerCenterShadowResponse);
|
|
131
|
+
const center = shadeVegetationSurface({
|
|
132
|
+
baseColor: centerBaseColor,
|
|
133
|
+
bandSoftness: u.uStyleFlowerBandSoftness,
|
|
134
|
+
bandThreshold: u.uStyleFlowerBandThreshold,
|
|
135
|
+
cloudShadow,
|
|
136
|
+
cloudShadowResponse: 1,
|
|
137
|
+
diffuseWrap: float(0.5),
|
|
138
|
+
normal,
|
|
139
|
+
normalUpBias: float(0),
|
|
140
|
+
sceneShadow: centerSceneShadow,
|
|
141
|
+
sceneShadowResponse: u.uStyleFlowerSceneShadowResponse,
|
|
142
|
+
shadowFloor: float(0.35),
|
|
143
|
+
skyColor: u.uSkyColor,
|
|
144
|
+
sunColor: u.uSunColor,
|
|
145
|
+
sunDirection: u.uSunDirection,
|
|
146
|
+
transmissionPower: float(3.5),
|
|
147
|
+
transmissionShadowFloor: float(0.35),
|
|
148
|
+
transmissionStrength: float(0),
|
|
149
|
+
twoSidedLighting: float(0),
|
|
150
|
+
u,
|
|
151
|
+
worldPosition,
|
|
152
|
+
});
|
|
153
|
+
const centerColor = mix(centerBaseColor, center.color, u.uStyleFlowerCenterLightResponse);
|
|
154
|
+
return mix(petal.color, centerColor, centerMask);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Textured head variants carry petal and center pixels in one draw call. The
|
|
158
|
+
// sprite texture publishes its semantic center radius (see flowerSpecies.js),
|
|
159
|
+
// so the shader does not guess from color and recoloring cannot change roles.
|
|
160
|
+
function shadeFlowerSprite({ normal, sceneShadow, sprite, surfaceUv, u, worldPosition }) {
|
|
161
|
+
const radius = length(surfaceUv.sub(vec2(0.5, 0.5))).toVar();
|
|
162
|
+
const centerFeather = u.uCenterRadius.mul(0.12).max(0.006);
|
|
163
|
+
const centerMask = smoothstep(
|
|
164
|
+
u.uCenterRadius.add(centerFeather),
|
|
165
|
+
u.uCenterRadius.sub(centerFeather),
|
|
166
|
+
radius,
|
|
167
|
+
).mul(step(0.001, u.uCenterRadius)).toVar();
|
|
168
|
+
const petalEdge = clamp(radius.mul(2), 0, 1).mul(centerMask.oneMinus());
|
|
169
|
+
const petalBaseColor = sprite.rgb.mul(
|
|
170
|
+
petalEdge.mul(u.uStyleFlowerCupDarkeningStrength).mul(0.8).oneMinus(),
|
|
171
|
+
).toVar();
|
|
172
|
+
return shadeFlowerHead({
|
|
173
|
+
centerBaseColor: sprite.rgb,
|
|
174
|
+
centerMask,
|
|
175
|
+
normal,
|
|
176
|
+
petalBaseColor,
|
|
177
|
+
sceneShadow,
|
|
178
|
+
u,
|
|
179
|
+
worldPosition,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function createFlowerNodeMaterial(settings, vegetationShader = null) {
|
|
184
|
+
const u = aliasLegacyFlowerUniforms({
|
|
44
185
|
uCenterColor: uniform(new THREE.Color()),
|
|
45
186
|
uPetalColor: uniform(new THREE.Color()),
|
|
46
187
|
uShadowStrength: uniform(settings.shadowStrength),
|
|
@@ -48,7 +189,8 @@ export function createFlowerNodeMaterial(settings) {
|
|
|
48
189
|
uWindDirection: uniform(new THREE.Vector2(settings.windDirection[0], settings.windDirection[1])),
|
|
49
190
|
uWindSpeed: uniform(settings.windSpeed),
|
|
50
191
|
uWindStrength: uniform(settings.windStrength),
|
|
51
|
-
|
|
192
|
+
...flowerSurfaceUniforms(vegetationShader),
|
|
193
|
+
});
|
|
52
194
|
|
|
53
195
|
const material = new NodeMaterial();
|
|
54
196
|
material.name = 'StylizedFlowers';
|
|
@@ -57,6 +199,7 @@ export function createFlowerNodeMaterial(settings) {
|
|
|
57
199
|
|
|
58
200
|
const vPetal = varying(vec2(), 'vFlowerPetal');
|
|
59
201
|
const vPhase = varying(float(), 'vFlowerPhase');
|
|
202
|
+
const vWorldNormal = varying(vec3(), 'vFlowerWorldNormal');
|
|
60
203
|
const vWorldPosition = varying(vec3(), 'vFlowerWorldPosition');
|
|
61
204
|
|
|
62
205
|
material.vertexNode = Fn(() => {
|
|
@@ -84,6 +227,11 @@ export function createFlowerNodeMaterial(settings) {
|
|
|
84
227
|
cameraViewMatrix.element(1).y,
|
|
85
228
|
cameraViewMatrix.element(2).y,
|
|
86
229
|
);
|
|
230
|
+
vWorldNormal.assign(normalize(
|
|
231
|
+
vec3(0, 1, 0)
|
|
232
|
+
.add(cameraRight.mul(positionLocal.x).mul(0.3))
|
|
233
|
+
.add(cameraUp.mul(positionLocal.y).mul(0.3)),
|
|
234
|
+
));
|
|
87
235
|
const flowerPosition = center.add(
|
|
88
236
|
cameraRight.mul(positionLocal.x).add(cameraUp.mul(positionLocal.y)).mul(iInfo.x),
|
|
89
237
|
);
|
|
@@ -102,19 +250,27 @@ export function createFlowerNodeMaterial(settings) {
|
|
|
102
250
|
Discard(radius.greaterThan(petalEdge));
|
|
103
251
|
|
|
104
252
|
const centerMask = smoothstep(0.34, 0.2, radius);
|
|
105
|
-
const color = mix(u.uPetalColor, u.uCenterColor, centerMask).toVar();
|
|
106
253
|
// Petals cup slightly: darken toward their outer edge.
|
|
107
|
-
|
|
254
|
+
const petalBaseColor = u.uPetalColor.mul(
|
|
255
|
+
radius.div(petalEdge).mul(u.uStyleFlowerCupDarkeningStrength).oneMinus(),
|
|
256
|
+
);
|
|
108
257
|
|
|
109
|
-
// Scene shadows: cool dark tint matched to the grass field's response.
|
|
110
258
|
const sceneShadow = mix(1.0, sampleEnvironmentSunShadow(vWorldPosition), u.uShadowStrength);
|
|
111
|
-
color
|
|
259
|
+
const color = shadeFlowerHead({
|
|
260
|
+
centerBaseColor: u.uCenterColor,
|
|
261
|
+
centerMask,
|
|
262
|
+
normal: normalize(vWorldNormal),
|
|
263
|
+
petalBaseColor,
|
|
264
|
+
sceneShadow,
|
|
265
|
+
u,
|
|
266
|
+
worldPosition: vWorldPosition,
|
|
267
|
+
});
|
|
112
268
|
|
|
113
269
|
return vec4(color, 1.0);
|
|
114
270
|
})();
|
|
115
271
|
|
|
116
272
|
material.uniforms = u;
|
|
117
|
-
return material;
|
|
273
|
+
return tagVegetationRole(material, FLOWER_HEAD_ROLES, 'procedural');
|
|
118
274
|
}
|
|
119
275
|
|
|
120
276
|
// Shared instance-phased sway for the tree lab's flower patch. Heads use the
|
|
@@ -132,13 +288,18 @@ function flowerSway(u) {
|
|
|
132
288
|
* patch's old MeshBasicMaterial billboards, plus a gentle wind bob the
|
|
133
289
|
* classic material never had.
|
|
134
290
|
*/
|
|
135
|
-
export function createFlowerHeadNodeMaterial({
|
|
136
|
-
|
|
291
|
+
export function createFlowerHeadNodeMaterial({
|
|
292
|
+
map, alphaCutoff = 0.4, centerRadius = null, vegetationShader = null,
|
|
293
|
+
windSpeed = 1, windStrength = 0,
|
|
294
|
+
} = {}) {
|
|
295
|
+
const u = aliasLegacyFlowerUniforms({
|
|
137
296
|
uAlphaCutoff: uniform(alphaCutoff),
|
|
297
|
+
uCenterRadius: uniform(resolveFlowerCenterRadius(map, centerRadius)),
|
|
138
298
|
uMap: texture(map),
|
|
139
299
|
uWindSpeed: uniform(windSpeed),
|
|
140
300
|
uWindStrength: uniform(windStrength),
|
|
141
|
-
|
|
301
|
+
...flowerSurfaceUniforms(vegetationShader),
|
|
302
|
+
});
|
|
142
303
|
|
|
143
304
|
const material = new MeshBasicNodeMaterial();
|
|
144
305
|
material.name = 'FlowerPatchHead';
|
|
@@ -146,11 +307,23 @@ export function createFlowerHeadNodeMaterial({ map, alphaCutoff = 0.4, windSpeed
|
|
|
146
307
|
material.transparent = true;
|
|
147
308
|
|
|
148
309
|
material.positionNode = positionLocal.add(flowerSway(u));
|
|
149
|
-
material.colorNode =
|
|
310
|
+
material.colorNode = Fn(() => {
|
|
311
|
+
const sprite = u.uMap.sample(uv());
|
|
312
|
+
const sceneShadow = mix(1.0, sampleEnvironmentSunShadow(positionWorld), 0.85);
|
|
313
|
+
const color = shadeFlowerSprite({
|
|
314
|
+
normal: normalize(normalWorld),
|
|
315
|
+
sceneShadow,
|
|
316
|
+
sprite,
|
|
317
|
+
surfaceUv: uv(),
|
|
318
|
+
u,
|
|
319
|
+
worldPosition: positionWorld,
|
|
320
|
+
});
|
|
321
|
+
return vec4(color, sprite.a);
|
|
322
|
+
})();
|
|
150
323
|
material.alphaTestNode = u.uAlphaCutoff;
|
|
151
324
|
|
|
152
325
|
material.uniforms = u;
|
|
153
|
-
return material;
|
|
326
|
+
return tagVegetationRole(material, FLOWER_HEAD_ROLES, 'cutout');
|
|
154
327
|
}
|
|
155
328
|
|
|
156
329
|
/**
|
|
@@ -160,21 +333,26 @@ export function createFlowerHeadNodeMaterial({ map, alphaCutoff = 0.4, windSpeed
|
|
|
160
333
|
* never renders edge-on, from any camera.
|
|
161
334
|
*/
|
|
162
335
|
export function createFlowerHeadBillboardNodeMaterial({
|
|
163
|
-
map, alphaCutoff = 0.4,
|
|
336
|
+
map, alphaCutoff = 0.4, centerRadius = null, vegetationShader = null,
|
|
337
|
+
windDirection = [1, 0.3], windSpeed = 1, windStrength = 0,
|
|
164
338
|
} = {}) {
|
|
165
|
-
const u = {
|
|
339
|
+
const u = aliasLegacyFlowerUniforms({
|
|
166
340
|
uAlphaCutoff: uniform(alphaCutoff),
|
|
341
|
+
uCenterRadius: uniform(resolveFlowerCenterRadius(map, centerRadius)),
|
|
167
342
|
uMap: texture(map),
|
|
168
343
|
uWindDirection: uniform(new THREE.Vector2(windDirection[0], windDirection[1])),
|
|
169
344
|
uWindSpeed: uniform(windSpeed),
|
|
170
345
|
uWindStrength: uniform(windStrength),
|
|
171
|
-
|
|
346
|
+
...flowerSurfaceUniforms(vegetationShader),
|
|
347
|
+
});
|
|
172
348
|
|
|
173
349
|
const material = new NodeMaterial();
|
|
174
350
|
material.name = 'StylizedFlowerHeads';
|
|
175
351
|
material.side = THREE.DoubleSide;
|
|
176
352
|
|
|
177
353
|
const vUv = varying(vec2(), 'vFlowerHeadUv');
|
|
354
|
+
const vWorldNormal = varying(vec3(), 'vFlowerHeadNormal');
|
|
355
|
+
const vWorldPosition = varying(vec3(), 'vFlowerHeadWorldPosition');
|
|
178
356
|
|
|
179
357
|
material.vertexNode = Fn(() => {
|
|
180
358
|
const iOrigin = attribute('iOrigin', 'vec3');
|
|
@@ -207,61 +385,132 @@ export function createFlowerHeadBillboardNodeMaterial({
|
|
|
207
385
|
cameraViewMatrix.element(1).y,
|
|
208
386
|
cameraViewMatrix.element(2).y,
|
|
209
387
|
);
|
|
388
|
+
vWorldNormal.assign(normalize(cameraUp.mul(0.65).add(vec3(0, 1, 0).mul(0.35))));
|
|
210
389
|
const headPosition = center.add(
|
|
211
390
|
cameraRight.mul(corner.x).add(cameraUp.mul(corner.y)).mul(iInfo.x),
|
|
212
391
|
);
|
|
213
392
|
const worldPosition = modelWorldMatrix.mul(vec4(headPosition, 1.0));
|
|
393
|
+
vWorldPosition.assign(worldPosition.xyz);
|
|
214
394
|
return cameraProjectionMatrix.mul(cameraViewMatrix).mul(worldPosition);
|
|
215
395
|
})();
|
|
216
396
|
|
|
217
397
|
material.fragmentNode = Fn(() => {
|
|
218
398
|
const sprite = u.uMap.sample(vUv).toVar();
|
|
219
399
|
Discard(sprite.a.lessThan(u.uAlphaCutoff));
|
|
220
|
-
|
|
400
|
+
const sceneShadow = mix(1.0, sampleEnvironmentSunShadow(vWorldPosition), 0.85);
|
|
401
|
+
const color = shadeFlowerSprite({
|
|
402
|
+
normal: normalize(vWorldNormal),
|
|
403
|
+
sceneShadow,
|
|
404
|
+
sprite,
|
|
405
|
+
surfaceUv: vUv,
|
|
406
|
+
u,
|
|
407
|
+
worldPosition: vWorldPosition,
|
|
408
|
+
});
|
|
409
|
+
return vec4(color, 1.0);
|
|
221
410
|
})();
|
|
222
411
|
|
|
223
412
|
material.uniforms = u;
|
|
224
|
-
return material;
|
|
413
|
+
return tagVegetationRole(material, FLOWER_HEAD_ROLES, 'billboard');
|
|
225
414
|
}
|
|
226
415
|
|
|
227
416
|
/**
|
|
228
417
|
* Toon material for 3D bloom-head meshes (vertex-colored petals + center
|
|
229
418
|
* from createFlowerHeadGeometry), with the shared instance-phased wind bob.
|
|
230
419
|
*/
|
|
231
|
-
export function createFlowerBloomNodeMaterial({
|
|
232
|
-
|
|
420
|
+
export function createFlowerBloomNodeMaterial({
|
|
421
|
+
unlitLift = 0.35, vegetationShader = null, windSpeed = 1, windStrength = 0,
|
|
422
|
+
} = {}) {
|
|
423
|
+
const u = aliasLegacyFlowerUniforms({
|
|
233
424
|
uWindSpeed: uniform(windSpeed),
|
|
234
425
|
uWindStrength: uniform(windStrength),
|
|
235
|
-
|
|
426
|
+
...flowerSurfaceUniforms(vegetationShader),
|
|
427
|
+
});
|
|
428
|
+
if (!vegetationShader) u.uStyleFlowerUnlitPetalLift.value = unlitLift;
|
|
236
429
|
|
|
237
|
-
const material = new
|
|
430
|
+
const material = new NodeMaterial();
|
|
238
431
|
material.name = 'StylizedFlowerBloom';
|
|
432
|
+
material.side = THREE.DoubleSide;
|
|
239
433
|
material.positionNode = positionLocal.add(flowerSway(u));
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
434
|
+
material.fragmentNode = Fn(() => {
|
|
435
|
+
const centerMask = attribute('flowerRole', 'float');
|
|
436
|
+
const petalEdge = abs(uv().x.sub(0.5)).mul(2).mul(centerMask.oneMinus());
|
|
437
|
+
const rawColor = vertexColor().rgb;
|
|
438
|
+
const petalBaseColor = rawColor.mul(
|
|
439
|
+
petalEdge.mul(u.uStyleFlowerCupDarkeningStrength).mul(0.8).oneMinus(),
|
|
440
|
+
);
|
|
441
|
+
const sceneShadow = sampleEnvironmentSunShadow(positionWorld);
|
|
442
|
+
const color = shadeFlowerHead({
|
|
443
|
+
centerBaseColor: rawColor,
|
|
444
|
+
centerMask,
|
|
445
|
+
normal: normalize(normalWorld),
|
|
446
|
+
petalBaseColor,
|
|
447
|
+
sceneShadow,
|
|
448
|
+
u,
|
|
449
|
+
worldPosition: positionWorld,
|
|
450
|
+
});
|
|
451
|
+
return vec4(color, 1.0);
|
|
452
|
+
})();
|
|
243
453
|
|
|
244
454
|
material.uniforms = u;
|
|
245
|
-
return material;
|
|
455
|
+
return tagVegetationRole(material, FLOWER_HEAD_ROLES, 'mesh');
|
|
246
456
|
}
|
|
247
457
|
|
|
248
458
|
/**
|
|
249
459
|
* Toon stem material for ground flowers. Bends with the same sway as the
|
|
250
460
|
* head, scaled by height fraction (root stays planted, tip follows the head).
|
|
251
461
|
*/
|
|
252
|
-
export function createFlowerStemNodeMaterial({
|
|
462
|
+
export function createFlowerStemNodeMaterial({
|
|
463
|
+
color = 0x4d8a3f, height = 1, vegetationShader = null, windSpeed = 1, windStrength = 0,
|
|
464
|
+
} = {}) {
|
|
253
465
|
const u = {
|
|
466
|
+
uBaseColor: uniform(new THREE.Color(color)),
|
|
254
467
|
uHeight: uniform(Math.max(height, 1e-3)),
|
|
255
468
|
uWindSpeed: uniform(windSpeed),
|
|
256
469
|
uWindStrength: uniform(windStrength),
|
|
470
|
+
...flowerSurfaceUniforms(vegetationShader, 'herbaceousStem'),
|
|
257
471
|
};
|
|
258
472
|
|
|
259
|
-
const material = new
|
|
473
|
+
const material = new NodeMaterial();
|
|
260
474
|
material.name = 'FlowerPatchStem';
|
|
261
475
|
|
|
262
476
|
const bend = clamp(positionLocal.y.div(u.uHeight), 0.0, 1.0);
|
|
263
477
|
material.positionNode = positionLocal.add(flowerSway(u).mul(bend));
|
|
478
|
+
material.fragmentNode = Fn(() => {
|
|
479
|
+
const normal = normalize(normalWorld);
|
|
480
|
+
const sunDirection = normalize(u.uSunDirection);
|
|
481
|
+
const wrap = dot(normal, sunDirection).mul(0.5).add(0.5);
|
|
482
|
+
const steps = max(floor(u.uStyleStemBandCount), 2.0);
|
|
483
|
+
const intervals = max(steps.sub(1.0), 1.0);
|
|
484
|
+
const stepped = floor(clamp(wrap, 0, 1).mul(intervals).add(1e-4)).div(intervals);
|
|
485
|
+
const band = mix(stepped, wrap, u.uStyleStemBandSoftness);
|
|
486
|
+
const shaded = shadeVegetationSurface({
|
|
487
|
+
bandOverride: band,
|
|
488
|
+
baseColor: u.uBaseColor,
|
|
489
|
+
bandSoftness: u.uStyleStemBandSoftness,
|
|
490
|
+
bandThreshold: 0.5,
|
|
491
|
+
cloudShadow: flowerCloudShadow(u, positionWorld),
|
|
492
|
+
cloudShadowResponse: 1,
|
|
493
|
+
diffuseWrap: float(0.5),
|
|
494
|
+
normal,
|
|
495
|
+
normalUpBias: float(0),
|
|
496
|
+
sceneShadow: sampleEnvironmentSunShadow(positionWorld),
|
|
497
|
+
sceneShadowResponse: 1,
|
|
498
|
+
shadowFloor: u.uStyleStemShadowFloor,
|
|
499
|
+
skyColor: u.uSkyColor,
|
|
500
|
+
skyFillStrength: u.uStyleLightingSkyFillStrength.add(u.uStyleStemSkyFillStrength),
|
|
501
|
+
rimStrength: u.uStyleLightingRimStrength.add(u.uStyleStemRimStrength),
|
|
502
|
+
sunColor: u.uSunColor,
|
|
503
|
+
sunDirection,
|
|
504
|
+
transmissionPower: float(3.5),
|
|
505
|
+
transmissionShadowFloor: float(0.35),
|
|
506
|
+
transmissionStrength: u.uStyleStemTransmissionStrength,
|
|
507
|
+
twoSidedLighting: float(0),
|
|
508
|
+
u,
|
|
509
|
+
worldPosition: positionWorld,
|
|
510
|
+
});
|
|
511
|
+
return vec4(shaded.color, 1.0);
|
|
512
|
+
})();
|
|
264
513
|
|
|
265
514
|
material.uniforms = u;
|
|
266
|
-
return material;
|
|
515
|
+
return tagVegetationRole(material, 'herbaceousStem', 'mesh');
|
|
267
516
|
}
|
package/src/shaders-tsl/grass.js
CHANGED
|
@@ -41,10 +41,15 @@ import { NodeMaterial } from 'three/webgpu';
|
|
|
41
41
|
|
|
42
42
|
import { sampleEnvironmentSunShadow } from './chunks/environment-sun-shadow.js';
|
|
43
43
|
import { stylizedCloudShadow } from './chunks/stylized-cloud-shadow.js';
|
|
44
|
+
import {
|
|
45
|
+
createVegetationStyleUniforms,
|
|
46
|
+
shadeVegetationSurface,
|
|
47
|
+
tagVegetationRole,
|
|
48
|
+
} from './chunks/vegetation-style.js';
|
|
44
49
|
|
|
45
|
-
export function createGrassNodeMaterial(settings) {
|
|
50
|
+
export function createGrassNodeMaterial(settings, vegetationShader = null) {
|
|
51
|
+
const styleUniforms = createVegetationStyleUniforms(vegetationShader, 'grassBlade');
|
|
46
52
|
const u = {
|
|
47
|
-
uBacklitStrength: uniform(settings.backlitStrength),
|
|
48
53
|
uBaseColor: uniform(new THREE.Color()),
|
|
49
54
|
uCloudShadowCoverage: uniform(settings.cloudShadowCoverage),
|
|
50
55
|
uCloudShadowScale: uniform(settings.cloudShadowScale),
|
|
@@ -53,6 +58,7 @@ export function createGrassNodeMaterial(settings) {
|
|
|
53
58
|
uFadeEnd: uniform(1e6 + 1),
|
|
54
59
|
uFadeStart: uniform(1e6),
|
|
55
60
|
uGustFrequency: uniform(settings.gustFrequency),
|
|
61
|
+
uGustResponse: uniform(settings.gustResponse),
|
|
56
62
|
uGustSpeed: uniform(settings.gustSpeed),
|
|
57
63
|
uPushPosition: uniform(new THREE.Vector3(0, -1e5, 0)),
|
|
58
64
|
uPushRadius: uniform(settings.pushRadius),
|
|
@@ -64,9 +70,14 @@ export function createGrassNodeMaterial(settings) {
|
|
|
64
70
|
uTime: uniform(0),
|
|
65
71
|
uTipColor: uniform(new THREE.Color()),
|
|
66
72
|
uWindDirection: uniform(new THREE.Vector2(settings.windDirection[0], settings.windDirection[1])),
|
|
73
|
+
uWindResponse: uniform(settings.windResponse),
|
|
67
74
|
uWindSpeed: uniform(settings.windSpeed),
|
|
68
75
|
uWindStrength: uniform(settings.windStrength),
|
|
76
|
+
...styleUniforms,
|
|
69
77
|
};
|
|
78
|
+
if (!vegetationShader) u.uStyleGrassBacklitStrength.value = settings.backlitStrength;
|
|
79
|
+
// Compatibility alias: legacy runtime setters now target the canonical style node.
|
|
80
|
+
u.uBacklitStrength = u.uStyleGrassBacklitStrength;
|
|
70
81
|
|
|
71
82
|
const material = new NodeMaterial();
|
|
72
83
|
material.name = 'StylizedGrass';
|
|
@@ -92,7 +103,7 @@ export function createGrassNodeMaterial(settings) {
|
|
|
92
103
|
bladePosition.xz.addAssign(facing.mul(positionLocal.x.mul(iInfo.z)));
|
|
93
104
|
bladePosition.y.addAssign(heightFraction.mul(iInfo.x));
|
|
94
105
|
|
|
95
|
-
const bendCurve = heightFraction.
|
|
106
|
+
const bendCurve = pow(heightFraction, u.uStyleGrassBendExponent).toVar();
|
|
96
107
|
|
|
97
108
|
// Static per-blade lean (see grass.vert.glsl).
|
|
98
109
|
const bowDirection = vec2(facing.y.negate(), facing.x);
|
|
@@ -116,8 +127,11 @@ export function createGrassNodeMaterial(settings) {
|
|
|
116
127
|
const phase = u.uTime.mul(u.uWindSpeed).add(iInfo.y.mul(6.2831))
|
|
117
128
|
.add(dot(iOrigin.xz, vec2(0.35, 0.28)));
|
|
118
129
|
const flutter = sin(phase).mul(0.5).add(0.5).add(sin(phase.mul(2.33).add(1.7)).mul(0.3));
|
|
119
|
-
const wind = windDirection.mul(
|
|
120
|
-
|
|
130
|
+
const wind = windDirection.mul(
|
|
131
|
+
flutter.mul(0.6).add(vGust.mul(1.1).mul(u.uGustResponse)),
|
|
132
|
+
).toVar();
|
|
133
|
+
const windAmplitude = u.uWindStrength.mul(u.uWindResponse).toVar();
|
|
134
|
+
bladePosition.xz.addAssign(wind.mul(windAmplitude).mul(bendCurve).mul(iInfo.x));
|
|
121
135
|
|
|
122
136
|
// Character push.
|
|
123
137
|
const fromPush = bladePosition.xz.sub(u.uPushPosition.xz).toVar();
|
|
@@ -125,12 +139,15 @@ export function createGrassNodeMaterial(settings) {
|
|
|
125
139
|
const push = smoothstep(0.0, u.uPushRadius, pushDistance).oneMinus()
|
|
126
140
|
.mul(step(abs(iOrigin.y.sub(u.uPushPosition.y)), 1.8));
|
|
127
141
|
bladePosition.xz.addAssign(
|
|
128
|
-
normalize(fromPush.add(vec2(1e-4, 0.0))).mul(push).mul(0.42)
|
|
142
|
+
normalize(fromPush.add(vec2(1e-4, 0.0))).mul(push).mul(0.42)
|
|
143
|
+
.mul(bendCurve).mul(iInfo.x).mul(u.uStyleGrassInteractionResponse),
|
|
144
|
+
);
|
|
145
|
+
bladePosition.y.subAssign(
|
|
146
|
+
push.mul(0.14).mul(bendCurve).mul(iInfo.x).mul(u.uStyleGrassInteractionResponse),
|
|
129
147
|
);
|
|
130
|
-
bladePosition.y.subAssign(push.mul(0.14).mul(bendCurve).mul(iInfo.x));
|
|
131
148
|
|
|
132
149
|
// Shared field normal, tilted by the current bend.
|
|
133
|
-
const tilt = wind.mul(
|
|
150
|
+
const tilt = wind.mul(windAmplitude).add(leanDirection.mul(leanAmount).mul(0.35)).mul(heightFraction);
|
|
134
151
|
vNormal.assign(normalize(vec3(tilt.x.mul(1.4), 1.0, tilt.y.mul(1.4))));
|
|
135
152
|
|
|
136
153
|
// Distance fade to a degenerate point.
|
|
@@ -149,12 +166,20 @@ export function createGrassNodeMaterial(settings) {
|
|
|
149
166
|
const halfWidth = taper.mul(0.5);
|
|
150
167
|
Discard(abs(vUv.x.sub(0.5)).greaterThan(halfWidth));
|
|
151
168
|
|
|
152
|
-
const tipMix = smoothstep(
|
|
169
|
+
const tipMix = smoothstep(
|
|
170
|
+
u.uStyleGrassTipGradientStart,
|
|
171
|
+
u.uStyleGrassTipGradientEnd,
|
|
172
|
+
vUv.y.mul(vJitter.mul(0.3).add(0.85)),
|
|
173
|
+
).toVar();
|
|
153
174
|
const color = mix(u.uBaseColor, u.uTipColor, tipMix).toVar();
|
|
154
|
-
color.mulAssign(vJitter.
|
|
175
|
+
color.mulAssign(vJitter.sub(0.5).mul(u.uStyleGrassColorVariationStrength).add(1.0));
|
|
155
176
|
|
|
156
177
|
// Dense-field AO toward the roots.
|
|
157
|
-
color.mulAssign(mix(
|
|
178
|
+
color.mulAssign(mix(
|
|
179
|
+
u.uStyleGrassRootOcclusionStrength.oneMinus(),
|
|
180
|
+
1.0,
|
|
181
|
+
smoothstep(0.0, u.uStyleGrassRootOcclusionHeight, vUv.y),
|
|
182
|
+
));
|
|
158
183
|
|
|
159
184
|
const normal = normalize(vNormal);
|
|
160
185
|
const sunDirection = normalize(u.uSunDirection);
|
|
@@ -163,31 +188,33 @@ export function createGrassNodeMaterial(settings) {
|
|
|
163
188
|
u.uCloudShadowStrength, u.uCloudShadowCoverage, u.uCloudShadowScale, u.uCloudShadowVelocity,
|
|
164
189
|
);
|
|
165
190
|
const sceneShadow = mix(1.0, sampleEnvironmentSunShadow(vWorldPosition), u.uShadowStrength);
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
const shaded = shadeVegetationSurface({
|
|
192
|
+
baseColor: color,
|
|
193
|
+
bandSoftness: u.uStyleGrassBandSoftness,
|
|
194
|
+
bandThreshold: u.uStyleGrassBandThreshold,
|
|
195
|
+
cloudShadow,
|
|
196
|
+
cloudShadowResponse: u.uStyleGrassCloudShadowResponse,
|
|
197
|
+
materialShadowColor: u.uShadowTint,
|
|
198
|
+
normal,
|
|
199
|
+
sceneShadow,
|
|
200
|
+
sceneShadowResponse: u.uStyleGrassSceneShadowResponse,
|
|
201
|
+
shadowFloor: u.uStyleGrassShadowFloor,
|
|
202
|
+
skyColor: u.uSkyColor,
|
|
203
|
+
sunColor: u.uSunColor,
|
|
204
|
+
sunDirection,
|
|
205
|
+
transmissionMultiplier: u.uStyleGrassBacklitStrength.div(0.35).mul(tipMix),
|
|
206
|
+
u,
|
|
207
|
+
worldPosition: vWorldPosition,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const sheen = smoothstep(u.uStyleGrassGustSheenThreshold, 1.0, vGust).mul(tipMix);
|
|
211
|
+
shaded.color.addAssign(
|
|
212
|
+
u.uSunColor.mul(sheen).mul(u.uStyleGrassGustSheenStrength).mul(shaded.band),
|
|
186
213
|
);
|
|
187
214
|
|
|
188
|
-
return vec4(color, 1.0);
|
|
215
|
+
return vec4(shaded.color, 1.0);
|
|
189
216
|
})();
|
|
190
217
|
|
|
191
218
|
material.uniforms = u;
|
|
192
|
-
return material;
|
|
219
|
+
return tagVegetationRole(material, 'grassBlade', 'procedural');
|
|
193
220
|
}
|