@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
|
@@ -90,6 +90,7 @@ export class StylizedFlower extends StylizedTree {
|
|
|
90
90
|
trunkMaterial: createFlowerStemNodeMaterial({
|
|
91
91
|
color: stemColor,
|
|
92
92
|
height: trunk.height,
|
|
93
|
+
vegetationShader: treeOptions.vegetationShader,
|
|
93
94
|
}),
|
|
94
95
|
});
|
|
95
96
|
this.name = 'StylizedFlower';
|
|
@@ -169,6 +170,7 @@ export class StylizedFlower extends StylizedTree {
|
|
|
169
170
|
// bloom faces up-and-out along its twig like a real flower head instead
|
|
170
171
|
// of tracking the camera.
|
|
171
172
|
const headMaterial = createFlowerBloomNodeMaterial({
|
|
173
|
+
vegetationShader: treeOptions.vegetationShader,
|
|
172
174
|
windSpeed: 1.1,
|
|
173
175
|
windStrength: headSize * 0.04,
|
|
174
176
|
});
|
|
@@ -205,6 +207,86 @@ export class StylizedFlower extends StylizedTree {
|
|
|
205
207
|
};
|
|
206
208
|
}
|
|
207
209
|
|
|
210
|
+
setWind(options = {}) {
|
|
211
|
+
super.setWind(options);
|
|
212
|
+
for (const material of [this.headsMesh?.material, this.trunkMesh?.material]) {
|
|
213
|
+
const uniforms = material?.uniforms;
|
|
214
|
+
if (!uniforms) continue;
|
|
215
|
+
if (options.speed !== undefined && uniforms.uWindSpeed) uniforms.uWindSpeed.value = Number(options.speed) || 0;
|
|
216
|
+
if (options.strength !== undefined && uniforms.uWindStrength) uniforms.uWindStrength.value = Math.max(Number(options.strength) || 0, 0);
|
|
217
|
+
if (options.direction !== undefined && uniforms.uWindDirection) {
|
|
218
|
+
const direction = Array.isArray(options.direction)
|
|
219
|
+
? options.direction
|
|
220
|
+
: [options.direction.x, options.direction.y ?? options.direction.z];
|
|
221
|
+
uniforms.uWindDirection.value.set(Number(direction[0]) || 0, Number(direction[1]) || 0);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
setSun(options = {}) {
|
|
228
|
+
super.setSun(options);
|
|
229
|
+
const uniforms = this.headsMesh?.material?.uniforms;
|
|
230
|
+
if (!uniforms) return this;
|
|
231
|
+
if (options.direction !== undefined && uniforms.uSunDirection) {
|
|
232
|
+
const direction = Array.isArray(options.direction)
|
|
233
|
+
? options.direction
|
|
234
|
+
: [options.direction.x, options.direction.y, options.direction.z];
|
|
235
|
+
uniforms.uSunDirection.value.set(...direction).normalize();
|
|
236
|
+
}
|
|
237
|
+
if (options.color !== undefined && uniforms.uSunColor) {
|
|
238
|
+
const color = Array.isArray(options.color)
|
|
239
|
+
? options.color
|
|
240
|
+
: [options.color.r, options.color.g, options.color.b];
|
|
241
|
+
uniforms.uSunColor.value.setRGB(...color, THREE.SRGBColorSpace);
|
|
242
|
+
}
|
|
243
|
+
if (options.sky !== undefined && uniforms.uSkyColor) {
|
|
244
|
+
const sky = Array.isArray(options.sky)
|
|
245
|
+
? options.sky
|
|
246
|
+
: [options.sky.r, options.sky.g, options.sky.b];
|
|
247
|
+
uniforms.uSkyColor.value.setRGB(...sky, THREE.SRGBColorSpace);
|
|
248
|
+
}
|
|
249
|
+
return this;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
setCloudShadow(options = {}) {
|
|
253
|
+
super.setCloudShadow(options);
|
|
254
|
+
for (const material of [this.headsMesh?.material, this.trunkMesh?.material]) {
|
|
255
|
+
const uniforms = material?.uniforms;
|
|
256
|
+
if (!uniforms) continue;
|
|
257
|
+
if (options.strength !== undefined && uniforms.uCloudShadowStrength) {
|
|
258
|
+
uniforms.uCloudShadowStrength.value = THREE.MathUtils.clamp(Number(options.strength) || 0, 0, 1);
|
|
259
|
+
}
|
|
260
|
+
if (options.coverage !== undefined && uniforms.uCloudShadowCoverage) {
|
|
261
|
+
uniforms.uCloudShadowCoverage.value = THREE.MathUtils.clamp(Number(options.coverage) || 0, 0, 1);
|
|
262
|
+
}
|
|
263
|
+
if (options.scale !== undefined && uniforms.uCloudShadowScale) {
|
|
264
|
+
uniforms.uCloudShadowScale.value = Math.max(Number(options.scale) || 0.0001, 0.0001);
|
|
265
|
+
}
|
|
266
|
+
if (options.velocity !== undefined && uniforms.uCloudShadowVelocity) {
|
|
267
|
+
const velocity = Array.isArray(options.velocity)
|
|
268
|
+
? options.velocity
|
|
269
|
+
: [options.velocity.x, options.velocity.y];
|
|
270
|
+
uniforms.uCloudShadowVelocity.value.set(Number(velocity[0]) || 0, Number(velocity[1]) || 0);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
setSurfaceWeather(options = {}) {
|
|
277
|
+
super.setSurfaceWeather?.(options);
|
|
278
|
+
for (const material of [this.headsMesh?.material, this.trunkMesh?.material]) {
|
|
279
|
+
const uniforms = material?.uniforms;
|
|
280
|
+
if (uniforms?.uWetness && options.wetness !== undefined) {
|
|
281
|
+
uniforms.uWetness.value = THREE.MathUtils.clamp(Number(options.wetness) || 0, 0, 1);
|
|
282
|
+
}
|
|
283
|
+
if (uniforms?.uSnowCover && options.snowCover !== undefined) {
|
|
284
|
+
uniforms.uSnowCover.value = THREE.MathUtils.clamp(Number(options.snowCover) || 0, 0, 1);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
|
|
208
290
|
dispose() {
|
|
209
291
|
this.headsMesh.geometry.dispose();
|
|
210
292
|
this.headsMesh.material.dispose();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
|
|
3
3
|
import { createFlowerNodeMaterial } from '../shaders-tsl/flower.js';
|
|
4
|
+
import { applyVegetationShader } from './vegetationShaders.js';
|
|
4
5
|
|
|
5
6
|
function setSrgbColor(color, rgb) {
|
|
6
7
|
color.setRGB(rgb[0], rgb[1], rgb[2], THREE.SRGBColorSpace);
|
|
@@ -254,7 +255,7 @@ export const FLOWER_SETTING_FIELD_SCHEMA = Object.freeze(
|
|
|
254
255
|
// existing callers keep working unchanged.
|
|
255
256
|
export class StylizedFlowerField extends THREE.Mesh {
|
|
256
257
|
constructor(options = {}) {
|
|
257
|
-
const { placements = [] } = cleanObject(options);
|
|
258
|
+
const { placements = [], vegetationShader = null } = cleanObject(options);
|
|
258
259
|
const settings = createFlowerSettings(options);
|
|
259
260
|
const { sizeRange } = settings;
|
|
260
261
|
|
|
@@ -283,7 +284,7 @@ export class StylizedFlowerField extends THREE.Mesh {
|
|
|
283
284
|
geometry.instanceCount = placements.length;
|
|
284
285
|
geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(), 1e5);
|
|
285
286
|
|
|
286
|
-
const material = createFlowerNodeMaterial(settings);
|
|
287
|
+
const material = createFlowerNodeMaterial(settings, vegetationShader);
|
|
287
288
|
setSrgbColor(material.uniforms.uPetalColor.value, settings.petalColor);
|
|
288
289
|
setSrgbColor(material.uniforms.uCenterColor.value, settings.centerColor);
|
|
289
290
|
|
|
@@ -324,14 +325,54 @@ export class StylizedFlowerField extends THREE.Mesh {
|
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
setWind({ direction, speed, strength } = {}) {
|
|
327
|
-
this.
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
328
|
+
const uniforms = this.material.uniforms;
|
|
329
|
+
if (direction !== undefined) {
|
|
330
|
+
const next = vectorArray(direction, this.settings.windDirection, 2);
|
|
331
|
+
uniforms.uWindDirection.value.set(next[0], next[1]);
|
|
332
|
+
}
|
|
333
|
+
if (speed !== undefined) uniforms.uWindSpeed.value = finiteNumber(speed, uniforms.uWindSpeed.value);
|
|
334
|
+
if (strength !== undefined) uniforms.uWindStrength.value = finiteNumber(strength, uniforms.uWindStrength.value, { min: 0 });
|
|
332
335
|
return this;
|
|
333
336
|
}
|
|
334
337
|
|
|
338
|
+
setSun({ direction, color, sky } = {}) {
|
|
339
|
+
const uniforms = this.material.uniforms;
|
|
340
|
+
if (direction !== undefined && uniforms.uSunDirection) {
|
|
341
|
+
const next = vectorArray(direction, [0.35, 0.72, 0.42], 3);
|
|
342
|
+
uniforms.uSunDirection.value.set(...next).normalize();
|
|
343
|
+
}
|
|
344
|
+
if (color !== undefined && uniforms.uSunColor) setSrgbColor(uniforms.uSunColor.value, colorArray(color, [1, 0.96, 0.84]));
|
|
345
|
+
if (sky !== undefined && uniforms.uSkyColor) setSrgbColor(uniforms.uSkyColor.value, colorArray(sky, [0.62, 0.78, 0.95]));
|
|
346
|
+
return this;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
setCloudShadow({ strength, coverage, scale, velocity } = {}) {
|
|
350
|
+
const uniforms = this.material.uniforms;
|
|
351
|
+
if (strength !== undefined) uniforms.uCloudShadowStrength.value = finiteNumber(strength, uniforms.uCloudShadowStrength.value, { min: 0, max: 1 });
|
|
352
|
+
if (coverage !== undefined) uniforms.uCloudShadowCoverage.value = finiteNumber(coverage, uniforms.uCloudShadowCoverage.value, { min: 0, max: 1 });
|
|
353
|
+
if (scale !== undefined) uniforms.uCloudShadowScale.value = finiteNumber(scale, uniforms.uCloudShadowScale.value, { min: 0.0001 });
|
|
354
|
+
if (velocity !== undefined) {
|
|
355
|
+
const next = vectorArray(velocity, [0.02, 0.006], 2);
|
|
356
|
+
uniforms.uCloudShadowVelocity.value.set(next[0], next[1]);
|
|
357
|
+
}
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
setSurfaceWeather({ wetness, snowCover } = {}) {
|
|
362
|
+
const uniforms = this.material.uniforms;
|
|
363
|
+
if (uniforms.uWetness && wetness !== undefined) {
|
|
364
|
+
uniforms.uWetness.value = finiteNumber(wetness, uniforms.uWetness.value, { min: 0, max: 1 });
|
|
365
|
+
}
|
|
366
|
+
if (uniforms.uSnowCover && snowCover !== undefined) {
|
|
367
|
+
uniforms.uSnowCover.value = finiteNumber(snowCover, uniforms.uSnowCover.value, { min: 0, max: 1 });
|
|
368
|
+
}
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
setVegetationShader(profile) {
|
|
373
|
+
return applyVegetationShader(this, profile);
|
|
374
|
+
}
|
|
375
|
+
|
|
335
376
|
update(delta) {
|
|
336
377
|
this.material.uniforms.uTime.value += Math.min(Math.max(delta ?? 0.016, 0), 0.1);
|
|
337
378
|
return this;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
+
import { applyVegetationShader } from './vegetationShaders.js';
|
|
2
3
|
import { MeshBasicNodeMaterial } from 'three/webgpu';
|
|
3
4
|
import {
|
|
4
5
|
clamp, exp, length, max, mix, positionView, positionWorld, texture, uniform, vec4, vertexColor,
|
|
@@ -90,12 +91,14 @@ export class StylizedForest extends THREE.Group {
|
|
|
90
91
|
castShadow = true, // near live clones cast; anchors the forest to the ground
|
|
91
92
|
renderer = null, // enables texture-baked billboard impostors (strongly recommended)
|
|
92
93
|
impostorTextureSize = 256, // billboard bake resolution per variant
|
|
94
|
+
vegetationShader = null,
|
|
93
95
|
} = {}) {
|
|
94
96
|
super();
|
|
95
97
|
this.name = 'StylizedForest';
|
|
96
98
|
this.detailDistance = detailDistance;
|
|
97
99
|
this.detailCount = detailCount;
|
|
98
100
|
this.updateInterval = updateInterval;
|
|
101
|
+
this.hasBakedImpostors = Boolean(renderer);
|
|
99
102
|
this._timer = updateInterval; // force an assignment on the first update
|
|
100
103
|
|
|
101
104
|
const variantCount = Math.max(1, Math.min(variants, Math.max(placements.length, 1)));
|
|
@@ -113,7 +116,7 @@ export class StylizedForest extends THREE.Group {
|
|
|
113
116
|
if (Array.isArray(canopyColors) && canopyColors.length > 0) {
|
|
114
117
|
variantSettings.tree.canopyColor = canopyColors[i % canopyColors.length];
|
|
115
118
|
}
|
|
116
|
-
const tree = new StylizedTree({ preset, seed, ...variantSettings });
|
|
119
|
+
const tree = new StylizedTree({ preset, seed, ...variantSettings, vegetationShader });
|
|
117
120
|
this.variantTrees.push(tree);
|
|
118
121
|
this._bakedVariants.push(prepareTreeForExport(tree));
|
|
119
122
|
}
|
|
@@ -406,6 +409,31 @@ export class StylizedForest extends THREE.Group {
|
|
|
406
409
|
return this;
|
|
407
410
|
}
|
|
408
411
|
|
|
412
|
+
setWind(options) {
|
|
413
|
+
for (const tree of this.variantTrees) tree.setWind?.(options);
|
|
414
|
+
return this;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** Keeps every live near-LOD tree on the current scene sun/sky inputs. */
|
|
418
|
+
setSun(options) {
|
|
419
|
+
for (const tree of this.variantTrees) tree.setSun?.(options);
|
|
420
|
+
return this;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
setSurfaceWeather(options) {
|
|
424
|
+
for (const tree of this.variantTrees) tree.setSurfaceWeather?.(options);
|
|
425
|
+
return this;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
setVegetationShader(profile) {
|
|
429
|
+
const report = applyVegetationShader(this.variantTrees, profile);
|
|
430
|
+
// Far LODs are rasterized from variant trees at construction time. Live
|
|
431
|
+
// materials update immediately; hosts that expose runtime style editing
|
|
432
|
+
// should rebuild the forest to bake matching impostors.
|
|
433
|
+
report.requiresImpostorRebake = this.hasBakedImpostors;
|
|
434
|
+
return report;
|
|
435
|
+
}
|
|
436
|
+
|
|
409
437
|
/**
|
|
410
438
|
* Matches the impostors' fog to the environment shader's height fog so far
|
|
411
439
|
* canopies haze with the terrain they stand on. Pass the same
|