@call-me-sensei/toonlab 0.1.1

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.
Files changed (146) hide show
  1. package/ATTRIBUTION.md +40 -0
  2. package/LICENSE +21 -0
  3. package/README.md +125 -0
  4. package/package.json +97 -0
  5. package/src/character/characterRig.js +353 -0
  6. package/src/character/freestyleSwimClip.js +541 -0
  7. package/src/character/index.js +4 -0
  8. package/src/character/modelLoader.js +433 -0
  9. package/src/core/materialRoles.js +438 -0
  10. package/src/core/presetDocuments.js +110 -0
  11. package/src/core/shaderBackend.js +24 -0
  12. package/src/debrisgen/debrisFields.js +544 -0
  13. package/src/debrisgen/debrisGenerator.js +1929 -0
  14. package/src/debrisgen/debrisPalettes.js +71 -0
  15. package/src/debrisgen/debrisPhysics.js +198 -0
  16. package/src/debrisgen/debrisPresets.js +155 -0
  17. package/src/debrisgen/debrisSettings.js +333 -0
  18. package/src/debrisgen/debrisTextures.js +380 -0
  19. package/src/debrisgen/index.js +5 -0
  20. package/src/debug/fieldValues.js +95 -0
  21. package/src/debug/index.js +7 -0
  22. package/src/debug/settingsPanel.js +170 -0
  23. package/src/environment/environmentAmbientProbe.js +160 -0
  24. package/src/environment/environmentMaterialAdapter.js +336 -0
  25. package/src/environment/environmentMaterialClassifier.js +178 -0
  26. package/src/environment/environmentPlanarReflection.js +201 -0
  27. package/src/environment/environmentPresets.js +443 -0
  28. package/src/environment/environmentRigs.js +684 -0
  29. package/src/environment/environmentSettings.js +504 -0
  30. package/src/environment/environmentShaderMaterials.js +318 -0
  31. package/src/environment/environmentSunShadowPass.js +268 -0
  32. package/src/environment/environmentTextureResolver.js +161 -0
  33. package/src/environment/environmentTimeOfDay.js +167 -0
  34. package/src/environment/environmentVertexAo.js +188 -0
  35. package/src/environment/index.js +8 -0
  36. package/src/environment/scanAssetStylize.js +103 -0
  37. package/src/index.js +21 -0
  38. package/src/loaders/index.js +1 -0
  39. package/src/post/index.js +2 -0
  40. package/src/post/postProcessing.js +1087 -0
  41. package/src/rockgen/export/glbExport.js +177 -0
  42. package/src/rockgen/heightfield/heightfieldErosion.js +7 -0
  43. package/src/rockgen/heightfield/heightfieldPatch.js +183 -0
  44. package/src/rockgen/heightfield/stylizedErosionSim.js +356 -0
  45. package/src/rockgen/index.js +14 -0
  46. package/src/rockgen/mesh/meshAttributes.js +374 -0
  47. package/src/rockgen/mesh/meshDocument.js +158 -0
  48. package/src/rockgen/mesh/surfaceNets.js +329 -0
  49. package/src/rockgen/noise/cellularNoise3.js +92 -0
  50. package/src/rockgen/noise/prng.js +62 -0
  51. package/src/rockgen/noise/simplexNoise3.js +89 -0
  52. package/src/rockgen/noise/valueNoise3.js +87 -0
  53. package/src/rockgen/rockDocument.js +255 -0
  54. package/src/rockgen/rockHelpers.js +8 -0
  55. package/src/rockgen/rockgenPresets.js +559 -0
  56. package/src/rockgen/rockgenSettings.js +756 -0
  57. package/src/rockgen/sdf/fieldCompiler.js +544 -0
  58. package/src/rockgen/sdf/sculptEdits.js +66 -0
  59. package/src/rockgen/sdf/sdfModifiers.js +45 -0
  60. package/src/rockgen/sdf/sdfOps.js +37 -0
  61. package/src/rockgen/sdf/sdfPrimitives.js +88 -0
  62. package/src/shaders-tsl/anime.js +963 -0
  63. package/src/shaders-tsl/chunks/character-color.js +64 -0
  64. package/src/shaders-tsl/chunks/character-highlights.js +174 -0
  65. package/src/shaders-tsl/chunks/character-lighting.js +309 -0
  66. package/src/shaders-tsl/chunks/character-material-maps.js +146 -0
  67. package/src/shaders-tsl/chunks/character-roles.js +52 -0
  68. package/src/shaders-tsl/chunks/character-scene-lights.js +270 -0
  69. package/src/shaders-tsl/chunks/character-shadow-color.js +61 -0
  70. package/src/shaders-tsl/chunks/character-skinning.js +140 -0
  71. package/src/shaders-tsl/chunks/environment-color.js +47 -0
  72. package/src/shaders-tsl/chunks/environment-debug.js +79 -0
  73. package/src/shaders-tsl/chunks/environment-lighting.js +260 -0
  74. package/src/shaders-tsl/chunks/environment-sun-shadow.js +87 -0
  75. package/src/shaders-tsl/chunks/foliage-fog.js +60 -0
  76. package/src/shaders-tsl/chunks/pass-depth-color.js +89 -0
  77. package/src/shaders-tsl/chunks/stylized-cloud-shadow.js +70 -0
  78. package/src/shaders-tsl/chunks/water-color.js +190 -0
  79. package/src/shaders-tsl/chunks/water-common.js +124 -0
  80. package/src/shaders-tsl/chunks/water-foam.js +93 -0
  81. package/src/shaders-tsl/chunks/water-lighting.js +116 -0
  82. package/src/shaders-tsl/chunks/water-ripple.js +64 -0
  83. package/src/shaders-tsl/chunks/water-waves.js +100 -0
  84. package/src/shaders-tsl/environment-ao-overlay.js +60 -0
  85. package/src/shaders-tsl/environment.js +680 -0
  86. package/src/shaders-tsl/flower.js +267 -0
  87. package/src/shaders-tsl/grass.js +193 -0
  88. package/src/shaders-tsl/post-composite.js +461 -0
  89. package/src/shaders-tsl/sky.js +175 -0
  90. package/src/shaders-tsl/tree-leaf.js +264 -0
  91. package/src/shaders-tsl/water-breaker.js +423 -0
  92. package/src/shaders-tsl/water-kelp.js +171 -0
  93. package/src/shaders-tsl/water-rain.js +107 -0
  94. package/src/shaders-tsl/water-simulation.js +140 -0
  95. package/src/shaders-tsl/water-splash.js +298 -0
  96. package/src/shaders-tsl/water.js +509 -0
  97. package/src/sky/index.js +2 -0
  98. package/src/sky/stylizedSky.js +341 -0
  99. package/src/toon/characterRenderPasses.js +646 -0
  100. package/src/toon/index.js +4 -0
  101. package/src/toon/settings/alphaSettings.js +170 -0
  102. package/src/toon/settings/averageShadowSettings.js +181 -0
  103. package/src/toon/settings/baseTextureSettings.js +133 -0
  104. package/src/toon/settings/celShadeSettings.js +96 -0
  105. package/src/toon/settings/contactShadowSettings.js +114 -0
  106. package/src/toon/settings/eyeHighlightSettings.js +187 -0
  107. package/src/toon/settings/faceLightingSettings.js +135 -0
  108. package/src/toon/settings/furSettings.js +112 -0
  109. package/src/toon/settings/glitterSettings.js +102 -0
  110. package/src/toon/settings/hairHighlightSettings.js +325 -0
  111. package/src/toon/settings/indirectLightSettings.js +244 -0
  112. package/src/toon/settings/localLightSettings.js +176 -0
  113. package/src/toon/settings/materialMapSettings.js +299 -0
  114. package/src/toon/settings/outlineSettings.js +263 -0
  115. package/src/toon/settings/perspectiveRemovalSettings.js +60 -0
  116. package/src/toon/settings/rimLightSettings.js +268 -0
  117. package/src/toon/settings/sceneShadowSettings.js +147 -0
  118. package/src/toon/settings/selfShadowSettings.js +221 -0
  119. package/src/toon/settings/shadowColorSettings.js +238 -0
  120. package/src/toon/settings/skinToneSettings.js +150 -0
  121. package/src/toon/settings/specularSettings.js +314 -0
  122. package/src/toon/settings/stickerSettings.js +102 -0
  123. package/src/toon/toonMaterialAdapter.js +2235 -0
  124. package/src/toon/toonSettings.js +860 -0
  125. package/src/vegetation/flowerSpecies.js +260 -0
  126. package/src/vegetation/index.js +10 -0
  127. package/src/vegetation/stylizedBush.js +136 -0
  128. package/src/vegetation/stylizedFlower.js +213 -0
  129. package/src/vegetation/stylizedFlowers.js +297 -0
  130. package/src/vegetation/stylizedGrass.js +491 -0
  131. package/src/vegetation/stylizedTree.js +2449 -0
  132. package/src/vegetation/stylizedTreeFoliage.js +691 -0
  133. package/src/vegetation/treeExport.js +300 -0
  134. package/src/vegetation/treeRecipe.js +647 -0
  135. package/src/water/index.js +2 -0
  136. package/src/water/water.js +20 -0
  137. package/src/water/waterBreakerSystem.js +591 -0
  138. package/src/water/waterInteraction.js +193 -0
  139. package/src/water/waterMaterial.js +263 -0
  140. package/src/water/waterRain.js +136 -0
  141. package/src/water/waterRippleSimulation.js +227 -0
  142. package/src/water/waterScenePasses.js +415 -0
  143. package/src/water/waterSettings.js +1138 -0
  144. package/src/water/waterSplashSystem.js +251 -0
  145. package/src/water/waterSurface.js +475 -0
  146. package/src/water/waterVegetation.js +83 -0
@@ -0,0 +1,251 @@
1
+ import * as THREE from 'three';
2
+
3
+ import {
4
+ createWaterSplashDropletsNodeMaterial,
5
+ createWaterSplashSheetsNodeMaterial,
6
+ } from '../shaders-tsl/water-splash.js';
7
+ import { createWaterSettings } from './waterSettings.js';
8
+
9
+ const SHEET_KIND_CROWN = 0;
10
+ const SHEET_KIND_RING = 1;
11
+
12
+ function setSrgbColor(color, rgb) {
13
+ color.setRGB(rgb[0], rgb[1], rgb[2], THREE.SRGBColorSpace);
14
+ }
15
+
16
+ // Procedural splash VFX: ballistic droplet points, a cylindrically billboarded
17
+ // spray crown, and expanding foam rings. Every sprite shape is drawn in the
18
+ // fragment shaders — the system ships with zero texture assets. Particles are
19
+ // GPU-resident: emitting writes spawn attributes once and trajectories are
20
+ // evaluated analytically per frame.
21
+ export class WaterSplashSystem extends THREE.Group {
22
+ constructor({
23
+ dropletPoolSize = 768,
24
+ sheetPoolSize = 96,
25
+ settings,
26
+ } = {}) {
27
+ super();
28
+ this.name = 'WaterSplashSystem';
29
+ this.dropletPoolSize = dropletPoolSize;
30
+ this.sheetPoolSize = sheetPoolSize;
31
+ this.dropletCursor = 0;
32
+ this.sheetCursor = 0;
33
+ this.time = 0;
34
+ this.settings = createWaterSettings(settings);
35
+
36
+ this.buildDroplets();
37
+ this.buildSheets();
38
+ this.applySettings(this.settings);
39
+ }
40
+
41
+ buildDroplets() {
42
+ const count = this.dropletPoolSize;
43
+
44
+ // WGSL has no gl_PointSize: droplet points are instanced billboard quads
45
+ // (dust-motes pattern). Attribute names/layout stay identical so
46
+ // writeDroplet works unchanged; only the attribute class is instanced.
47
+ const quad = new THREE.PlaneGeometry(1, 1);
48
+ const geometry = new THREE.InstancedBufferGeometry();
49
+ geometry.index = quad.index;
50
+ geometry.setAttribute('position', quad.attributes.position);
51
+ geometry.setAttribute('uv', quad.attributes.uv);
52
+ const info = new Float32Array(count * 4);
53
+ for (let i = 0; i < count; i += 1) info[i * 4] = -1e6;
54
+ geometry.setAttribute('aSpawnOrigin', new THREE.InstancedBufferAttribute(new Float32Array(count * 3), 3).setUsage(THREE.DynamicDrawUsage));
55
+ geometry.setAttribute('aVelocity', new THREE.InstancedBufferAttribute(new Float32Array(count * 3), 3).setUsage(THREE.DynamicDrawUsage));
56
+ geometry.setAttribute('aInfo', new THREE.InstancedBufferAttribute(info, 4).setUsage(THREE.DynamicDrawUsage));
57
+ geometry.instanceCount = count;
58
+ geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(), 1e5);
59
+
60
+ this.dropletMaterial = createWaterSplashDropletsNodeMaterial();
61
+ this.droplets = new THREE.Mesh(geometry, this.dropletMaterial);
62
+ this.droplets.frustumCulled = false;
63
+ this.droplets.renderOrder = 30;
64
+ this.add(this.droplets);
65
+ }
66
+
67
+ buildSheets() {
68
+ const count = this.sheetPoolSize;
69
+ // Subdivided so foam rings can drape over wave curvature in the vertex
70
+ // shader instead of lying flat across a swell.
71
+ const plane = new THREE.PlaneGeometry(1, 1, 6, 6);
72
+ const geometry = new THREE.InstancedBufferGeometry();
73
+ geometry.index = plane.index;
74
+ geometry.setAttribute('position', plane.attributes.position);
75
+ geometry.setAttribute('uv', plane.attributes.uv);
76
+
77
+ const info = new Float32Array(count * 4);
78
+ for (let i = 0; i < count; i += 1) info[i * 4] = -1e6;
79
+ geometry.setAttribute('iOrigin', new THREE.InstancedBufferAttribute(new Float32Array(count * 3), 3).setUsage(THREE.DynamicDrawUsage));
80
+ geometry.setAttribute('iInfo', new THREE.InstancedBufferAttribute(info, 4).setUsage(THREE.DynamicDrawUsage));
81
+ geometry.setAttribute('iKind', new THREE.InstancedBufferAttribute(new Float32Array(count), 1).setUsage(THREE.DynamicDrawUsage));
82
+ // Local wave-motion scale at the sheet center (written per frame by the
83
+ // owning WaterSurface); damps the drape in shallows/on the beach film.
84
+ geometry.setAttribute('iSurface', new THREE.InstancedBufferAttribute(new Float32Array(count), 1).setUsage(THREE.DynamicDrawUsage));
85
+ geometry.instanceCount = count;
86
+ geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(), 1e5);
87
+
88
+ this.sheetMaterial = createWaterSplashSheetsNodeMaterial();
89
+
90
+ this.sheets = new THREE.Mesh(geometry, this.sheetMaterial);
91
+ this.sheets.frustumCulled = false;
92
+ this.sheets.renderOrder = 28;
93
+ this.add(this.sheets);
94
+ }
95
+
96
+ applySettings(options = {}) {
97
+ this.settings = createWaterSettings({ ...this.settings, ...options });
98
+ setSrgbColor(this.dropletMaterial.uniforms.uDropletColor.value, this.settings.splashShadeColor);
99
+ setSrgbColor(this.dropletMaterial.uniforms.uHighlightColor.value, this.settings.splashColor);
100
+ setSrgbColor(this.sheetMaterial.uniforms.uSprayColor.value, this.settings.splashColor);
101
+ setSrgbColor(this.sheetMaterial.uniforms.uSprayShadeColor.value, this.settings.splashShadeColor);
102
+ return this;
103
+ }
104
+
105
+ writeDroplet(origin, velocity, life, size, delay = 0) {
106
+ const i = this.dropletCursor;
107
+ this.dropletCursor = (this.dropletCursor + 1) % this.dropletPoolSize;
108
+ const spawn = this.droplets.geometry.attributes.aSpawnOrigin;
109
+ const vel = this.droplets.geometry.attributes.aVelocity;
110
+ const info = this.droplets.geometry.attributes.aInfo;
111
+ spawn.setXYZ(i, origin.x, origin.y, origin.z);
112
+ vel.setXYZ(i, velocity.x, velocity.y, velocity.z);
113
+ info.setXYZW(i, this.time + delay, life, size, Math.random());
114
+ spawn.needsUpdate = true;
115
+ vel.needsUpdate = true;
116
+ info.needsUpdate = true;
117
+ }
118
+
119
+ writeSheet(kind, origin, scale, life, delay = 0) {
120
+ const i = this.sheetCursor;
121
+ this.sheetCursor = (this.sheetCursor + 1) % this.sheetPoolSize;
122
+ const originAttribute = this.sheets.geometry.attributes.iOrigin;
123
+ const info = this.sheets.geometry.attributes.iInfo;
124
+ const kindAttribute = this.sheets.geometry.attributes.iKind;
125
+ originAttribute.setXYZ(i, origin.x, origin.y, origin.z);
126
+ info.setXYZW(i, this.time + delay, life, scale, Math.random());
127
+ kindAttribute.setX(i, kind);
128
+ originAttribute.needsUpdate = true;
129
+ info.needsUpdate = true;
130
+ kindAttribute.needsUpdate = true;
131
+ }
132
+
133
+ // Emits droplets in a cone. position is local to this system's parent.
134
+ emitDroplets(position, {
135
+ count = 12,
136
+ strength = 1,
137
+ coneRadius = 0.16,
138
+ upwardBias = 1,
139
+ } = {}) {
140
+ const scale = this.settings.splashScale;
141
+ for (let i = 0; i < count; i += 1) {
142
+ const angle = Math.random() * Math.PI * 2;
143
+ const radial = (0.45 + Math.random() * 1.25) * Math.pow(strength, 0.6) * scale;
144
+ const upward = (1.5 + Math.random() * 1.9) * Math.pow(Math.min(strength, 2.2), 0.7) * upwardBias * scale;
145
+ const origin = {
146
+ x: position.x + Math.cos(angle) * coneRadius * Math.random() * scale,
147
+ y: position.y + 0.02,
148
+ z: position.z + Math.sin(angle) * coneRadius * Math.random() * scale,
149
+ };
150
+ const velocity = {
151
+ x: Math.cos(angle) * radial,
152
+ y: upward,
153
+ z: Math.sin(angle) * radial,
154
+ };
155
+ const life = 0.5 + Math.random() * 0.5;
156
+ const size = (0.02 + Math.random() * 0.04) * scale * (0.8 + 0.4 * Math.min(strength, 2));
157
+ this.writeDroplet(origin, velocity, life, size);
158
+ }
159
+ }
160
+
161
+ // Full composite splash: droplets + spray crown + expanding foam rings.
162
+ emitSplash(position, { strength = 1 } = {}) {
163
+ const settings = this.settings;
164
+ const effective = strength * settings.splashStrength;
165
+ if (effective <= 0.01) return;
166
+
167
+ const dropletCount = Math.round(
168
+ settings.splashDropletCount * Math.min(Math.max(effective, 0.25), 2.4));
169
+ this.emitDroplets(position, { count: dropletCount, strength: effective });
170
+
171
+ // A couple of chunky slow blobs read as the heavy core of the splash.
172
+ this.emitDroplets(position, {
173
+ count: Math.max(2, Math.round(dropletCount * 0.15)),
174
+ strength: effective * 0.6,
175
+ coneRadius: 0.05,
176
+ upwardBias: 1.25,
177
+ });
178
+
179
+ const crownScale = (0.26 + 0.28 * Math.min(effective, 2.2)) * settings.splashScale;
180
+ this.writeSheet(SHEET_KIND_CROWN, position, crownScale, 0.62);
181
+
182
+ for (let i = 0; i < settings.splashRingCount; i += 1) {
183
+ const ringScale = (0.55 + 0.4 * i + 0.34 * Math.min(effective, 2.2)) * settings.splashScale;
184
+ this.writeSheet(SHEET_KIND_RING, position, ringScale, 0.85 + 0.3 * i, i * 0.09);
185
+ }
186
+ }
187
+
188
+ // Re-anchors live surface-hugging sheets to the animated wave height.
189
+ // heightSampler(localX, localZ) returns the surface height in parent-local
190
+ // space; waveScaleSampler (optional) returns the local 0..1 wave-motion
191
+ // scale used to drape ring geometry over the swell.
192
+ updateSurfaceHeights(heightSampler, waveScaleSampler = null) {
193
+ const origin = this.sheets.geometry.attributes.iOrigin;
194
+ const surface = this.sheets.geometry.attributes.iSurface;
195
+ const info = this.sheets.geometry.attributes.iInfo;
196
+ let dirty = false;
197
+ for (let i = 0; i < this.sheetPoolSize; i += 1) {
198
+ const spawnTime = info.getX(i);
199
+ if (spawnTime < -1e5) continue;
200
+ const age = this.time - spawnTime;
201
+ if (age < -0.5 || age > info.getY(i)) continue;
202
+ const x = origin.getX(i);
203
+ const z = origin.getZ(i);
204
+ origin.setY(i, heightSampler(x, z));
205
+ if (waveScaleSampler) surface.setX(i, waveScaleSampler(x, z));
206
+ dirty = true;
207
+ }
208
+ if (dirty) {
209
+ origin.needsUpdate = true;
210
+ if (waveScaleSampler) surface.needsUpdate = true;
211
+ }
212
+ }
213
+
214
+ // Shares the owning water material's Gerstner uniforms with the sheet
215
+ // shader so rings can evaluate the same spectrum. Uniform objects are
216
+ // shared by reference, keeping preset changes live.
217
+ attachWaveUniforms(sourceMaterial) {
218
+ const waveCount = sourceMaterial?.defines?.WATER_WAVE_COUNT;
219
+ if (!waveCount || !sourceMaterial?.uniforms?.uWavesA) return this;
220
+ // Rebuild the sheet material with the surface's wave uniform nodes in the
221
+ // graph. Own uniforms are carried over so applySettings writes persist.
222
+ this.sheetMaterial = createWaterSplashSheetsNodeMaterial({
223
+ previous: this.sheetMaterial.uniforms,
224
+ waves: {
225
+ waveCount,
226
+ wavesA: sourceMaterial.uniforms.uWavesA,
227
+ wavesB: sourceMaterial.uniforms.uWavesB,
228
+ },
229
+ });
230
+ this.sheets.material = this.sheetMaterial;
231
+ return this;
232
+ }
233
+
234
+ update(time, renderer) {
235
+ this.time = time;
236
+ this.dropletMaterial.uniforms.uTime.value = time;
237
+ this.sheetMaterial.uniforms.uTime.value = time;
238
+ if (renderer) {
239
+ this.dropletMaterial.uniforms.uPixelRatio.value = renderer.getPixelRatio();
240
+ const height = renderer.domElement?.clientHeight || 540;
241
+ this.dropletMaterial.uniforms.uPointScale.value = height * 0.9;
242
+ }
243
+ }
244
+
245
+ dispose() {
246
+ this.droplets.geometry.dispose();
247
+ this.dropletMaterial.dispose();
248
+ this.sheets.geometry.dispose();
249
+ this.sheetMaterial.dispose();
250
+ }
251
+ }