Skip to content

Commit faa4216

Browse files
authored
Examples: Improve webgpu_custom_fog with terrain and forest generators. (#2238)
* Update three.js * Update * Add jsdoc * Update patch and delete jsdoc * Update declarations * Add examples * Update patch and delete examples
1 parent 8d3c12f commit faa4216

6 files changed

Lines changed: 386 additions & 10 deletions

File tree

examples-testing/changes.patch

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15563,20 +15563,39 @@ index 6fbdb55ae..fd5ec5705 100644
1556315563
init();
1556415564

1556515565
diff --git a/examples-testing/examples/webgpu_custom_fog.ts b/examples-testing/examples/webgpu_custom_fog.ts
15566-
index bcfcb0fd3..be07fc038 100644
15566+
index 8b1036a14..b3ec9805b 100644
1556715567
--- a/examples-testing/examples/webgpu_custom_fog.ts
1556815568
+++ b/examples-testing/examples/webgpu_custom_fog.ts
15569-
@@ -4,8 +4,8 @@ import { color, fog, float, positionWorld, triNoise3D, positionView, normalWorld
15570-
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
15571-
import { Inspector } from 'three/addons/inspector/Inspector.js';
15569+
@@ -7,9 +7,17 @@ import { SkyMesh } from 'three/addons/objects/SkyMesh.js';
15570+
import { TerrainGenerator } from 'three/addons/generators/TerrainGenerator.js';
15571+
import { ForestGenerator } from 'three/addons/generators/ForestGenerator.js';
1557215572

15573-
-let camera, scene, renderer;
15574-
-let controls;
15575-
+let camera: THREE.PerspectiveCamera, scene: THREE.Scene, renderer: THREE.WebGPURenderer;
15576-
+let controls: OrbitControls;
15573+
-let camera, scene, renderer, controls, timer;
15574+
-let terrain, forest, terrainGroup, forestGroup;
15575+
-let sky, sun, sunLight, pmremGenerator, envScene;
15576+
+let camera: THREE.PerspectiveCamera,
15577+
+ scene: THREE.Scene,
15578+
+ renderer: THREE.WebGPURenderer,
15579+
+ controls: FirstPersonControls,
15580+
+ timer: THREE.Timer;
15581+
+let terrain: TerrainGenerator, forest: ForestGenerator, terrainGroup: THREE.Group, forestGroup: THREE.Group;
15582+
+let sky: SkyMesh,
15583+
+ sun: THREE.Vector3,
15584+
+ sunLight: THREE.DirectionalLight,
15585+
+ pmremGenerator: THREE.PMREMGenerator,
15586+
+ envScene: THREE.Scene;
1557715587

15578-
init();
15588+
const parameters = {
15589+
elevation: 11, // sun height above the horizon, in degrees ( low = golden hour )
15590+
@@ -126,7 +134,7 @@ async function init() {
15591+
15592+
// gui
15593+
15594+
- const gui = renderer.inspector.createParameters('Settings');
15595+
+ const gui = (renderer.inspector as Inspector).createParameters('Settings');
1557915596

15597+
const skyFolder = gui.addFolder('Sun');
15598+
skyFolder.add(parameters, 'elevation', 1, 40).step(0.5).name('elevation').onChange(updateSun);
1558015599
diff --git a/examples-testing/examples/webgpu_custom_fog_background.ts b/examples-testing/examples/webgpu_custom_fog_background.ts
1558115600
index a9b619345..e482a1e2e 100644
1558215601
--- a/examples-testing/examples/webgpu_custom_fog_background.ts

jsdoc-testing/changes.patch

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,215 @@ index baf210642..ddf63e336 100644
171171
-import { Group } from 'three';
172172
-import { MeshStandardNodeMaterial } from 'three/webgpu';
173173
+export function createRoadMaterial(layout: CityGeneratorLayout): MeshStandardNodeMaterial;
174+
diff --git a/jsdoc-testing/jsdoc/examples/jsm/generators/ForestGenerator.d.ts b/jsdoc-testing/jsdoc/examples/jsm/generators/ForestGenerator.d.ts
175+
index 4b2772243..d481a3379 100644
176+
--- a/jsdoc-testing/jsdoc/examples/jsm/generators/ForestGenerator.d.ts
177+
+++ b/jsdoc-testing/jsdoc/examples/jsm/generators/ForestGenerator.d.ts
178+
@@ -1,3 +1,25 @@
179+
+import { Group, InstancedMesh, MeshStandardNodeMaterial, Node, UniformNode, Vector3 } from 'three/webgpu';
180+
+import { TerrainGenerator } from './TerrainGenerator.js';
181+
+
182+
+export interface ForestGeneratorParameters {
183+
+ seed: number;
184+
+ count: number;
185+
+ detail: number;
186+
+ radius: number;
187+
+ height: number;
188+
+ distortion: number;
189+
+ sink: number;
190+
+ altitudeMin: number;
191+
+ altitudeMax: number;
192+
+ minSlope: number;
193+
+ densityFrequency: number;
194+
+ minScale: number;
195+
+ maxScale: number;
196+
+ from: number;
197+
+ to: number;
198+
+ castShadow: boolean;
199+
+}
200+
+
201+
/**
202+
* Carpets a {@link TerrainGenerator} ( or anything exposing `sampleHeight`,
203+
* `sampleSlope`, `minY`, `maxY` and `parameters.size` ) with a forest of hundreds
204+
@@ -18,55 +40,24 @@
205+
* ```
206+
*/
207+
export class ForestGenerator {
208+
- constructor(parameters?: {});
209+
- parameters: {
210+
- seed: number;
211+
- count: number;
212+
- detail: number;
213+
- radius: number;
214+
- height: number;
215+
- distortion: number;
216+
- sink: number;
217+
- altitudeMin: number;
218+
- altitudeMax: number;
219+
- minSlope: number;
220+
- densityFrequency: number;
221+
- minScale: number;
222+
- maxScale: number;
223+
- from: number;
224+
- to: number;
225+
- castShadow: boolean;
226+
- };
227+
- from: import("three/webgpu").UniformNode;
228+
- to: import("three/webgpu").UniformNode;
229+
- _cameraPosition: import("three/webgpu").UniformNode;
230+
+ constructor(parameters?: Partial<ForestGeneratorParameters>);
231+
+
232+
+ parameters: ForestGeneratorParameters;
233+
+
234+
+ from: UniformNode<'float', number>;
235+
+ to: UniformNode<'float', number>;
236+
+
237+
material: MeshStandardNodeMaterial;
238+
mesh: InstancedMesh | null;
239+
group: Group | null;
240+
- build(terrain: any): Group;
241+
- setCameraPosition(position: any): void;
242+
+
243+
+ build(terrain: TerrainGenerator): Group;
244+
+ setCameraPosition(position: Vector3): void;
245+
dispose(): void;
246+
+
247+
+ static defaults: ForestGeneratorParameters
248+
}
249+
-export namespace ForestGenerator {
250+
- namespace defaults {
251+
- let seed: number;
252+
- let count: number;
253+
- let detail: number;
254+
- let radius: number;
255+
- let height: number;
256+
- let distortion: number;
257+
- let sink: number;
258+
- let altitudeMin: number;
259+
- let altitudeMax: number;
260+
- let minSlope: number;
261+
- let densityFrequency: number;
262+
- let minScale: number;
263+
- let maxScale: number;
264+
- let from: number;
265+
- let to: number;
266+
- let castShadow: boolean;
267+
- }
268+
-}
269+
+
270+
/**
271+
* The single material shared by every tree in a {@link ForestGenerator}. A plain
272+
* MeshStandardNodeMaterial lit by the scene — only the surface is authored: deep
273+
@@ -81,7 +72,4 @@ export namespace ForestGenerator {
274+
* @param {Node} to - distance past which no tree is drawn.
275+
* @return {MeshStandardNodeMaterial}
276+
*/
277+
-export function createForestMaterial(from: Node, to: Node, camPos: any): MeshStandardNodeMaterial;
278+
-import { MeshStandardNodeMaterial } from 'three/webgpu';
279+
-import { InstancedMesh } from 'three';
280+
-import { Group } from 'three';
281+
+export function createForestMaterial(from: Node<'float'>, to: Node<'float'>, camPos: Node<'vec3'>): MeshStandardNodeMaterial;
282+
diff --git a/jsdoc-testing/jsdoc/examples/jsm/generators/TerrainGenerator.d.ts b/jsdoc-testing/jsdoc/examples/jsm/generators/TerrainGenerator.d.ts
283+
index a5b279bf6..7ca0512e6 100644
284+
--- a/jsdoc-testing/jsdoc/examples/jsm/generators/TerrainGenerator.d.ts
285+
+++ b/jsdoc-testing/jsdoc/examples/jsm/generators/TerrainGenerator.d.ts
286+
@@ -1,3 +1,22 @@
287+
+import { BufferGeometry, Group, MeshStandardNodeMaterial, UniformNode } from 'three/webgpu';
288+
+
289+
+export interface TerrainGeneratorParameters {
290+
+ seed: number;
291+
+ size: number;
292+
+ segments: number;
293+
+ heightScale: number;
294+
+ frequency: number;
295+
+ octaves: number;
296+
+ lacunarity: number;
297+
+ gain: number;
298+
+ erosion: number;
299+
+ warp: number;
300+
+ valleyBias: number;
301+
+ seaLevel: number;
302+
+ talus: number;
303+
+ talusPasses: number;
304+
+}
305+
+
306+
/**
307+
* Bakes a procedural mountain range into a single {@link THREE.BufferGeometry} and
308+
* returns a `THREE.Group` ready to add to a scene.
309+
@@ -22,55 +41,27 @@
310+
* ```
311+
*/
312+
export class TerrainGenerator {
313+
- constructor(parameters?: {});
314+
- parameters: {
315+
- seed: number;
316+
- size: number;
317+
- segments: number;
318+
- heightScale: number;
319+
- frequency: number;
320+
- octaves: number;
321+
- lacunarity: number;
322+
- gain: number;
323+
- erosion: number;
324+
- warp: number;
325+
- valleyBias: number;
326+
- seaLevel: number;
327+
- talus: number;
328+
- talusPasses: number;
329+
- };
330+
- minHeight: import("three/webgpu").UniformNode;
331+
- maxHeight: import("three/webgpu").UniformNode;
332+
+ constructor(parameters?: Partial<TerrainGeneratorParameters>);
333+
+
334+
+ parameters: TerrainGeneratorParameters;
335+
+
336+
+ minHeight: UniformNode<'float', number>;
337+
+ maxHeight: UniformNode<'float', number>;
338+
+
339+
material: MeshStandardNodeMaterial;
340+
geometry: BufferGeometry | null;
341+
group: Group | null;
342+
+
343+
+ heights?: Float32Array;
344+
+ gridSize?: number;
345+
+ minY?: number;
346+
+ maxY?: number;
347+
+
348+
build(): Group;
349+
- heights: Float32Array<ArrayBuffer> | undefined;
350+
- gridSize: number | undefined;
351+
- minY: number | undefined;
352+
- maxY: number | undefined;
353+
- sampleHeight(x: any, z: any): number;
354+
- sampleSlope(x: any, z: any): number;
355+
+
356+
+ sampleHeight(x: number, z: number): number;
357+
+ sampleSlope(x: number, z: number): number;
358+
dispose(): void;
359+
+
360+
+ static defaults: TerrainGeneratorParameters;
361+
}
362+
-export namespace TerrainGenerator {
363+
- namespace defaults {
364+
- let seed: number;
365+
- let size: number;
366+
- let segments: number;
367+
- let heightScale: number;
368+
- let frequency: number;
369+
- let octaves: number;
370+
- let lacunarity: number;
371+
- let gain: number;
372+
- let erosion: number;
373+
- let warp: number;
374+
- let valleyBias: number;
375+
- let seaLevel: number;
376+
- let talus: number;
377+
- let talusPasses: number;
378+
- }
379+
-}
380+
-import { MeshStandardNodeMaterial } from 'three/webgpu';
381+
-import { BufferGeometry } from 'three';
382+
-import { Group } from 'three';
174383
diff --git a/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts b/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts
175384
index 81c1a0ec9..d560e432c 100644
176385
--- a/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts

jsdoc-testing/declarations.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const files = [
77
'examples/jsm/generators/city/SidewalkGenerator',
88
'examples/jsm/generators/city/SkyscraperGenerator',
99
'examples/jsm/generators/CityGenerator',
10+
'examples/jsm/generators/ForestGenerator',
11+
'examples/jsm/generators/TerrainGenerator',
1012
'examples/jsm/geometries/LoftGeometry',
1113
'examples/jsm/lighting/ClusteredLighting',
1214
'examples/jsm/lighting/LightProbeGrid',
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Group, InstancedMesh, MeshStandardNodeMaterial, Node, UniformNode, Vector3 } from "three/webgpu";
2+
import { TerrainGenerator } from "./TerrainGenerator.js";
3+
4+
export interface ForestGeneratorParameters {
5+
seed: number;
6+
count: number;
7+
detail: number;
8+
radius: number;
9+
height: number;
10+
distortion: number;
11+
sink: number;
12+
altitudeMin: number;
13+
altitudeMax: number;
14+
minSlope: number;
15+
densityFrequency: number;
16+
minScale: number;
17+
maxScale: number;
18+
from: number;
19+
to: number;
20+
castShadow: boolean;
21+
}
22+
23+
/**
24+
* Carpets a {@link TerrainGenerator} ( or anything exposing `sampleHeight`,
25+
* `sampleSlope`, `minY`, `maxY` and `parameters.size` ) with a forest of hundreds
26+
* of thousands of trees in a single draw call.
27+
*
28+
* Each tree is the cheapest thing that still reads as a tree: a ~20-face icosphere
29+
* squashed into a tapered teardrop and lumped with a little noise, carrying a baked
30+
* dark-base / bright-top gradient. Tens of triangles each, so a single
31+
* {@link THREE.InstancedMesh} of half a million of them costs one draw call. Trees
32+
* are placed by rejection sampling against ecological rules — a min/max altitude
33+
* band ( above the mist floor, below the snowline ), a slope limit ( none on
34+
* cliffs ) and a low-frequency density mask that opens clearings — then jittered in
35+
* yaw, lean and ( squared-biased ) scale so the stand never reads as copies.
36+
*
37+
* ```js
38+
* const forest = new ForestGenerator( { count: 500000 } );
39+
* scene.add( forest.build( terrain ) );
40+
* ```
41+
*/
42+
export class ForestGenerator {
43+
constructor(parameters?: Partial<ForestGeneratorParameters>);
44+
45+
parameters: ForestGeneratorParameters;
46+
47+
from: UniformNode<"float", number>;
48+
to: UniformNode<"float", number>;
49+
50+
material: MeshStandardNodeMaterial;
51+
mesh: InstancedMesh | null;
52+
group: Group | null;
53+
54+
build(terrain: TerrainGenerator): Group;
55+
setCameraPosition(position: Vector3): void;
56+
dispose(): void;
57+
58+
static defaults: ForestGeneratorParameters;
59+
}
60+
61+
/**
62+
* The single material shared by every tree in a {@link ForestGenerator}. A plain
63+
* MeshStandardNodeMaterial lit by the scene — only the surface is authored: deep
64+
* shadowed green in the recesses rising to a bright, yellow-green sunlit crown,
65+
* mottled into needle clumps by 3D noise, with a matching bump so the clumps catch
66+
* the light. Half a million instanced blobs makes this mesh vertex-bound, so the
67+
* regional colour drift is baked to a per-instance attribute ( no shader noise for it ),
68+
* and the costly clump noise + bump are **gated by distance** — full detail on the near
69+
* trees ( where it reads ), skipped on the far canopy ( where it is sub-pixel ).
70+
*
71+
* @param {Node} from - distance within which every tree is drawn.
72+
* @param {Node} to - distance past which no tree is drawn.
73+
* @return {MeshStandardNodeMaterial}
74+
*/
75+
export function createForestMaterial(
76+
from: Node<"float">,
77+
to: Node<"float">,
78+
camPos: Node<"vec3">,
79+
): MeshStandardNodeMaterial;

0 commit comments

Comments
 (0)