@call-me-sensei/toonlab 0.3.0 → 0.4.19
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/README.md +549 -184
- package/agents/README.md +59 -0
- package/agents/references/anime-art-direction.md +24 -0
- package/agents/references/asset-sourcing-policy.md +23 -0
- package/agents/references/custom-gap-report.md +16 -0
- package/agents/references/geology-playbook.md +118 -0
- package/agents/references/mcp-asset-discovery.md +104 -0
- package/agents/references/runtime-entry-points.md +174 -0
- package/agents/references/style-bundles.md +71 -0
- package/agents/skills/claude/asset-sourcing/SKILL.md +275 -0
- package/agents/skills/claude/environment/SKILL.md +59 -0
- package/agents/skills/claude/game-dev/SKILL.md +100 -0
- package/agents/skills/claude/karst-cliff-construction/SKILL.md +258 -0
- package/agents/skills/claude/outdoor-world/SKILL.md +492 -0
- package/agents/skills/claude/outdoor-world/references/coastal-landform-formation.md +100 -0
- package/agents/skills/claude/post-processing/SKILL.md +44 -0
- package/agents/skills/claude/rock-ground-shaders/SKILL.md +118 -0
- package/agents/skills/claude/rockgen/SKILL.md +30 -0
- package/agents/skills/claude/scene-style-application/SKILL.md +74 -0
- package/agents/skills/claude/style-presets/SKILL.md +101 -0
- package/agents/skills/claude/toon-shading/SKILL.md +44 -0
- package/agents/skills/claude/vegetation-sky/SKILL.md +167 -0
- package/agents/skills/claude/visual-verification/SKILL.md +136 -0
- package/agents/skills/claude/water/SKILL.md +105 -0
- package/agents/skills/codex/asset-sourcing/SKILL.md +275 -0
- package/agents/skills/codex/environment/SKILL.md +59 -0
- package/agents/skills/codex/game-dev/SKILL.md +100 -0
- package/agents/skills/codex/karst-cliff-construction/SKILL.md +258 -0
- package/agents/skills/codex/outdoor-world/SKILL.md +492 -0
- package/agents/skills/codex/outdoor-world/references/coastal-landform-formation.md +100 -0
- package/agents/skills/codex/post-processing/SKILL.md +44 -0
- package/agents/skills/codex/rock-ground-shaders/SKILL.md +118 -0
- package/agents/skills/codex/rockgen/SKILL.md +30 -0
- package/agents/skills/codex/scene-style-application/SKILL.md +74 -0
- package/agents/skills/codex/style-presets/SKILL.md +101 -0
- package/agents/skills/codex/toon-shading/SKILL.md +44 -0
- package/agents/skills/codex/vegetation-sky/SKILL.md +167 -0
- package/agents/skills/codex/visual-verification/SKILL.md +136 -0
- package/agents/skills/codex/water/SKILL.md +105 -0
- package/cli/toonlab.mjs +52 -0
- package/compose.yaml +20 -0
- package/database/apply-sql.mjs +141 -0
- package/database/client.mjs +39 -0
- package/database/creation-tags.mjs +23 -0
- package/database/env.mjs +16 -0
- package/database/generation-service.mjs +314 -0
- package/database/migrations/0001_local_workspace.sql +120 -0
- package/database/migrations/0002_file_ownership.sql +11 -0
- package/database/migrations/0003_remove_autosaves_from_library.sql +7 -0
- package/database/migrations/0004_catalog_asset_packs.sql +39 -0
- package/database/migrations/0005_creation_tag_discovery.sql +1 -0
- package/database/migrations/0006_normalize_creation_tags.sql +28 -0
- package/database/providers.mjs +465 -0
- package/database/repository.mjs +625 -0
- package/database/seeds/catalog/0001_empty_official_catalog.sql +4 -0
- package/database/seeds/catalog/0002_2026-08.sql +19454 -0
- package/mcp/lab-management.mjs +629 -0
- package/mcp/public-catalog.mjs +168 -0
- package/mcp/server.mjs +1026 -63
- package/mcp/vite-plugin.mjs +443 -26
- package/mcp/workspace.mjs +26 -1
- package/package.json +312 -45
- package/scripts/generate-catalog-seed.mjs +297 -0
- package/scripts/setup-local.mjs +128 -0
- package/src/agents/index.js +7 -0
- package/src/agents/sceneStyleOperations.js +169 -0
- package/src/asset-policy/catalogLicenses.js +44 -0
- package/src/asset-policy/index.js +315 -0
- package/src/assetlib/assetRef.js +1 -1
- package/src/assetlib/galleryMaterialFamily.js +165 -0
- package/src/assetlib/index.js +6 -2
- package/src/assetlib/plateau.js +188 -0
- package/src/assetlib/plateauLandmarks.js +144 -0
- package/src/assetlib/plateauViewer.js +348 -0
- package/src/assetlib/sources.js +16 -2
- package/src/catalog/manifest.js +11 -1
- package/src/catalog/officialCatalog.js +4 -0
- package/src/catalog/officialCatalogAssetRuntime.js +313 -0
- package/src/catalog/officialCatalogLod.js +150 -0
- package/src/catalog/officialCatalogPlacement.js +228 -0
- package/src/catalog/officialCatalogProvider.js +334 -0
- package/src/character/animationRetarget.js +1082 -0
- package/src/character/characterRuntime.js +376 -0
- package/src/character/groundStabilizer.js +137 -0
- package/src/character/index.js +8 -0
- package/src/character/locomotionActions.js +74 -0
- package/src/character/locomotionStateMachine.js +241 -0
- package/src/character/mannequinAsset.js +15 -0
- package/src/character/mannequinAssetUrl.browser.js +4 -0
- package/src/character/mannequinAssetUrl.node.js +3 -0
- package/src/character/modelLoader.js +92 -12
- package/src/character/walkableCharacterRuntime.js +284 -0
- package/src/character/waterInteractionController.js +217 -0
- package/src/cloud/ambientSkyBaker.js +248 -0
- package/src/cloud/cloudLighting.js +1114 -0
- package/src/cloud/cloudParams.js +819 -0
- package/src/cloud/cloudReprojection.js +563 -0
- package/src/cloud/cloudStyle.js +780 -0
- package/src/cloud/cloudStyleSnapshots.js +387 -0
- package/src/cloud/cloudVolume.js +1903 -0
- package/src/cloud/heroCloudRecipe.js +404 -0
- package/src/cloud/index.js +42 -0
- package/src/cloud/noise/baseShapeVolume.js +331 -0
- package/src/cloud/noise/cirrusMap.js +131 -0
- package/src/cloud/noise/curlNoise.js +289 -0
- package/src/cloud/noise/erosionVolume.js +188 -0
- package/src/cloud/noise/noiseVolume.js +202 -0
- package/src/cloud/noise/periodicNoise3.js +295 -0
- package/src/cloud/noise/weatherMap.js +470 -0
- package/src/cloud/paramSchema.js +458 -0
- package/src/collisionMetadata.js +320 -0
- package/src/core/systemStylePolicy.js +32 -0
- package/src/environment/dayCurves.js +146 -0
- package/src/environment/environmentGroundFieldPass.js +354 -0
- package/src/environment/environmentMaterialAdapter.js +114 -6
- package/src/environment/environmentPresets.js +396 -90
- package/src/environment/environmentRigs.js +17 -2
- package/src/environment/environmentSettings.js +37 -1
- package/src/environment/environmentShaderMaterials.js +37 -6
- package/src/environment/environmentState.js +133 -0
- package/src/environment/environmentSunShadowPass.js +357 -6
- package/src/environment/environmentTextureResolver.js +7 -0
- package/src/environment/index.js +51 -0
- package/src/environment/manufacturedMaterialContract.js +837 -0
- package/src/environment/manufacturedReflectionProvider.js +114 -0
- package/src/environment/scanAssetStylize.js +4 -4
- package/src/environment/surfaceMaterialModes.js +71 -0
- package/src/environment/toonLabEnvironmentMaterials.js +353 -0
- package/src/environment/toonLabMaterialPassCoupling.js +347 -0
- package/src/environment/toonLabNormalIntegration.js +171 -0
- package/src/environment/toonLabRockMaterialResolver.js +592 -0
- package/src/environment/toonLabSourceDefaultLit.js +444 -0
- package/src/environment/toonLabSourceLibrary.js +762 -0
- package/src/environment/toonLabSourceMaterials.js +3718 -0
- package/src/environment/toonLabSourceSubsurfaceLighting.js +415 -0
- package/src/environment/toonLabSourceTemporal.js +717 -0
- package/src/environment/toonLabSurfaceLighting.js +364 -0
- package/src/environment/toonLabTextureReadiness.js +105 -0
- package/src/environment/toonLabTreeMaterials.js +450 -0
- package/src/environment/transparentMaterialProfile.js +87 -0
- package/src/environment/urbanPropMaterial.js +2874 -0
- package/src/ground-shader/groundPrintLayer.js +375 -0
- package/src/ground-shader/groundShaderMaterial.js +851 -0
- package/src/ground-shader/groundShaderSettings.js +468 -0
- package/src/ground-shader/index.js +3 -0
- package/src/index.js +52 -22
- package/src/lighting/callMeSenseiLightingContract.js +163 -0
- package/src/lighting/index.js +14 -7
- package/src/lighting/lightingCapabilities.js +2 -2
- package/src/lighting/lightingPresets.js +6 -3
- package/src/lighting/lightingStyle.js +41 -6
- package/src/lighting/lightingSystem.js +140 -1
- package/src/lighting/{unrealExport.js → toonLabExport.js} +40 -41
- package/src/post/postProcessing.js +71 -12
- package/src/react/index.js +66 -0
- package/src/renderer/index.js +9 -0
- package/src/renderer/rendererConfiguration.js +250 -0
- package/src/rock-shader/index.js +3 -0
- package/src/rock-shader/rockMaterial.js +1843 -0
- package/src/rock-shader/rockShaderRuntime.js +494 -0
- package/src/rock-shader/rockShaderSettings.js +869 -0
- package/src/rockgen/export/glbExport.js +104 -14
- package/src/rockgen/index.js +4 -3
- package/src/rockgen/lod/index.js +6 -0
- package/src/rockgen/lod/rockLodMetrics.js +168 -0
- package/src/rockgen/lod/rockLodPlanner.js +372 -0
- package/src/rockgen/lod/rockLodPolicy.js +235 -0
- package/src/rockgen/lod/rockLodRuntime.js +124 -0
- package/src/rockgen/lod/rockLodSimplifier.js +173 -0
- package/src/rockgen/lod/rockLodValidation.js +113 -0
- package/src/rockgen/mesh/meshAttributes.js +17 -0
- package/src/rockgen/mesh/meshDocument.js +6 -0
- package/src/rockgen/rockDocument.js +352 -9
- package/src/rockgen/rockgenPresets.js +114 -13
- package/src/rockgen/rockgenSettings.js +62 -11
- package/src/runtime/index.js +14 -0
- package/src/runtime/sceneCollisionRuntime.js +317 -0
- package/src/runtime/sceneSurfaceRuntime.js +451 -0
- package/src/runtime/sceneUpdateScheduler.js +203 -0
- package/src/shaders-tsl/anime.js +9 -2
- package/src/shaders-tsl/chunks/environment-ground-field.js +174 -0
- package/src/shaders-tsl/chunks/environment-state.js +79 -0
- package/src/shaders-tsl/chunks/environment-sun-shadow.js +99 -32
- package/src/shaders-tsl/chunks/normalized-hue.js +41 -0
- package/src/shaders-tsl/chunks/pass-depth-color.js +4 -2
- package/src/shaders-tsl/chunks/scene-depth-color-pass.js +273 -0
- package/src/shaders-tsl/chunks/vegetation-style.js +116 -8
- package/src/shaders-tsl/chunks/water-color.js +19 -5
- package/src/shaders-tsl/chunks/water-shore-state.js +8 -1
- package/src/shaders-tsl/chunks/world-noise.js +30 -0
- package/src/shaders-tsl/environment.js +123 -17
- package/src/shaders-tsl/flower.js +51 -8
- package/src/shaders-tsl/grass.js +194 -29
- package/src/shaders-tsl/post-composite.js +83 -2
- package/src/shaders-tsl/tree-leaf.js +107 -16
- package/src/shaders-tsl/water-breaker.js +18 -4
- package/src/shaders-tsl/water.js +43 -3
- package/src/shaders-tsl/woody-surface.js +59 -7
- package/src/sky/atmosphereDome.js +193 -0
- package/src/sky/atmosphereParams.js +396 -0
- package/src/sky/atmosphereScattering.js +593 -0
- package/src/sky/atmosphereSky.js +371 -0
- package/src/sky/cloudShadow.js +355 -0
- package/src/sky/godRays.js +257 -0
- package/src/sky/index.js +55 -1
- package/src/sky/nightSky.js +1190 -0
- package/src/sky/renderLayers.js +120 -0
- package/src/sky/skyColor.js +582 -0
- package/src/sky/skyDayCycle.js +244 -0
- package/src/sky/skyParams.js +661 -0
- package/src/sky/skyPresets.js +772 -0
- package/src/sky/skyQualityTiers.js +383 -0
- package/src/sky/skyShaderSettings.js +699 -0
- package/src/sky/skyStyleSnapshots.js +211 -0
- package/src/sky/skySystem.js +1438 -0
- package/src/sky/skyTimeKeyframes.js +361 -0
- package/src/sky/stylizedSky.js +405 -116
- package/src/sky/sunDriver.js +499 -0
- package/src/sky/timeOfDay.js +335 -0
- package/src/styles/animeGameProfile.js +44 -0
- package/src/styles/index.js +134 -0
- package/src/styles/manufacturedStyleLabeling.js +204 -0
- package/src/styles/sceneLayerDocuments.js +185 -0
- package/src/styles/sceneLookComposition.js +156 -0
- package/src/styles/sceneQualityApplication.js +152 -0
- package/src/styles/sceneQualityProfiles.js +268 -0
- package/src/styles/sceneStyleAudit.js +512 -0
- package/src/styles/sceneStyleRuntime.js +876 -0
- package/src/styles/styleAdapters.js +166 -0
- package/src/styles/styleApplication.js +369 -0
- package/src/styles/styleBundle.js +444 -91
- package/src/styles/styleBundleProvider.js +83 -0
- package/src/styles/styleDomains.js +21 -0
- package/src/styles/styleInspector.js +262 -0
- package/src/styles/styleMaterialContract.js +375 -0
- package/src/styles/styleMetadata.js +73 -0
- package/src/styles/styleTargetDiscovery.js +162 -0
- package/src/styles/styleTargetLabels.js +206 -0
- package/src/styles/styleTargetMaterialCoverage.js +137 -0
- package/src/styles/styleTransaction.js +272 -0
- package/src/texgen/textureGenerators.js +21 -5
- package/src/toon/toonSettings.js +4 -0
- package/src/vegetation/branchTree.js +302 -0
- package/src/vegetation/callMeSenseiGrass.js +183 -0
- package/src/vegetation/compiledTree.js +506 -0
- package/src/vegetation/contactShadowField.js +107 -0
- package/src/vegetation/flowerSpecies.js +10 -2
- package/src/vegetation/grass.js +13 -0
- package/src/vegetation/grassClump.js +1179 -0
- package/src/vegetation/importedVegetationMaterial.js +183 -0
- package/src/vegetation/index.js +15 -1
- package/src/vegetation/legacyTreePresets.js +120 -0
- package/src/vegetation/scatter.js +322 -3
- package/src/vegetation/stylizedBush.js +14 -0
- package/src/vegetation/stylizedFlower.js +31 -0
- package/src/vegetation/stylizedFlowers.js +59 -7
- package/src/vegetation/stylizedForest.js +455 -147
- package/src/vegetation/stylizedGrass.js +188 -24
- package/src/vegetation/stylizedTree.js +378 -46
- package/src/vegetation/stylizedTreeFoliage.js +889 -38
- package/src/vegetation/stylizedUnderstory.js +230 -0
- package/src/vegetation/treeExport.js +262 -47
- package/src/vegetation/treeSurfaceTextures.js +337 -0
- package/src/vegetation/vegetationShaders.js +617 -28
- package/src/version.js +3 -0
- package/src/water/water.js +2 -0
- package/src/water/waterBreakerSystem.js +2 -0
- package/src/water/waterCurrentField.js +1 -0
- package/src/water/waterMaterial.js +3 -0
- package/src/water/waterRain.js +2 -0
- package/src/water/waterScenePasses.js +170 -7
- package/src/water/waterSettings.js +235 -43
- package/src/water/waterShoreMaterial.js +16 -2
- package/src/water/waterShoreStateField.js +1 -1
- package/src/water/waterSplashSystem.js +2 -0
- package/src/water/waterStageSettings.js +60 -0
- package/src/water/waterSurface.js +144 -4
- package/src/water/waterUnderwaterAtmosphere.js +288 -0
- package/src/water/waterVegetation.js +20 -4
- package/src/worldCollision.js +64 -9
- package/types/agents/index.d.ts +1 -0
- package/types/agents/sceneStyleOperations.d.ts +484 -0
- package/types/asset-policy/catalogLicenses.d.ts +5 -0
- package/types/asset-policy/index.d.ts +18 -0
- package/types/assetlib/ambientcg.d.ts +81 -0
- package/types/assetlib/assetRef.d.ts +26 -0
- package/types/assetlib/galleryMaterialFamily.d.ts +13 -0
- package/types/assetlib/importedEntry.d.ts +18 -0
- package/types/assetlib/index.d.ts +16 -0
- package/types/assetlib/kaykit.d.ts +112 -0
- package/types/assetlib/kaykitStaticIndex.d.ts +38 -0
- package/types/assetlib/loadImported.d.ts +54 -0
- package/types/assetlib/opensource3d.d.ts +55 -0
- package/types/assetlib/plateau.d.ts +67 -0
- package/types/assetlib/plateauLandmarks.d.ts +238 -0
- package/types/assetlib/plateauViewer.d.ts +3 -0
- package/types/assetlib/polyhaven.d.ts +90 -0
- package/types/assetlib/polypizza.d.ts +10 -0
- package/types/assetlib/smithsonian.d.ts +9 -0
- package/types/assetlib/sources.d.ts +22 -0
- package/types/assetlib/zip.d.ts +8 -0
- package/types/catalog/manifest.d.ts +26 -0
- package/types/catalog/officialCatalog.d.ts +4 -0
- package/types/catalog/officialCatalogAssetRuntime.d.ts +2 -0
- package/types/catalog/officialCatalogLod.d.ts +5 -0
- package/types/catalog/officialCatalogPlacement.d.ts +49 -0
- package/types/catalog/officialCatalogProvider.d.ts +7 -0
- package/types/character/animationRetarget.d.ts +20 -0
- package/types/character/characterRig.d.ts +28 -0
- package/types/character/characterRuntime.d.ts +4 -0
- package/types/character/freestyleSwimClip.d.ts +5 -0
- package/types/character/groundStabilizer.d.ts +55 -0
- package/types/character/index.d.ts +10 -0
- package/types/character/locomotionActions.d.ts +4 -0
- package/types/character/locomotionStateMachine.d.ts +62 -0
- package/types/character/mannequinAsset.d.ts +12 -0
- package/types/character/mannequinAssetUrl.node.d.ts +1 -0
- package/types/character/modelLoader.d.ts +7 -0
- package/types/character/walkableCharacterRuntime.d.ts +343 -0
- package/types/character/waterInteractionController.d.ts +114 -0
- package/types/cloud/ambientSkyBaker.d.ts +18 -0
- package/types/cloud/cloudLighting.d.ts +38 -0
- package/types/cloud/cloudParams.d.ts +18 -0
- package/types/cloud/cloudReprojection.d.ts +15 -0
- package/types/cloud/cloudStyle.d.ts +1380 -0
- package/types/cloud/cloudStyleSnapshots.d.ts +10 -0
- package/types/cloud/cloudVolume.d.ts +43 -0
- package/types/cloud/heroCloudRecipe.d.ts +167 -0
- package/types/cloud/index.d.ts +12 -0
- package/types/cloud/noise/baseShapeVolume.d.ts +86 -0
- package/types/cloud/noise/cirrusMap.d.ts +24 -0
- package/types/cloud/noise/curlNoise.d.ts +106 -0
- package/types/cloud/noise/erosionVolume.d.ts +58 -0
- package/types/cloud/noise/noiseVolume.d.ts +63 -0
- package/types/cloud/noise/periodicNoise3.d.ts +75 -0
- package/types/cloud/noise/weatherMap.d.ts +227 -0
- package/types/cloud/paramSchema.d.ts +142 -0
- package/types/collisionMetadata.d.ts +11 -0
- package/types/core/generation.d.ts +95 -0
- package/types/core/materialRoles.d.ts +102 -0
- package/types/core/presetDocuments.d.ts +25 -0
- package/types/core/systemStylePolicy.d.ts +4 -0
- package/types/environment/dayCurves.d.ts +47 -0
- package/types/environment/environmentAmbientProbe.d.ts +2 -0
- package/types/environment/environmentGroundFieldPass.d.ts +2 -0
- package/types/environment/environmentMaterialAdapter.d.ts +42 -0
- package/types/environment/environmentMaterialClassifier.d.ts +26 -0
- package/types/environment/environmentPlanarReflection.d.ts +3 -0
- package/types/environment/environmentPresets.d.ts +171 -0
- package/types/environment/environmentRigs.d.ts +13 -0
- package/types/environment/environmentSettings.d.ts +161 -0
- package/types/environment/environmentShaderMaterials.d.ts +14 -0
- package/types/environment/environmentState.d.ts +6 -0
- package/types/environment/environmentSunShadowPass.d.ts +2 -0
- package/types/environment/environmentTextureResolver.d.ts +30 -0
- package/types/environment/environmentTimeOfDay.d.ts +25 -0
- package/types/environment/environmentVertexAo.d.ts +18 -0
- package/types/environment/index.d.ts +27 -0
- package/types/environment/manufacturedMaterialContract.d.ts +129 -0
- package/types/environment/manufacturedReflectionProvider.d.ts +3 -0
- package/types/environment/scanAssetStylize.d.ts +43 -0
- package/types/environment/surfaceMaterialModes.d.ts +14 -0
- package/types/environment/toonLabEnvironmentMaterials.d.ts +139 -0
- package/types/environment/toonLabMaterialPassCoupling.d.ts +7 -0
- package/types/environment/toonLabNormalIntegration.d.ts +29 -0
- package/types/environment/toonLabRockMaterialResolver.d.ts +270 -0
- package/types/environment/toonLabSourceDefaultLit.d.ts +136 -0
- package/types/environment/toonLabSourceLibrary.d.ts +19 -0
- package/types/environment/toonLabSourceMaterials.d.ts +14 -0
- package/types/environment/toonLabSourceSubsurfaceLighting.d.ts +85 -0
- package/types/environment/toonLabSourceTemporal.d.ts +20 -0
- package/types/environment/toonLabSurfaceLighting.d.ts +136 -0
- package/types/environment/toonLabTextureReadiness.d.ts +8 -0
- package/types/environment/toonLabTreeMaterials.d.ts +7 -0
- package/types/environment/transparentMaterialProfile.d.ts +76 -0
- package/types/environment/urbanPropMaterial.d.ts +25 -0
- package/types/ground-shader/groundPrintLayer.d.ts +4 -0
- package/types/ground-shader/groundShaderMaterial.d.ts +11 -0
- package/types/ground-shader/groundShaderSettings.d.ts +90 -0
- package/types/ground-shader/index.d.ts +3 -0
- package/types/index.d.ts +1502 -0
- package/types/lighting/callMeSenseiLightingContract.d.ts +14 -0
- package/types/lighting/colorIntensity.d.ts +44 -0
- package/types/lighting/index.d.ts +12 -0
- package/types/lighting/lightDescriptors.d.ts +803 -0
- package/types/lighting/lightingCapabilities.d.ts +85 -0
- package/types/lighting/lightingDocuments.d.ts +140 -0
- package/types/lighting/lightingFixtures.d.ts +171 -0
- package/types/lighting/lightingGenerator.d.ts +403 -0
- package/types/lighting/lightingPresets.d.ts +264 -0
- package/types/lighting/lightingRuntime.d.ts +401 -0
- package/types/lighting/lightingStyle.d.ts +156 -0
- package/types/lighting/lightingSystem.d.ts +433 -0
- package/types/lighting/toonLabExport.d.ts +46 -0
- package/types/lighting/utils.d.ts +18 -0
- package/types/loaders/index.d.ts +1 -0
- package/types/post/index.d.ts +2 -0
- package/types/post/postGenerator.d.ts +282 -0
- package/types/post/postProcessing.d.ts +16 -0
- package/types/react/index.d.ts +1765 -0
- package/types/renderer/index.d.ts +1 -0
- package/types/renderer/rendererConfiguration.d.ts +8 -0
- package/types/rock-shader/index.d.ts +3 -0
- package/types/rock-shader/rockMaterial.d.ts +18 -0
- package/types/rock-shader/rockShaderRuntime.d.ts +8 -0
- package/types/rock-shader/rockShaderSettings.d.ts +170 -0
- package/types/rockgen/export/glbExport.d.ts +58 -0
- package/types/rockgen/heightfield/heightfieldErosion.d.ts +10 -0
- package/types/rockgen/heightfield/heightfieldPatch.d.ts +15 -0
- package/types/rockgen/heightfield/stylizedErosionSim.d.ts +41 -0
- package/types/rockgen/index.d.ts +11 -0
- package/types/rockgen/lod/index.d.ts +6 -0
- package/types/rockgen/lod/rockLodMetrics.d.ts +62 -0
- package/types/rockgen/lod/rockLodPlanner.d.ts +86 -0
- package/types/rockgen/lod/rockLodPolicy.d.ts +76 -0
- package/types/rockgen/lod/rockLodRuntime.d.ts +95 -0
- package/types/rockgen/lod/rockLodSimplifier.d.ts +15 -0
- package/types/rockgen/lod/rockLodValidation.d.ts +16 -0
- package/types/rockgen/mesh/meshAttributes.d.ts +32 -0
- package/types/rockgen/mesh/meshDocument.d.ts +40 -0
- package/types/rockgen/mesh/surfaceNets.d.ts +42 -0
- package/types/rockgen/noise/cellularNoise3.d.ts +24 -0
- package/types/rockgen/noise/prng.d.ts +16 -0
- package/types/rockgen/noise/simplexNoise3.d.ts +2 -0
- package/types/rockgen/noise/valueNoise3.d.ts +12 -0
- package/types/rockgen/rockDocument.d.ts +215 -0
- package/types/rockgen/rockHelpers.d.ts +2 -0
- package/types/rockgen/rockgenPresets.d.ts +10 -0
- package/types/rockgen/rockgenSettings.d.ts +531 -0
- package/types/rockgen/sdf/fieldCompiler.d.ts +20 -0
- package/types/rockgen/sdf/sculptEdits.d.ts +30 -0
- package/types/rockgen/sdf/sdfModifiers.d.ts +19 -0
- package/types/rockgen/sdf/sdfOps.d.ts +8 -0
- package/types/rockgen/sdf/sdfPrimitives.d.ts +22 -0
- package/types/runtime/index.d.ts +3 -0
- package/types/runtime/sceneCollisionRuntime.d.ts +94 -0
- package/types/runtime/sceneSurfaceRuntime.d.ts +90 -0
- package/types/runtime/sceneUpdateScheduler.d.ts +28 -0
- package/types/shaders-tsl/anime.d.ts +9 -0
- package/types/shaders-tsl/chunks/character-color.d.ts +6 -0
- package/types/shaders-tsl/chunks/character-highlights.d.ts +12 -0
- package/types/shaders-tsl/chunks/character-lighting.d.ts +20 -0
- package/types/shaders-tsl/chunks/character-material-maps.d.ts +18 -0
- package/types/shaders-tsl/chunks/character-roles.d.ts +21 -0
- package/types/shaders-tsl/chunks/character-scene-lights.d.ts +48 -0
- package/types/shaders-tsl/chunks/character-shadow-color.d.ts +5 -0
- package/types/shaders-tsl/chunks/character-skinning.d.ts +23 -0
- package/types/shaders-tsl/chunks/environment-color.d.ts +9 -0
- package/types/shaders-tsl/chunks/environment-debug.d.ts +24 -0
- package/types/shaders-tsl/chunks/environment-ground-field.d.ts +40 -0
- package/types/shaders-tsl/chunks/environment-lighting.d.ts +22 -0
- package/types/shaders-tsl/chunks/environment-state.d.ts +42 -0
- package/types/shaders-tsl/chunks/environment-sun-shadow.d.ts +19 -0
- package/types/shaders-tsl/chunks/foliage-fog.d.ts +21 -0
- package/types/shaders-tsl/chunks/normalized-hue.d.ts +1 -0
- package/types/shaders-tsl/chunks/pass-depth-color.d.ts +20 -0
- package/types/shaders-tsl/chunks/projected-water-caustics.d.ts +24 -0
- package/types/shaders-tsl/chunks/scene-depth-color-pass.d.ts +39 -0
- package/types/shaders-tsl/chunks/stylized-cloud-shadow.d.ts +9 -0
- package/types/shaders-tsl/chunks/vegetation-style.d.ts +60 -0
- package/types/shaders-tsl/chunks/water-color.d.ts +15 -0
- package/types/shaders-tsl/chunks/water-common.d.ts +9 -0
- package/types/shaders-tsl/chunks/water-foam.d.ts +8 -0
- package/types/shaders-tsl/chunks/water-lighting.d.ts +9 -0
- package/types/shaders-tsl/chunks/water-ripple.d.ts +8 -0
- package/types/shaders-tsl/chunks/water-shore-state.d.ts +7 -0
- package/types/shaders-tsl/chunks/water-waves.d.ts +18 -0
- package/types/shaders-tsl/chunks/world-noise.d.ts +4 -0
- package/types/shaders-tsl/environment-ao-overlay.d.ts +5 -0
- package/types/shaders-tsl/environment.d.ts +34 -0
- package/types/shaders-tsl/flower.d.ts +6 -0
- package/types/shaders-tsl/grass.d.ts +4 -0
- package/types/shaders-tsl/post-composite.d.ts +25 -0
- package/types/shaders-tsl/sky.d.ts +4 -0
- package/types/shaders-tsl/tree-leaf.d.ts +2 -0
- package/types/shaders-tsl/water-breaker.d.ts +15 -0
- package/types/shaders-tsl/water-kelp.d.ts +5 -0
- package/types/shaders-tsl/water-rain.d.ts +10 -0
- package/types/shaders-tsl/water-shore-state-simulation.d.ts +12 -0
- package/types/shaders-tsl/water-simulation.d.ts +5 -0
- package/types/shaders-tsl/water-splash.d.ts +12 -0
- package/types/shaders-tsl/water.d.ts +22 -0
- package/types/shaders-tsl/woody-surface.d.ts +3 -0
- package/types/sky/atmosphereDome.d.ts +2 -0
- package/types/sky/atmosphereParams.d.ts +185 -0
- package/types/sky/atmosphereScattering.d.ts +11 -0
- package/types/sky/atmosphereSky.d.ts +2 -0
- package/types/sky/cloudShadow.d.ts +68 -0
- package/types/sky/godRays.d.ts +5 -0
- package/types/sky/index.d.ts +18 -0
- package/types/sky/nightSky.d.ts +22 -0
- package/types/sky/renderLayers.d.ts +59 -0
- package/types/sky/sceneOverrideLayers.d.ts +10 -0
- package/types/sky/skyColor.d.ts +704 -0
- package/types/sky/skyDayCycle.d.ts +86 -0
- package/types/sky/skyParams.d.ts +3407 -0
- package/types/sky/skyPresets.d.ts +160 -0
- package/types/sky/skyQuality.d.ts +21 -0
- package/types/sky/skyQualityTiers.d.ts +223 -0
- package/types/sky/skyShaderSettings.d.ts +152 -0
- package/types/sky/skyStyleSnapshots.d.ts +11 -0
- package/types/sky/skySystem.d.ts +3 -0
- package/types/sky/skyTimeKeyframes.d.ts +230 -0
- package/types/sky/stylizedSky.d.ts +341 -0
- package/types/sky/sunDriver.d.ts +15 -0
- package/types/sky/timeOfDay.d.ts +145 -0
- package/types/styles/animeGameProfile.d.ts +27 -0
- package/types/styles/index.d.ts +17 -0
- package/types/styles/manufacturedStyleLabeling.d.ts +119 -0
- package/types/styles/sceneLayerDocuments.d.ts +145 -0
- package/types/styles/sceneLookComposition.d.ts +53 -0
- package/types/styles/sceneQualityApplication.d.ts +34 -0
- package/types/styles/sceneQualityProfiles.d.ts +13 -0
- package/types/styles/sceneStyleAudit.d.ts +80 -0
- package/types/styles/sceneStyleRuntime.d.ts +1782 -0
- package/types/styles/styleAdapters.d.ts +14 -0
- package/types/styles/styleApplication.d.ts +47 -0
- package/types/styles/styleBundle.d.ts +19 -0
- package/types/styles/styleBundleProvider.d.ts +44 -0
- package/types/styles/styleDomains.d.ts +18 -0
- package/types/styles/styleInspector.d.ts +59 -0
- package/types/styles/styleMaterialContract.d.ts +46 -0
- package/types/styles/styleMetadata.d.ts +11 -0
- package/types/styles/styleTargetDiscovery.d.ts +48 -0
- package/types/styles/styleTargetLabels.d.ts +32 -0
- package/types/styles/styleTargetMaterialCoverage.d.ts +20 -0
- package/types/styles/styleTransaction.d.ts +10 -0
- package/types/styles/styleTypes.d.ts +66 -0
- package/types/texgen/evaluateTexture.d.ts +40 -0
- package/types/texgen/index.d.ts +7 -0
- package/types/texgen/noise2.d.ts +46 -0
- package/types/texgen/textureAi.d.ts +6 -0
- package/types/texgen/textureGenerators.d.ts +261 -0
- package/types/texgen/texturePresets.d.ts +45 -0
- package/types/texgen/textureSettings.d.ts +121 -0
- package/types/texgen/textureThree.d.ts +13 -0
- package/types/toon/characterRenderPasses.d.ts +3 -0
- package/types/toon/index.d.ts +3 -0
- package/types/toon/settings/alphaSettings.d.ts +125 -0
- package/types/toon/settings/averageShadowSettings.d.ts +39 -0
- package/types/toon/settings/baseTextureSettings.d.ts +39 -0
- package/types/toon/settings/celShadeSettings.d.ts +37 -0
- package/types/toon/settings/contactShadowSettings.d.ts +30 -0
- package/types/toon/settings/eyeHighlightSettings.d.ts +55 -0
- package/types/toon/settings/faceLightingSettings.d.ts +32 -0
- package/types/toon/settings/furSettings.d.ts +23 -0
- package/types/toon/settings/glitterSettings.d.ts +43 -0
- package/types/toon/settings/hairHighlightSettings.d.ts +89 -0
- package/types/toon/settings/indirectLightSettings.d.ts +43 -0
- package/types/toon/settings/localLightSettings.d.ts +46 -0
- package/types/toon/settings/materialMapSettings.d.ts +86 -0
- package/types/toon/settings/outlineSettings.d.ts +125 -0
- package/types/toon/settings/perspectiveRemovalSettings.d.ts +14 -0
- package/types/toon/settings/rimLightSettings.d.ts +79 -0
- package/types/toon/settings/sceneShadowSettings.d.ts +32 -0
- package/types/toon/settings/selfShadowSettings.d.ts +44 -0
- package/types/toon/settings/shadowColorSettings.d.ts +77 -0
- package/types/toon/settings/skinToneSettings.d.ts +30 -0
- package/types/toon/settings/specularSettings.d.ts +96 -0
- package/types/toon/settings/stickerSettings.d.ts +40 -0
- package/types/toon/toonMaterialAdapter.d.ts +883 -0
- package/types/toon/toonSettings.d.ts +1182 -0
- package/types/vegetation/branchTree.d.ts +10 -0
- package/types/vegetation/callMeSenseiGrass.d.ts +8 -0
- package/types/vegetation/compiledTree.d.ts +75 -0
- package/types/vegetation/contactShadowField.d.ts +26 -0
- package/types/vegetation/flowerSpecies.d.ts +107 -0
- package/types/vegetation/grass.d.ts +4 -0
- package/types/vegetation/grassClump.d.ts +7 -0
- package/types/vegetation/grassPalettes.d.ts +29 -0
- package/types/vegetation/importedVegetationMaterial.d.ts +13 -0
- package/types/vegetation/index.d.ts +216 -0
- package/types/vegetation/legacyTreePresets.d.ts +22 -0
- package/types/vegetation/scatter.d.ts +12 -0
- package/types/vegetation/stylizedBush.d.ts +2 -0
- package/types/vegetation/stylizedFlower.d.ts +2 -0
- package/types/vegetation/stylizedFlowers.d.ts +8 -0
- package/types/vegetation/stylizedForest.d.ts +3 -0
- package/types/vegetation/stylizedGrass.d.ts +21 -0
- package/types/vegetation/stylizedTree.d.ts +19 -0
- package/types/vegetation/stylizedTreeFoliage.d.ts +18 -0
- package/types/vegetation/stylizedUnderstory.d.ts +50 -0
- package/types/vegetation/treeExport.d.ts +6 -0
- package/types/vegetation/treeSurfaceTextures.d.ts +72 -0
- package/types/vegetation/vegetationShaders.d.ts +74 -0
- package/types/version.d.ts +1 -0
- package/types/water/index.d.ts +1 -0
- package/types/water/sceneOverrideLayers.d.ts +16 -0
- package/types/water/water.d.ts +17 -0
- package/types/water/waterBreakerSystem.d.ts +46 -0
- package/types/water/waterCurrentField.d.ts +115 -0
- package/types/water/waterInteraction.d.ts +21 -0
- package/types/water/waterMaterial.d.ts +60 -0
- package/types/water/waterNearshorePhase.d.ts +5 -0
- package/types/water/waterRain.d.ts +17 -0
- package/types/water/waterRippleSimulation.d.ts +52 -0
- package/types/water/waterScenePasses.d.ts +70 -0
- package/types/water/waterSettings.d.ts +648 -0
- package/types/water/waterShoreMaterial.d.ts +3 -0
- package/types/water/waterShoreStateField.d.ts +2 -0
- package/types/water/waterSplashSystem.d.ts +2 -0
- package/types/water/waterStageSettings.d.ts +9 -0
- package/types/water/waterSurface.d.ts +2 -0
- package/types/water/waterUnderwaterAtmosphere.d.ts +103 -0
- package/types/water/waterVegetation.d.ts +16 -0
- package/types/worldCollision.d.ts +22 -0
- package/AGENTS.md +0 -254
- package/ATTRIBUTION.md +0 -78
- package/docs/characters.md +0 -144
- package/docs/debug-panel.md +0 -126
- package/docs/docs.css +0 -589
- package/docs/environment.md +0 -186
- package/docs/getting-started.md +0 -180
- package/docs/index.html +0 -14
- package/docs/lab-architecture.md +0 -100
- package/docs/lighting.md +0 -825
- package/docs/main.jsx +0 -739
- package/docs/mcp.md +0 -97
- package/docs/post-processing.md +0 -98
- package/docs/settings-reference.md +0 -1878
- package/docs/shader-constants.md +0 -77
- package/docs/sky.md +0 -182
- package/docs/style-labs.md +0 -309
- package/docs/texture-lab.md +0 -135
- package/docs/toon-shading.md +0 -183
- package/docs/tsl-conventions.md +0 -167
- package/docs/vegetation-sky.md +0 -275
- package/docs/water.md +0 -430
- package/docs/weather.md +0 -200
- package/docs/world-scale.md +0 -111
- package/mcp/style-lab-tools.mjs +0 -371
- package/src/ambientfx/INTEGRATION.md +0 -164
- package/src/ambientfx/ambientFxPresets.js +0 -83
- package/src/ambientfx/ambientFxSettings.js +0 -368
- package/src/ambientfx/emitters.js +0 -169
- package/src/ambientfx/index.js +0 -5
- package/src/ambientfx/particleBackbone.js +0 -493
- package/src/ambientfx/stylizedAmbientFx.js +0 -450
- package/src/biome/biomeGenerator.js +0 -385
- package/src/biome/biomeRuntime.js +0 -299
- package/src/biome/index.js +0 -2
- package/src/buildinggen/buildingAsset.js +0 -44
- package/src/buildinggen/buildingGrammar.js +0 -311
- package/src/buildinggen/buildingMesh.js +0 -451
- package/src/buildinggen/buildingPresets.js +0 -46
- package/src/buildinggen/buildingRecipe.js +0 -100
- package/src/buildinggen/buildingSettings.js +0 -238
- package/src/buildinggen/index.js +0 -6
- package/src/camera/cameraDirector.js +0 -157
- package/src/camera/cameraGenerator.js +0 -367
- package/src/camera/cameraRig.js +0 -570
- package/src/camera/cameraSettings.js +0 -236
- package/src/camera/index.js +0 -7
- package/src/catalog/builtinEntries.js +0 -245
- package/src/catalog/catalog.js +0 -210
- package/src/catalog/index.js +0 -3
- package/src/core/shaderBackend.js +0 -24
- package/src/debrisgen/debrisFields.js +0 -544
- package/src/debrisgen/debrisGenerator.js +0 -1929
- package/src/debrisgen/debrisPalettes.js +0 -71
- package/src/debrisgen/debrisPhysics.js +0 -198
- package/src/debrisgen/debrisPresets.js +0 -162
- package/src/debrisgen/debrisSettings.js +0 -333
- package/src/debrisgen/debrisTextures.js +0 -380
- package/src/debrisgen/index.js +0 -5
- package/src/debug/fieldValues.js +0 -95
- package/src/debug/index.js +0 -7
- package/src/debug/settingsPanel.js +0 -170
- package/src/fauna/INTEGRATION.md +0 -174
- package/src/fauna/boids.js +0 -861
- package/src/fauna/faunaBodies.js +0 -492
- package/src/fauna/faunaPresets.js +0 -52
- package/src/fauna/faunaSettings.js +0 -525
- package/src/fauna/index.js +0 -5
- package/src/fauna/stylizedFauna.js +0 -395
- package/src/game-feel/gameFeelGenerator.js +0 -402
- package/src/game-feel/gameFeelRuntime.js +0 -549
- package/src/game-feel/index.js +0 -2
- package/src/motion/index.js +0 -5
- package/src/motion/motionClip.js +0 -441
- package/src/motion/motionController.js +0 -628
- package/src/motion/motionDocuments.js +0 -225
- package/src/motion/motionGraph.js +0 -307
- package/src/motion/motionSettings.js +0 -222
- package/src/pathgen/index.js +0 -7
- package/src/pathgen/pathBridge.js +0 -232
- package/src/pathgen/pathPresets.js +0 -35
- package/src/pathgen/pathRibbon.js +0 -410
- package/src/pathgen/pathRouter.js +0 -380
- package/src/pathgen/pathSettings.js +0 -335
- package/src/pathgen/pathTextures.js +0 -123
- package/src/pathgen/stylizedPaths.js +0 -453
- package/src/propgen/generatorsWave1.js +0 -379
- package/src/propgen/generatorsWave2.js +0 -462
- package/src/propgen/index.js +0 -5
- package/src/propgen/propAsset.js +0 -323
- package/src/propgen/propParts.js +0 -170
- package/src/propgen/propPlacement.js +0 -459
- package/src/propgen/propPresets.js +0 -82
- package/src/propgen/propSettings.js +0 -395
- package/src/soundscape/index.js +0 -4
- package/src/soundscape/soundscapeGenerator.js +0 -179
- package/src/soundscape/soundscapeRuntime.js +0 -806
- package/src/soundscape/soundscapeSettings.js +0 -292
- package/src/stylizedTerrain.js +0 -631
- package/src/stylizedWorld.js +0 -903
- package/src/vegetation/treeRecipe.js +0 -647
- package/src/vfxgen/INTEGRATION.md +0 -145
- package/src/vfxgen/core/burstBackbone.js +0 -380
- package/src/vfxgen/core/projectileCore.js +0 -92
- package/src/vfxgen/core/spriteShapes.js +0 -98
- package/src/vfxgen/core/trailRibbon.js +0 -272
- package/src/vfxgen/core/vfxRandom.js +0 -29
- package/src/vfxgen/effects/emitHelpers.js +0 -37
- package/src/vfxgen/effects/magicEffects.js +0 -162
- package/src/vfxgen/effects/movementEffects.js +0 -87
- package/src/vfxgen/effects/weaponEffects.js +0 -118
- package/src/vfxgen/index.js +0 -18
- package/src/vfxgen/moves/moveController.js +0 -146
- package/src/vfxgen/moves/moveLibrary.js +0 -335
- package/src/vfxgen/vfxPresets.js +0 -98
- package/src/vfxgen/vfxSettings.js +0 -384
- package/src/vfxgen/vfxSystem.js +0 -449
- package/src/vfxgen/weapons/stylizedWeapons.js +0 -137
- package/src/villagegen/index.js +0 -4
- package/src/villagegen/stylizedVillage.js +0 -490
- package/src/villagegen/villageArchetypes.js +0 -160
- package/src/villagegen/villageNames.js +0 -40
- package/src/villagegen/villageSites.js +0 -105
- package/src/weather/index.js +0 -6
- package/src/weather/weatherPrecipitation.js +0 -221
- package/src/weather/weatherPresets.js +0 -258
- package/src/weather/weatherSettings.js +0 -269
- package/src/weather/weatherSystem.js +0 -871
- package/src/worldMinimap.js +0 -214
- package/src/worldPresets.js +0 -125
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
// Curl noise — the divergence-free vector field that advects cloud edges into
|
|
2
|
+
// wisps. Displacing a sample position by an arbitrary noise vector pumps
|
|
3
|
+
// density in and out of the cloud (the field has sources and sinks), so edges
|
|
4
|
+
// bulge and pop. The curl of a vector potential is divergence-free by
|
|
5
|
+
// construction, so advecting along it shears and folds the cloud without
|
|
6
|
+
// creating or destroying any of it — the reason curl noise, not plain noise, is
|
|
7
|
+
// what makes a wisp look torn from the body rather than pasted onto it.
|
|
8
|
+
//
|
|
9
|
+
// Potential: three decorrelated periodic Perlin FBM fields. Curl: collocated
|
|
10
|
+
// central differences of those. Because the same difference stencil is used for
|
|
11
|
+
// every partial, the mixed second derivatives cancel exactly and the discrete
|
|
12
|
+
// divergence is zero to floating-point rounding — not just to O(h²).
|
|
13
|
+
//
|
|
14
|
+
// Encoding: the volume packs curl * 0.5 + 0.5 into RGB and the vector's length
|
|
15
|
+
// into A, so a shader can modulate wisp strength by field energy from the same
|
|
16
|
+
// fetch. Decode through decodeCurlNoise(), or take the ready-made advection
|
|
17
|
+
// offset from curlNoiseOffsetNode(), rather than unpacking by hand; the scale
|
|
18
|
+
// the CPU normalized by is this module's business, not the raymarcher's.
|
|
19
|
+
//
|
|
20
|
+
// Both channels share one normalization scale, so A is exactly the length of the
|
|
21
|
+
// vector RGB decodes to. That scale comes from the probed peak *length*, not the
|
|
22
|
+
// peak component: a length reaches up to sqrt(3) times its largest component, so
|
|
23
|
+
// normalizing by the component peak overflowed A and clipped it.
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
Fn,
|
|
27
|
+
texture3D,
|
|
28
|
+
vec3,
|
|
29
|
+
} from 'three/tsl';
|
|
30
|
+
|
|
31
|
+
import { hashSeed } from '../../core/generation.js';
|
|
32
|
+
import { hashCombine } from '../../rockgen/noise/prng.js';
|
|
33
|
+
import {
|
|
34
|
+
createNoiseVolumeTexture,
|
|
35
|
+
encodeSnorm8,
|
|
36
|
+
encodeUnorm8,
|
|
37
|
+
noiseVolumeKey,
|
|
38
|
+
resolveNoiseDims,
|
|
39
|
+
warnNoiseVolumeOnce,
|
|
40
|
+
} from './noiseVolume.js';
|
|
41
|
+
import { createPeriodicPerlinFbm3 } from './periodicNoise3.js';
|
|
42
|
+
|
|
43
|
+
/** Default resolution. Curl is a low-frequency advection field; 32³ is ample. */
|
|
44
|
+
export const CURL_NOISE_DEFAULT_DIMS = 32;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Potential-field plan. `epsilon` is the central-difference step in tile units:
|
|
48
|
+
* small enough to read as a derivative, large enough that the difference of two
|
|
49
|
+
* nearly equal FBM samples keeps its significant digits.
|
|
50
|
+
*/
|
|
51
|
+
export const CURL_NOISE_PLAN = Object.freeze({
|
|
52
|
+
epsilon: 1 / 256,
|
|
53
|
+
gain: 0.6,
|
|
54
|
+
lacunarity: 2,
|
|
55
|
+
octaves: 3,
|
|
56
|
+
period: 3,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// The normalization scale is measured on a fixed probe grid rather than on the
|
|
60
|
+
// output grid, so the same seed yields the same field at every resolution — a
|
|
61
|
+
// 16³ curl volume must not be a differently scaled field from the 64³ one.
|
|
62
|
+
const NORMALIZATION_PROBE_DIMS = 32;
|
|
63
|
+
// Headroom over the probed peak, and the reason the probe can be fixed at all: a
|
|
64
|
+
// finer output grid samples points the probe never visits, so it finds higher
|
|
65
|
+
// values. Measured against the 32³ probe's peak length, the true peak runs 8.5%
|
|
66
|
+
// higher on a 64³ output grid and 8.8% higher on a 128³ one, and a 400k-point
|
|
67
|
+
// off-lattice sweep tops out at 6.8% — so the growth flattens off well inside
|
|
68
|
+
// 15%, resolveNoiseDims' 256³ ceiling included.
|
|
69
|
+
const NORMALIZATION_HEADROOM = 1.15;
|
|
70
|
+
|
|
71
|
+
const volumeCache = new Map();
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Builds the divergence-free field.
|
|
75
|
+
*
|
|
76
|
+
* `sample(x, y, z)` takes tile coordinates and writes the normalized curl into
|
|
77
|
+
* `out`, returning it — components land in about [-1, 1]. `curl()` returns the
|
|
78
|
+
* same vector unnormalized, which is what the divergence check needs.
|
|
79
|
+
*/
|
|
80
|
+
export function createCurlNoiseField({ seed = 1, plan = {} } = {}) {
|
|
81
|
+
const rootSeed = hashSeed(seed);
|
|
82
|
+
const settings = { ...CURL_NOISE_PLAN, ...plan };
|
|
83
|
+
const epsilon = Math.max(1e-5, Number(settings.epsilon) || CURL_NOISE_PLAN.epsilon);
|
|
84
|
+
const fbmOptions = {
|
|
85
|
+
// The potential is evaluated analytically at arbitrary offsets, not on the
|
|
86
|
+
// output grid, so it carries no band limit of its own. The curl's own
|
|
87
|
+
// frequency content is set by `period` and stays well inside 32³.
|
|
88
|
+
dim: Infinity,
|
|
89
|
+
gain: settings.gain,
|
|
90
|
+
lacunarity: settings.lacunarity,
|
|
91
|
+
octaves: settings.octaves,
|
|
92
|
+
period: settings.period,
|
|
93
|
+
};
|
|
94
|
+
// Three potential components, seeded apart so the curl does not degenerate
|
|
95
|
+
// toward a single axis.
|
|
96
|
+
const psi = [
|
|
97
|
+
createPeriodicPerlinFbm3(hashCombine(rootSeed, 0x9e37), fbmOptions),
|
|
98
|
+
createPeriodicPerlinFbm3(hashCombine(rootSeed, 0x85eb), fbmOptions),
|
|
99
|
+
createPeriodicPerlinFbm3(hashCombine(rootSeed, 0xc2b2), fbmOptions),
|
|
100
|
+
];
|
|
101
|
+
const inverseStep = 1 / (2 * epsilon);
|
|
102
|
+
|
|
103
|
+
function curl(x, y, z, out) {
|
|
104
|
+
const dy3 = (psi[2].sample(x, y + epsilon, z) - psi[2].sample(x, y - epsilon, z)) * inverseStep;
|
|
105
|
+
const dz2 = (psi[1].sample(x, y, z + epsilon) - psi[1].sample(x, y, z - epsilon)) * inverseStep;
|
|
106
|
+
const dz1 = (psi[0].sample(x, y, z + epsilon) - psi[0].sample(x, y, z - epsilon)) * inverseStep;
|
|
107
|
+
const dx3 = (psi[2].sample(x + epsilon, y, z) - psi[2].sample(x - epsilon, y, z)) * inverseStep;
|
|
108
|
+
const dx2 = (psi[1].sample(x + epsilon, y, z) - psi[1].sample(x - epsilon, y, z)) * inverseStep;
|
|
109
|
+
const dy1 = (psi[0].sample(x, y + epsilon, z) - psi[0].sample(x, y - epsilon, z)) * inverseStep;
|
|
110
|
+
out.x = dy3 - dz2;
|
|
111
|
+
out.y = dz1 - dx3;
|
|
112
|
+
out.z = dx2 - dy1;
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Probe for the peak so the 8-bit encoding uses its range without clipping the
|
|
117
|
+
// tails. Both peaks are measured; only the length one sets the scale.
|
|
118
|
+
const probe = { x: 0, y: 0, z: 0 };
|
|
119
|
+
let componentPeak = 0;
|
|
120
|
+
let lengthPeak = 0;
|
|
121
|
+
const inverseProbe = 1 / NORMALIZATION_PROBE_DIMS;
|
|
122
|
+
for (let z = 0; z < NORMALIZATION_PROBE_DIMS; z += 1) {
|
|
123
|
+
for (let y = 0; y < NORMALIZATION_PROBE_DIMS; y += 1) {
|
|
124
|
+
for (let x = 0; x < NORMALIZATION_PROBE_DIMS; x += 1) {
|
|
125
|
+
curl((x + 0.5) * inverseProbe, (y + 0.5) * inverseProbe, (z + 0.5) * inverseProbe, probe);
|
|
126
|
+
componentPeak = Math.max(
|
|
127
|
+
componentPeak, Math.abs(probe.x), Math.abs(probe.y), Math.abs(probe.z),
|
|
128
|
+
);
|
|
129
|
+
lengthPeak = Math.max(
|
|
130
|
+
lengthPeak,
|
|
131
|
+
Math.sqrt(probe.x * probe.x + probe.y * probe.y + probe.z * probe.z),
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Normalize by the *length* peak, because the length is what the A channel
|
|
137
|
+
// encodes and a length runs up to sqrt(3) times its largest component. Scaling
|
|
138
|
+
// by the component peak fit RGB and overflowed A, and a clipped |curl| is no
|
|
139
|
+
// longer the length of the RGB it ships with. One shared scale keeps
|
|
140
|
+
// `a === length(decode(rgb))` exact; it costs the components about a tenth of
|
|
141
|
+
// their range, which is cheaper than an inconsistent encoding.
|
|
142
|
+
const scale = 1 / (lengthPeak * NORMALIZATION_HEADROOM || 1);
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
componentPeak,
|
|
146
|
+
curl,
|
|
147
|
+
epsilon,
|
|
148
|
+
lengthPeak,
|
|
149
|
+
sample(x, y, z, out = { x: 0, y: 0, z: 0 }) {
|
|
150
|
+
curl(x, y, z, out);
|
|
151
|
+
out.x *= scale;
|
|
152
|
+
out.y *= scale;
|
|
153
|
+
out.z *= scale;
|
|
154
|
+
return out;
|
|
155
|
+
},
|
|
156
|
+
scale,
|
|
157
|
+
seed: rootSeed,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Bakes the RGBA8 curl volume. Returned separately from the texture so the
|
|
163
|
+
* divergence and tiling checks can read the numbers without a renderer.
|
|
164
|
+
*/
|
|
165
|
+
export function createCurlNoiseData({
|
|
166
|
+
dims = CURL_NOISE_DEFAULT_DIMS,
|
|
167
|
+
seed = 1,
|
|
168
|
+
plan = {},
|
|
169
|
+
} = {}) {
|
|
170
|
+
const size = resolveNoiseDims(dims, CURL_NOISE_DEFAULT_DIMS);
|
|
171
|
+
const field = createCurlNoiseField({ plan, seed });
|
|
172
|
+
const data = new Uint8Array(size.x * size.y * size.z * 4);
|
|
173
|
+
const vector = { x: 0, y: 0, z: 0 };
|
|
174
|
+
const invX = 1 / size.x;
|
|
175
|
+
const invY = 1 / size.y;
|
|
176
|
+
const invZ = 1 / size.z;
|
|
177
|
+
let cursor = 0;
|
|
178
|
+
// Watchdog on the fixed probe grid's assumption: the output grid is free to
|
|
179
|
+
// land on a higher field value than the probe found, and if the headroom ever
|
|
180
|
+
// fails to cover that the encoders clamp silently. Report it instead.
|
|
181
|
+
let peakLength = 0;
|
|
182
|
+
let clippedTexels = 0;
|
|
183
|
+
for (let z = 0; z < size.z; z += 1) {
|
|
184
|
+
const w = (z + 0.5) * invZ;
|
|
185
|
+
for (let y = 0; y < size.y; y += 1) {
|
|
186
|
+
const v = (y + 0.5) * invY;
|
|
187
|
+
for (let x = 0; x < size.x; x += 1) {
|
|
188
|
+
const u = (x + 0.5) * invX;
|
|
189
|
+
field.sample(u, v, w, vector);
|
|
190
|
+
const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
|
|
191
|
+
if (length > peakLength) peakLength = length;
|
|
192
|
+
if (length > 1) clippedTexels += 1;
|
|
193
|
+
data[cursor] = encodeSnorm8(vector.x);
|
|
194
|
+
data[cursor + 1] = encodeSnorm8(vector.y);
|
|
195
|
+
data[cursor + 2] = encodeSnorm8(vector.z);
|
|
196
|
+
data[cursor + 3] = encodeUnorm8(length);
|
|
197
|
+
cursor += 4;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (clippedTexels > 0) {
|
|
202
|
+
warnNoiseVolumeOnce(
|
|
203
|
+
`curl-clip:${size.x}x${size.y}x${size.z}`,
|
|
204
|
+
`[curlNoise] |curl| peaked at ${peakLength.toFixed(3)} on the `
|
|
205
|
+
+ `${size.x}x${size.y}x${size.z} output grid, above the 1.0 the A channel can hold, so `
|
|
206
|
+
+ `${clippedTexels} texel(s) clipped. The ${NORMALIZATION_PROBE_DIMS}³ probe grid `
|
|
207
|
+
+ 'under-estimated the field peak at this resolution.',
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
clippedTexels,
|
|
213
|
+
data,
|
|
214
|
+
dims: size,
|
|
215
|
+
field,
|
|
216
|
+
peakLength,
|
|
217
|
+
seed: field.seed,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Bakes an uncached curl volume. Callers own dispose(). */
|
|
222
|
+
export function createCurlNoiseVolume({
|
|
223
|
+
dims = CURL_NOISE_DEFAULT_DIMS,
|
|
224
|
+
seed = 1,
|
|
225
|
+
plan = {},
|
|
226
|
+
} = {}) {
|
|
227
|
+
const baked = createCurlNoiseData({ dims, plan, seed });
|
|
228
|
+
const texture = createNoiseVolumeTexture(
|
|
229
|
+
baked.data,
|
|
230
|
+
baked.dims,
|
|
231
|
+
`ToonLabCloudCurl${baked.dims.x}x${baked.dims.y}x${baked.dims.z}`,
|
|
232
|
+
);
|
|
233
|
+
texture.userData.toonlabCloudNoise = {
|
|
234
|
+
componentPeak: baked.field.componentPeak,
|
|
235
|
+
dims: baked.dims,
|
|
236
|
+
encoding: 'rgb = curl * 0.5 + 0.5, a = |curl|',
|
|
237
|
+
kind: 'curl',
|
|
238
|
+
lengthPeak: baked.field.lengthPeak,
|
|
239
|
+
peakLength: baked.peakLength,
|
|
240
|
+
scale: baked.field.scale,
|
|
241
|
+
seed: baked.seed,
|
|
242
|
+
};
|
|
243
|
+
return texture;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Cached curl volume, keyed by resolution and seed. */
|
|
247
|
+
export function getCurlNoiseVolume({
|
|
248
|
+
dims = CURL_NOISE_DEFAULT_DIMS,
|
|
249
|
+
seed = 1,
|
|
250
|
+
plan = {},
|
|
251
|
+
} = {}) {
|
|
252
|
+
const size = resolveNoiseDims(dims, CURL_NOISE_DEFAULT_DIMS);
|
|
253
|
+
// The plan joins the key: a custom potential is a different field, and
|
|
254
|
+
// returning the default one for it would be a silent wrong answer.
|
|
255
|
+
const key = `${noiseVolumeKey(size, hashSeed(seed))}:${hashSeed(JSON.stringify({ ...CURL_NOISE_PLAN, ...plan }))}`;
|
|
256
|
+
const cached = volumeCache.get(key);
|
|
257
|
+
if (cached) return cached;
|
|
258
|
+
const texture = createCurlNoiseVolume({ dims: size, plan, seed });
|
|
259
|
+
volumeCache.set(key, texture);
|
|
260
|
+
return texture;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Releases every cached curl volume. */
|
|
264
|
+
export function disposeCurlNoiseVolumes() {
|
|
265
|
+
for (const texture of volumeCache.values()) texture.dispose();
|
|
266
|
+
volumeCache.clear();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** Decodes a packed curl texel back to a signed vector in about [-1, 1]. */
|
|
270
|
+
export const decodeCurlNoise = /*@__PURE__*/ Fn(([packed]) => (
|
|
271
|
+
packed.rgb.mul(2).sub(vec3(1))
|
|
272
|
+
));
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Samples a baked curl volume as an advection offset, in metres.
|
|
276
|
+
*
|
|
277
|
+
* `scale` is the world size of one tile — pass the same repeat the erosion
|
|
278
|
+
* detail uses so wisps shear at the scale they are carved at. `strength` is the
|
|
279
|
+
* offset magnitude in metres at full field energy. RepeatWrapping does the
|
|
280
|
+
* tiling, so the world position needs no fract() first.
|
|
281
|
+
*/
|
|
282
|
+
export function curlNoiseOffsetNode(volume, {
|
|
283
|
+
position,
|
|
284
|
+
scale,
|
|
285
|
+
strength,
|
|
286
|
+
}) {
|
|
287
|
+
const packed = texture3D(volume).sample(position.div(scale));
|
|
288
|
+
return decodeCurlNoise(packed).mul(strength);
|
|
289
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Cloud erosion volume — the high-frequency Worley detail field that carves
|
|
2
|
+
// the cloud silhouette after the base shape has decided where cloud exists.
|
|
3
|
+
//
|
|
4
|
+
// R inverted Worley FBM, low detail (2 / 4 / 8 cells)
|
|
5
|
+
// G inverted Worley FBM, mid detail (4 / 8 / 16 cells)
|
|
6
|
+
// B inverted Worley FBM, high detail (8 / 16 cells)
|
|
7
|
+
// A R * 0.625 + G * 0.25 + B * 0.125, precombined
|
|
8
|
+
//
|
|
9
|
+
// Each RGB channel is already an overlapping FBM, matching Hillaire's published
|
|
10
|
+
// TileableVolumeNoise companion implementation. The density field combines the
|
|
11
|
+
// three FBMs once more, which is what gives erosion a broad support plus enough
|
|
12
|
+
// fine structure to break a silhouette:
|
|
13
|
+
//
|
|
14
|
+
// detail = r * 0.625 + g * 0.25 + b * 0.125 (or just the A channel)
|
|
15
|
+
// wispy = mix(detail, 1 - detail, saturate(heightFraction * 5))
|
|
16
|
+
// modifier = mix(detail, wispy, erosionShape)
|
|
17
|
+
// density = remap(base, modifier * erosionStrength, 1, 0, 1)
|
|
18
|
+
//
|
|
19
|
+
// The A channel exists for the cheap paths — the shadow bake and the env-map
|
|
20
|
+
// bake carve with one weighted band instead of three, and a fetch they already
|
|
21
|
+
// have to make is cheaper than three multiplies they do not.
|
|
22
|
+
//
|
|
23
|
+
// The band limit here is deliberately looser than the base-shape volume's (two
|
|
24
|
+
// texels per cell rather than four). A detail field's job is high-frequency
|
|
25
|
+
// grain, not a resolvable silhouette, and the top rung of a 32³ detail volume
|
|
26
|
+
// is where the reference-class implementations sit.
|
|
27
|
+
|
|
28
|
+
import { deriveSeed, hashSeed } from '../../core/generation.js';
|
|
29
|
+
import {
|
|
30
|
+
createNoiseVolumeTexture,
|
|
31
|
+
encodeUnorm8,
|
|
32
|
+
noiseVolumeKey,
|
|
33
|
+
resolveNoiseDims,
|
|
34
|
+
warnNoiseVolumeOnce,
|
|
35
|
+
} from './noiseVolume.js';
|
|
36
|
+
import { createWorleyLadder3 } from './periodicNoise3.js';
|
|
37
|
+
|
|
38
|
+
/** Default resolution. Not tier-driven: erosion is cheap at every tier. */
|
|
39
|
+
export const CLOUD_EROSION_DEFAULT_DIMS = 32;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Seed namespace for this volume's bands.
|
|
43
|
+
*
|
|
44
|
+
* createWorleyLadder3 seeds each band by its cell count, so a frequency is the
|
|
45
|
+
* same field at every volume resolution — and, without a namespace, the same
|
|
46
|
+
* field in every *volume* that requests that count. The base-shape volume's
|
|
47
|
+
* ladder overlaps this plan at 4/8/16 cells, so the two combined fields became
|
|
48
|
+
* strongly correlated. Carving a cloud with a copy of its own erosion basis
|
|
49
|
+
* flattens the silhouette instead of tearing it, and at
|
|
50
|
+
* `shape.erosionScaleBaseMultiplier = 1.0` — the top of the spec's authoring
|
|
51
|
+
* range, where both volumes are read at the same tile coordinate — the two
|
|
52
|
+
* fields were 0.69 correlated. Namespacing the seed drops that to ~0.
|
|
53
|
+
*/
|
|
54
|
+
export const CLOUD_EROSION_SEED_NAMESPACE = 'cloud-erosion';
|
|
55
|
+
|
|
56
|
+
/** Weights the A channel packs, and the density field's own detail FBM. */
|
|
57
|
+
export const CLOUD_EROSION_DETAIL_WEIGHTS = Object.freeze([0.625, 0.25, 0.125]);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Frequency plan in cells across one tile. Fixed in tile units so a custom
|
|
61
|
+
* resolution re-resolves the same field rather than authoring a new one.
|
|
62
|
+
*/
|
|
63
|
+
export const CLOUD_EROSION_PLAN = Object.freeze({
|
|
64
|
+
cells: Object.freeze([2, 4, 8, 16]),
|
|
65
|
+
jitter: 1,
|
|
66
|
+
texelsPerCell: 2,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const volumeCache = new Map();
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Bakes the RGBA8 erosion field. Returned separately from the texture so
|
|
73
|
+
* verification scripts can read the numbers without a renderer.
|
|
74
|
+
*/
|
|
75
|
+
export function createCloudErosionData({
|
|
76
|
+
dims = CLOUD_EROSION_DEFAULT_DIMS,
|
|
77
|
+
seed = 1,
|
|
78
|
+
} = {}) {
|
|
79
|
+
const size = resolveNoiseDims(dims, CLOUD_EROSION_DEFAULT_DIMS);
|
|
80
|
+
const rootSeed = hashSeed(seed);
|
|
81
|
+
// The public seed is reported unchanged so a preset can round-trip it; only
|
|
82
|
+
// the field seed is namespaced.
|
|
83
|
+
const fieldSeed = deriveSeed(rootSeed, CLOUD_EROSION_SEED_NAMESPACE);
|
|
84
|
+
const bands = createWorleyLadder3(fieldSeed, CLOUD_EROSION_PLAN.cells, {
|
|
85
|
+
dim: Math.min(size.x, size.y, size.z),
|
|
86
|
+
jitter: CLOUD_EROSION_PLAN.jitter,
|
|
87
|
+
texelsPerCell: CLOUD_EROSION_PLAN.texelsPerCell,
|
|
88
|
+
});
|
|
89
|
+
// Four bands are the contract, not a preference: RGB are the overlapping
|
|
90
|
+
// FBMs [2/4/8], [4/8/16] and [8/16]. At two texels per cell a short axis of
|
|
91
|
+
// 16 band-limits the last rung and loses the finest part of G/B.
|
|
92
|
+
const distinctBands = new Set(bands).size;
|
|
93
|
+
if (distinctBands < CLOUD_EROSION_PLAN.cells.length) {
|
|
94
|
+
warnNoiseVolumeOnce(
|
|
95
|
+
`erosion-bands:${size.x}x${size.y}x${size.z}`,
|
|
96
|
+
`[erosionVolume] ${size.x}x${size.y}x${size.z} band-limits cells `
|
|
97
|
+
+ `[${CLOUD_EROSION_PLAN.cells}] to [${bands.map((band) => band.cells)}], leaving `
|
|
98
|
+
+ `${distinctBands} distinct band(s) of ${CLOUD_EROSION_PLAN.cells.length}: the repeated `
|
|
99
|
+
+ 'channels carry identical bytes and the detail FBM loses a band. Raise the resolution to '
|
|
100
|
+
+ `${CLOUD_EROSION_PLAN.cells[CLOUD_EROSION_PLAN.cells.length - 1]
|
|
101
|
+
* CLOUD_EROSION_PLAN.texelsPerCell}³ or above for all three.`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const [weightR, weightG, weightB] = CLOUD_EROSION_DETAIL_WEIGHTS;
|
|
105
|
+
|
|
106
|
+
const data = new Uint8Array(size.x * size.y * size.z * 4);
|
|
107
|
+
const invX = 1 / size.x;
|
|
108
|
+
const invY = 1 / size.y;
|
|
109
|
+
const invZ = 1 / size.z;
|
|
110
|
+
let cursor = 0;
|
|
111
|
+
for (let z = 0; z < size.z; z += 1) {
|
|
112
|
+
const w = (z + 0.5) * invZ;
|
|
113
|
+
for (let y = 0; y < size.y; y += 1) {
|
|
114
|
+
const v = (y + 0.5) * invY;
|
|
115
|
+
for (let x = 0; x < size.x; x += 1) {
|
|
116
|
+
const u = (x + 0.5) * invX;
|
|
117
|
+
const w0 = 1 - bands[0].sample(u, v, w);
|
|
118
|
+
const w1 = 1 - bands[1].sample(u, v, w);
|
|
119
|
+
const w2 = 1 - bands[2].sample(u, v, w);
|
|
120
|
+
const w3 = 1 - bands[3].sample(u, v, w);
|
|
121
|
+
// Exact packing from Hillaire's reference generator. The highest
|
|
122
|
+
// channel has two usable rungs at 32^3, hence 0.75 / 0.25.
|
|
123
|
+
const low = w0 * 0.625 + w1 * 0.25 + w2 * 0.125;
|
|
124
|
+
const mid = w1 * 0.625 + w2 * 0.25 + w3 * 0.125;
|
|
125
|
+
const high = w2 * 0.75 + w3 * 0.25;
|
|
126
|
+
data[cursor] = encodeUnorm8(low);
|
|
127
|
+
data[cursor + 1] = encodeUnorm8(mid);
|
|
128
|
+
data[cursor + 2] = encodeUnorm8(high);
|
|
129
|
+
data[cursor + 3] = encodeUnorm8(low * weightR + mid * weightG + high * weightB);
|
|
130
|
+
cursor += 4;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
data,
|
|
137
|
+
dims: size,
|
|
138
|
+
distinctBands,
|
|
139
|
+
fieldSeed,
|
|
140
|
+
seed: rootSeed,
|
|
141
|
+
worleyCells: bands.map((band) => band.cells),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Bakes an uncached erosion volume. Callers own dispose(). */
|
|
146
|
+
export function createCloudErosionVolume({
|
|
147
|
+
dims = CLOUD_EROSION_DEFAULT_DIMS,
|
|
148
|
+
seed = 1,
|
|
149
|
+
} = {}) {
|
|
150
|
+
const baked = createCloudErosionData({ dims, seed });
|
|
151
|
+
const texture = createNoiseVolumeTexture(
|
|
152
|
+
baked.data,
|
|
153
|
+
baked.dims,
|
|
154
|
+
`ToonLabCloudErosion${baked.dims.x}x${baked.dims.y}x${baked.dims.z}`,
|
|
155
|
+
);
|
|
156
|
+
texture.userData.toonlabCloudNoise = {
|
|
157
|
+
detailWeights: CLOUD_EROSION_DETAIL_WEIGHTS,
|
|
158
|
+
dims: baked.dims,
|
|
159
|
+
distinctBands: baked.distinctBands,
|
|
160
|
+
// `seed` is the public seed, so a lab can serialize it and get this volume
|
|
161
|
+
// back; `fieldSeed` is the namespaced seed the bands were built from.
|
|
162
|
+
fieldSeed: baked.fieldSeed,
|
|
163
|
+
kind: 'erosion',
|
|
164
|
+
seed: baked.seed,
|
|
165
|
+
worleyCells: baked.worleyCells,
|
|
166
|
+
};
|
|
167
|
+
return texture;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Cached erosion volume, keyed by resolution and seed. */
|
|
171
|
+
export function getCloudErosionVolume({
|
|
172
|
+
dims = CLOUD_EROSION_DEFAULT_DIMS,
|
|
173
|
+
seed = 1,
|
|
174
|
+
} = {}) {
|
|
175
|
+
const size = resolveNoiseDims(dims, CLOUD_EROSION_DEFAULT_DIMS);
|
|
176
|
+
const key = noiseVolumeKey(size, hashSeed(seed));
|
|
177
|
+
const cached = volumeCache.get(key);
|
|
178
|
+
if (cached) return cached;
|
|
179
|
+
const texture = createCloudErosionVolume({ dims: size, seed });
|
|
180
|
+
volumeCache.set(key, texture);
|
|
181
|
+
return texture;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Releases every cached erosion volume. */
|
|
185
|
+
export function disposeCloudErosionVolumes() {
|
|
186
|
+
for (const texture of volumeCache.values()) texture.dispose();
|
|
187
|
+
volumeCache.clear();
|
|
188
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// The Data3DTexture contract shared by the three cloud noise volumes.
|
|
2
|
+
//
|
|
3
|
+
// All of them are RGBA8 tiling fields sampled trilinearly with RepeatWrapping
|
|
4
|
+
// on every axis. Getting one axis wrong (wrapR defaults to ClampToEdge) puts a
|
|
5
|
+
// seam in the sky that looks like a shader bug rather than a texture setting,
|
|
6
|
+
// so the settings live in one place instead of three.
|
|
7
|
+
|
|
8
|
+
import * as THREE from 'three';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reads one authored number out of untrusted input, returning `fallback` for
|
|
12
|
+
* anything absent. The single definition of "absent" for the whole noise module.
|
|
13
|
+
*
|
|
14
|
+
* `Number()` is not the guard it looks like: `Number(null)`, `Number('')`,
|
|
15
|
+
* `Number([])` and `Number(false)` are all 0 and all pass `Number.isFinite`, so
|
|
16
|
+
* a clamp downstream pins them to a range's minimum instead of falling back to a
|
|
17
|
+
* default. A preset that round-tripped through JSON carries `null` for every
|
|
18
|
+
* untouched field, so that difference is the difference between reloading a sky
|
|
19
|
+
* and authoring a new one. Numeric strings stay legal because lab inputs and URL
|
|
20
|
+
* parameters arrive as strings.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveAuthoredNumber(value, fallback) {
|
|
23
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : fallback;
|
|
24
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
25
|
+
const parsed = Number(value);
|
|
26
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
27
|
+
}
|
|
28
|
+
return fallback;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Hard floor for every noise volume, on every axis.
|
|
33
|
+
*
|
|
34
|
+
* Below 8 the band ladder has nothing left to resolve: every Worley rung
|
|
35
|
+
* band-limits onto the same cell count, so the three erosion channels come out
|
|
36
|
+
* byte-identical and what remains is not a cloud field. The floor lives here
|
|
37
|
+
* rather than in each baker because the degenerate volume still samples cleanly
|
|
38
|
+
* — nothing downstream can detect that it was handed junk.
|
|
39
|
+
*/
|
|
40
|
+
export const NOISE_VOLUME_MIN_DIM = 8;
|
|
41
|
+
|
|
42
|
+
/** Accepts 64, [64, 32, 64] or { x, y, z } and normalizes to { x, y, z }. */
|
|
43
|
+
export function resolveNoiseDims(dims, fallback = 64) {
|
|
44
|
+
const clampAxis = (value) => {
|
|
45
|
+
// An absent axis is the default, not zero: a preset that serialized `null`
|
|
46
|
+
// — or `false`, or 0 — must not deserialize into a 2³ volume.
|
|
47
|
+
const size = Math.round(resolveAuthoredNumber(value, fallback));
|
|
48
|
+
if (!(size > 0)) return fallback;
|
|
49
|
+
if (size < NOISE_VOLUME_MIN_DIM) {
|
|
50
|
+
warnNoiseVolumeOnce(
|
|
51
|
+
`noise-dim-floor:${size}`,
|
|
52
|
+
`Noise volume axis ${size} is below the ${NOISE_VOLUME_MIN_DIM}-texel floor; `
|
|
53
|
+
+ `clamping to ${NOISE_VOLUME_MIN_DIM}. Below it every band collapses onto one `
|
|
54
|
+
+ 'cell count and the erosion channels come out identical.',
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return Math.min(Math.max(size, NOISE_VOLUME_MIN_DIM), 256);
|
|
58
|
+
};
|
|
59
|
+
if (Array.isArray(dims)) {
|
|
60
|
+
return {
|
|
61
|
+
x: clampAxis(dims[0]),
|
|
62
|
+
y: clampAxis(dims[1] ?? dims[0]),
|
|
63
|
+
z: clampAxis(dims[2] ?? dims[0]),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (dims && typeof dims === 'object') {
|
|
67
|
+
return { x: clampAxis(dims.x), y: clampAxis(dims.y), z: clampAxis(dims.z) };
|
|
68
|
+
}
|
|
69
|
+
const size = clampAxis(dims);
|
|
70
|
+
return { x: size, y: size, z: size };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** `${x}x${y}x${z}:${seed}` — the cache key every volume generator uses. */
|
|
74
|
+
export function noiseVolumeKey(dims, seed) {
|
|
75
|
+
return `${dims.x}x${dims.y}x${dims.z}:${seed}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const warnedKeys = new Set();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Reports a degenerate volume configuration once per distinct `key`.
|
|
82
|
+
*
|
|
83
|
+
* A band ladder that collapsed, a mip level that hit the resolution floor, an
|
|
84
|
+
* encoding that clipped — all of them produce a field that still *looks* like a
|
|
85
|
+
* volume, so silence is the failure mode. Deduplicated because a lab bound to a
|
|
86
|
+
* seed slider re-bakes on every drag, and a warning repeated a hundred times
|
|
87
|
+
* buries the first one. The key is the configuration, not the seed: the same
|
|
88
|
+
* resolution degenerates the same way whatever it is seeded with.
|
|
89
|
+
*/
|
|
90
|
+
export function warnNoiseVolumeOnce(key, message) {
|
|
91
|
+
if (warnedKeys.has(key)) return false;
|
|
92
|
+
warnedKeys.add(key);
|
|
93
|
+
console.warn(message);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Wraps baked RGBA8 data in a fully configured tiling 3D texture.
|
|
99
|
+
*
|
|
100
|
+
* `generateMipmaps` stays off: three.js cannot build a 3D mip chain on the
|
|
101
|
+
* WebGPU backend. Volumes that carry authored levels are configured and uploaded
|
|
102
|
+
* by configureNoiseVolumeMipChain/uploadNoiseVolumeMipChain below.
|
|
103
|
+
*/
|
|
104
|
+
export function createNoiseVolumeTexture(data, dims, name) {
|
|
105
|
+
const texture = new THREE.Data3DTexture(data, dims.x, dims.y, dims.z);
|
|
106
|
+
texture.name = name;
|
|
107
|
+
texture.format = THREE.RGBAFormat;
|
|
108
|
+
texture.type = THREE.UnsignedByteType;
|
|
109
|
+
texture.colorSpace = THREE.NoColorSpace;
|
|
110
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
111
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
112
|
+
texture.wrapR = THREE.RepeatWrapping;
|
|
113
|
+
texture.minFilter = THREE.LinearFilter;
|
|
114
|
+
texture.magFilter = THREE.LinearFilter;
|
|
115
|
+
texture.generateMipmaps = false;
|
|
116
|
+
texture.unpackAlignment = 1;
|
|
117
|
+
texture.needsUpdate = true;
|
|
118
|
+
return texture;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function volumeMipDims(dims, level) {
|
|
122
|
+
const scale = 2 ** level;
|
|
123
|
+
return {
|
|
124
|
+
x: Math.max(1, Math.floor(dims.x / scale)),
|
|
125
|
+
y: Math.max(1, Math.floor(dims.y / scale)),
|
|
126
|
+
z: Math.max(1, Math.floor(dims.z / scale)),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Gives a Data3DTexture a full authored mip pyramid. WebGPU cannot generate
|
|
132
|
+
* 3D mips through three's normal generator, so the byte levels are retained
|
|
133
|
+
* until a renderer can copy them into the allocated GPU levels.
|
|
134
|
+
*/
|
|
135
|
+
export function configureNoiseVolumeMipChain(texture, levels, dims) {
|
|
136
|
+
if (!texture?.isData3DTexture || !Array.isArray(levels) || levels.length < 2) {
|
|
137
|
+
return texture;
|
|
138
|
+
}
|
|
139
|
+
texture.minFilter = THREE.LinearMipMapLinearFilter;
|
|
140
|
+
texture.magFilter = THREE.LinearFilter;
|
|
141
|
+
texture.generateMipmaps = false;
|
|
142
|
+
texture.mipmaps = levels.map((unused, level) => {
|
|
143
|
+
const size = volumeMipDims(dims, level);
|
|
144
|
+
return { width: size.x, height: size.y, depth: size.z };
|
|
145
|
+
});
|
|
146
|
+
texture.userData.toonlabVolumeMipChain = {
|
|
147
|
+
dims: { ...dims },
|
|
148
|
+
levels,
|
|
149
|
+
uploadedRenderers: new WeakSet(),
|
|
150
|
+
};
|
|
151
|
+
texture.needsUpdate = true;
|
|
152
|
+
return texture;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Uploads the retained 3D mip levels once for each renderer. */
|
|
156
|
+
export function uploadNoiseVolumeMipChain(renderer, texture) {
|
|
157
|
+
const chain = texture?.userData?.toonlabVolumeMipChain;
|
|
158
|
+
if (!renderer?.copyTextureToTexture || !chain || chain.uploadedRenderers.has(renderer)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const temps = [];
|
|
163
|
+
for (let level = 1; level < chain.levels.length; level += 1) {
|
|
164
|
+
const size = volumeMipDims(chain.dims, level);
|
|
165
|
+
const temp = new THREE.Data3DTexture(
|
|
166
|
+
chain.levels[level],
|
|
167
|
+
size.x,
|
|
168
|
+
size.y,
|
|
169
|
+
size.z,
|
|
170
|
+
);
|
|
171
|
+
temp.format = THREE.RGBAFormat;
|
|
172
|
+
temp.type = THREE.UnsignedByteType;
|
|
173
|
+
temp.unpackAlignment = 1;
|
|
174
|
+
temp.needsUpdate = true;
|
|
175
|
+
renderer.copyTextureToTexture(
|
|
176
|
+
temp,
|
|
177
|
+
texture,
|
|
178
|
+
new THREE.Box3(
|
|
179
|
+
new THREE.Vector3(0, 0, 0),
|
|
180
|
+
new THREE.Vector3(size.x, size.y, size.z),
|
|
181
|
+
),
|
|
182
|
+
new THREE.Vector3(0, 0, 0),
|
|
183
|
+
0,
|
|
184
|
+
level,
|
|
185
|
+
);
|
|
186
|
+
temps.push(temp);
|
|
187
|
+
}
|
|
188
|
+
for (const temp of temps) temp.dispose();
|
|
189
|
+
chain.uploadedRenderers.add(renderer);
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Quantizes a [0, 1] field value to a byte with round-half-up. */
|
|
194
|
+
export function encodeUnorm8(value) {
|
|
195
|
+
const clamped = value < 0 ? 0 : value > 1 ? 1 : value;
|
|
196
|
+
return (clamped * 255 + 0.5) | 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Quantizes a [-1, 1] field value to a byte, matching a `* 2 - 1` decode. */
|
|
200
|
+
export function encodeSnorm8(value) {
|
|
201
|
+
return encodeUnorm8(value * 0.5 + 0.5);
|
|
202
|
+
}
|