Skip to content

Commit 8d3c12f

Browse files
authored
Examples: Add procedural city generator. (#2237)
* Update three.js * Update * Add jsdoc * Update patch and delete jsdoc * Add examples * Update patch and delete examples * Update declarations * Update * Update * Update declarations * Add jsdoc * Update patch and delete jsdoc * Update declarations * Add jsdoc * Update patch and delete jsdoc * Update declarations
1 parent b206d62 commit 8d3c12f

7 files changed

Lines changed: 535 additions & 1 deletion

File tree

examples-testing/changes.patch

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15798,6 +15798,73 @@ index 4afa5d2d0..715c323a2 100644
1579815798
});
1579915799

1580015800
render();
15801+
diff --git a/examples-testing/examples/webgpu_generator_building.ts b/examples-testing/examples/webgpu_generator_building.ts
15802+
index 9b9b49fdf..9081ba6d4 100644
15803+
--- a/examples-testing/examples/webgpu_generator_building.ts
15804+
+++ b/examples-testing/examples/webgpu_generator_building.ts
15805+
@@ -10,8 +10,14 @@ import {
15806+
pickBuildingColor,
15807+
} from 'three/addons/generators/city/SkyscraperGenerator.js';
15808+
15809+
-let camera, scene, renderer, controls, generator, building, material;
15810+
-let sky, sunLight, pmremGenerator, envScene;
15811+
+let camera: THREE.PerspectiveCamera,
15812+
+ scene: THREE.Scene,
15813+
+ renderer: THREE.WebGPURenderer,
15814+
+ controls: OrbitControls,
15815+
+ generator,
15816+
+ building: THREE.Mesh,
15817+
+ material: THREE.MeshStandardNodeMaterial;
15818+
+let sky: SkyMesh, sunLight: THREE.DirectionalLight, pmremGenerator: THREE.PMREMGenerator, envScene: THREE.Scene;
15819+
15820+
// reused by updateSun(): the current sun direction and the key-light
15821+
// colours it blends between as the sun nears the horizon or climbs high
15822+
@@ -109,7 +115,7 @@ async function init() {
15823+
material = createSkyscraperMaterial(baseColor);
15824+
generate();
15825+
15826+
- const gui = renderer.inspector.createParameters('Building');
15827+
+ const gui = (renderer.inspector as Inspector).createParameters('Building');
15828+
gui.add(parameters, 'seed', 0, 100, 1).onChange(generate);
15829+
gui.add(parameters, 'height', 60, 200, 1).onChange(generate);
15830+
gui.add(parameters, 'width', 18, 60, 1).onChange(generate);
15831+
diff --git a/examples-testing/examples/webgpu_generator_city.ts b/examples-testing/examples/webgpu_generator_city.ts
15832+
index beb8da8cc..95b976d46 100644
15833+
--- a/examples-testing/examples/webgpu_generator_city.ts
15834+
+++ b/examples-testing/examples/webgpu_generator_city.ts
15835+
@@ -7,9 +7,20 @@ import { SkyMesh } from 'three/addons/objects/SkyMesh.js';
15836+
import { bloom } from 'three/addons/tsl/display/BloomNode.js';
15837+
import { CityGenerator, createBuildingMaterial, createRoadMaterial } from 'three/addons/generators/CityGenerator.js';
15838+
15839+
-let camera, scene, renderer, controls, timer;
15840+
-let cityGroup, materials, city, renderPipeline;
15841+
-let sky, sun, sunLight, pmremGenerator, envScene;
15842+
+let camera: THREE.PerspectiveCamera,
15843+
+ scene: THREE.Scene,
15844+
+ renderer: THREE.WebGPURenderer,
15845+
+ controls: FirstPersonControls,
15846+
+ timer: THREE.Timer;
15847+
+let cityGroup: THREE.Group,
15848+
+ materials: { building: THREE.MeshStandardNodeMaterial },
15849+
+ city: CityGenerator,
15850+
+ renderPipeline: THREE.RenderPipeline;
15851+
+let sky: SkyMesh,
15852+
+ sun: THREE.Vector3,
15853+
+ sunLight: THREE.DirectionalLight,
15854+
+ pmremGenerator: THREE.PMREMGenerator,
15855+
+ envScene: THREE.Scene;
15856+
15857+
const parameters = {
15858+
seed: 94,
15859+
@@ -107,7 +118,7 @@ async function init() {
15860+
15861+
// parameters
15862+
15863+
- const gui = renderer.inspector.createParameters('City');
15864+
+ const gui = (renderer.inspector as Inspector).createParameters('City');
15865+
gui.add(parameters, 'seed', 0, 100, 1).onChange(generateCity);
15866+
gui.add(parameters, 'timeOfDay', 6, 18, 0.1).name('time of day').onChange(updateSun);
15867+
gui.add(renderer, 'toneMappingExposure', 0.01, 1).name('exposure');
1580115868
diff --git a/examples-testing/examples/webgpu_geometry_loft.ts b/examples-testing/examples/webgpu_geometry_loft.ts
1580215869
index f378f3384..d1562c106 100644
1580315870
--- a/examples-testing/examples/webgpu_geometry_loft.ts

jsdoc-testing/changes.patch

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,272 @@ index d3c23f934..214d0cf95 100644
5656
/**
5757
* Splits the CSM frustum by the given array. The new CSM frustum are pushed into the given
5858
* target array.
59+
diff --git a/jsdoc-testing/jsdoc/examples/jsm/generators/CityGenerator.d.ts b/jsdoc-testing/jsdoc/examples/jsm/generators/CityGenerator.d.ts
60+
index baf210642..ddf63e336 100644
61+
--- a/jsdoc-testing/jsdoc/examples/jsm/generators/CityGenerator.d.ts
62+
+++ b/jsdoc-testing/jsdoc/examples/jsm/generators/CityGenerator.d.ts
63+
@@ -1,3 +1,36 @@
64+
+import { Group, Material, MeshStandardNodeMaterial } from 'three/webgpu';
65+
+import { SidewalkGenerator } from './city/SidewalkGenerator.js';
66+
+import { SkyscraperGenerator } from './city/SkyscraperGenerator.js';
67+
+
68+
+export interface CityGeneratorParameters {
69+
+ seed: number;
70+
+ street: number;
71+
+ lot: number;
72+
+ lotsX: number;
73+
+ lotsZ: number;
74+
+ blocksX: number;
75+
+ blocksZ: number;
76+
+ curbHeight: number;
77+
+ curbRadius: number;
78+
+}
79+
+
80+
+export interface CityGeneratorLayout {
81+
+ street: number;
82+
+ lot: number;
83+
+ lotsX: number;
84+
+ lotsZ: number;
85+
+ blocksX: number;
86+
+ blocksZ: number;
87+
+ blockW: number;
88+
+ blockD: number;
89+
+ cityW: number;
90+
+ cityD: number;
91+
+}
92+
+
93+
+export interface CityGeneratorMaterials {
94+
+ building?: Material | undefined;
95+
+}
96+
+
97+
/**
98+
* Lays out a grid of city blocks and fills each lot with a {@link SkyscraperGenerator}
99+
* tower of its own seed, height and footprint, optionally on raised sidewalk
100+
@@ -14,59 +47,29 @@
101+
* ```
102+
*/
103+
export class CityGenerator {
104+
- constructor(parameters?: {});
105+
- parameters: {
106+
- seed: number;
107+
- street: number;
108+
- lot: number;
109+
- lotsX: number;
110+
- lotsZ: number;
111+
- blocksX: number;
112+
- blocksZ: number;
113+
- curbHeight: number;
114+
- curbRadius: number;
115+
- };
116+
- layout: {
117+
- street: any;
118+
- lot: any;
119+
- lotsX: any;
120+
- lotsZ: any;
121+
- blocksX: any;
122+
- blocksZ: any;
123+
- blockW: number;
124+
- blockD: number;
125+
- cityW: number;
126+
- cityD: number;
127+
- };
128+
- generators: any[];
129+
+ constructor(parameters?: Partial<CityGeneratorParameters>);
130+
+
131+
+ parameters: CityGeneratorParameters;
132+
+ layout: CityGeneratorLayout;
133+
+
134+
+ generators: SkyscraperGenerator[];
135+
sidewalk: SidewalkGenerator;
136+
group: Group | null;
137+
- build(materials?: {}): Group;
138+
+
139+
+ build(materials?: CityGeneratorMaterials): Group;
140+
dispose(): void;
141+
+
142+
+ static defaults: CityGeneratorParameters;
143+
}
144+
-export namespace CityGenerator {
145+
- namespace defaults {
146+
- let seed: number;
147+
- let street: number;
148+
- let lot: number;
149+
- let lotsX: number;
150+
- let lotsZ: number;
151+
- let blocksX: number;
152+
- let blocksZ: number;
153+
- let curbHeight: number;
154+
- let curbRadius: number;
155+
- }
156+
-}
157+
+
158+
/**
159+
* The shared material every tower in a {@link CityGenerator} is dressed with: one flat
160+
* masonry colour per lot, picked from a palette by hashing the lot's grid cell.
161+
*/
162+
-export function createBuildingMaterial(layout: any, seed?: number): MeshStandardNodeMaterial;
163+
+export function createBuildingMaterial(layout: CityGeneratorLayout, seed?: number): MeshStandardNodeMaterial;
164+
+
165+
/**
166+
* The road surface: wet asphalt with lane lines and crosswalks aligned to a
167+
* {@link CityGenerator} layout. Apply it to a ground plane sized to the city.
168+
*/
169+
-export function createRoadMaterial(layout: any): MeshStandardNodeMaterial;
170+
-import { SidewalkGenerator } from './city/SidewalkGenerator.js';
171+
-import { Group } from 'three';
172+
-import { MeshStandardNodeMaterial } from 'three/webgpu';
173+
+export function createRoadMaterial(layout: CityGeneratorLayout): MeshStandardNodeMaterial;
174+
diff --git a/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts b/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts
175+
index 81c1a0ec9..d560e432c 100644
176+
--- a/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts
177+
+++ b/jsdoc-testing/jsdoc/examples/jsm/generators/city/SidewalkGenerator.d.ts
178+
@@ -1,3 +1,14 @@
179+
+import { Group, Matrix4, MeshStandardNodeMaterial } from 'three/webgpu';
180+
+
181+
+export interface SidewalkGeneratorParameters {
182+
+ width: number;
183+
+ depth: number;
184+
+ height: number;
185+
+ radius: number;
186+
+ curbWidth: number;
187+
+ curbLip: number;
188+
+}
189+
+
190+
/**
191+
* Generates the raised sidewalk for a city's blocks: per block, a rounded-corner concrete
192+
* slab rimmed by a distinct granite kerbstone that stands proud of the walking surface and
193+
@@ -14,30 +25,16 @@
194+
* ```
195+
*/
196+
export class SidewalkGenerator {
197+
- constructor(parameters?: {});
198+
- parameters: {
199+
- width: number;
200+
- depth: number;
201+
- height: number;
202+
- radius: number;
203+
- curbWidth: number;
204+
- curbLip: number;
205+
- };
206+
+ constructor(parameters?: Partial<SidewalkGeneratorParameters>);
207+
+
208+
+ parameters: SidewalkGeneratorParameters;
209+
+
210+
material: MeshStandardNodeMaterial | null;
211+
curbMaterial: MeshStandardNodeMaterial | null;
212+
mesh: Group | null;
213+
- build(placements: any): Group;
214+
+
215+
+ build(placements: Matrix4[]): Group;
216+
dispose(): void;
217+
+
218+
+ static defaults: SidewalkGeneratorParameters;
219+
}
220+
-export namespace SidewalkGenerator {
221+
- namespace defaults {
222+
- let width: number;
223+
- let depth: number;
224+
- let height: number;
225+
- let radius: number;
226+
- let curbWidth: number;
227+
- let curbLip: number;
228+
- }
229+
-}
230+
-import { MeshStandardNodeMaterial } from 'three/webgpu';
231+
-import { Group } from 'three/webgpu';
232+
diff --git a/jsdoc-testing/jsdoc/examples/jsm/generators/city/SkyscraperGenerator.d.ts b/jsdoc-testing/jsdoc/examples/jsm/generators/city/SkyscraperGenerator.d.ts
233+
index cfca639f0..75965dd21 100644
234+
--- a/jsdoc-testing/jsdoc/examples/jsm/generators/city/SkyscraperGenerator.d.ts
235+
+++ b/jsdoc-testing/jsdoc/examples/jsm/generators/city/SkyscraperGenerator.d.ts
236+
@@ -1,3 +1,29 @@
237+
+import { Color, Material, Mesh, MeshStandardNodeMaterial, Node } from 'three/webgpu';
238+
+
239+
+export interface SkyscraperGeneratorDefaultParameters {
240+
+ seed: number;
241+
+ totalHeight: number;
242+
+ floorHeight: number;
243+
+ bayWidth: number;
244+
+ stringCourseEvery: number;
245+
+ chamferWidth: number;
246+
+ chamferCornerX: number;
247+
+ chamferCornerZ: number;
248+
+ setbackDepth: number;
249+
+ acChance: number;
250+
+}
251+
+
252+
+export interface SkyscraperGeneratorParameters extends SkyscraperGeneratorDefaultParameters {
253+
+ footprint: { width: number; depth: number };
254+
+ tierFractions: { base: number; crown: number };
255+
+ pierWidth: number;
256+
+ pierDepth: number;
257+
+ windowReveal: number;
258+
+ stringCourseHeight: number;
259+
+ archBayWidthRatio: number;
260+
+ archRise: number;
261+
+}
262+
+
263+
/**
264+
* Generates intricate, tripartite "Beaux-Arts / Neo-Gothic" terracotta
265+
* skyscrapers from a small set of parameters.
266+
@@ -19,29 +45,21 @@
267+
* ```
268+
*/
269+
export class SkyscraperGenerator {
270+
- constructor(parameters?: {}, material?: null);
271+
- parameters: {};
272+
- material: any;
273+
+ constructor(parameters?: Partial<SkyscraperGeneratorParameters>, material?: Material);
274+
+
275+
+ parameters: Partial<SkyscraperGeneratorParameters>;
276+
+ material: Material;
277+
+
278+
mesh: Mesh | null;
279+
- setParameters(parameters: any): this;
280+
+
281+
+ setParameters(parameters: Partial<SkyscraperGeneratorParameters>): this;
282+
build(): Mesh;
283+
rebuild(): Mesh;
284+
dispose(): void;
285+
+
286+
+ static defaults: SkyscraperGeneratorDefaultParameters;
287+
}
288+
-export namespace SkyscraperGenerator {
289+
- namespace defaults {
290+
- let seed: number;
291+
- let totalHeight: number;
292+
- let floorHeight: number;
293+
- let bayWidth: number;
294+
- let stringCourseEvery: number;
295+
- let chamferWidth: number;
296+
- let chamferCornerX: number;
297+
- let chamferCornerZ: number;
298+
- let setbackDepth: number;
299+
- let acChance: number;
300+
- }
301+
-}
302+
+
303+
/**
304+
* The facade material: a single MeshStandardNodeMaterial that reads the baked
305+
* per-vertex `partId` and reproduces every zone — procedural terracotta brickwork
306+
@@ -52,14 +70,14 @@ export namespace SkyscraperGenerator {
307+
* masonry colour as a TSL node: pass a `uniform( Color )` for a single tower, or a
308+
* per-fragment palette pick for a city, so the same material dresses both.
309+
*/
310+
-export function createSkyscraperMaterial(buildingBase?: any): MeshStandardNodeMaterial;
311+
+export function createSkyscraperMaterial(buildingBase?: Node<'color'> | Color): MeshStandardNodeMaterial;
312+
+
313+
/**
314+
* The NYC masonry palette every tower is dressed from ( hex colours ): limestone-dominant
315+
* with terracotta accents. Shared by the single-tower example and {@link CityGenerator}'s
316+
* building material so both stay in sync.
317+
*/
318+
export const buildingPalette: number[];
319+
+
320+
/** Picks one {@link buildingPalette} colour ( a hex number ) for a tower from its seed. */
321+
-export function pickBuildingColor(seed: any): number;
322+
-import { Mesh } from 'three';
323+
-import { MeshStandardNodeMaterial } from 'three/webgpu';
324+
+export function pickBuildingColor(seed: number): number;
59325
diff --git a/jsdoc-testing/jsdoc/examples/jsm/geometries/LoftGeometry.d.ts b/jsdoc-testing/jsdoc/examples/jsm/geometries/LoftGeometry.d.ts
60326
index 1e007e460..a2de0b896 100644
61327
--- a/jsdoc-testing/jsdoc/examples/jsm/geometries/LoftGeometry.d.ts

jsdoc-testing/declarations.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { argv } from 'node:process';
44

55
const files = [
66
'examples/jsm/csm/CSMFrustum',
7+
'examples/jsm/generators/city/SidewalkGenerator',
8+
'examples/jsm/generators/city/SkyscraperGenerator',
9+
'examples/jsm/generators/CityGenerator',
710
'examples/jsm/geometries/LoftGeometry',
811
'examples/jsm/lighting/ClusteredLighting',
912
'examples/jsm/lighting/LightProbeGrid',

0 commit comments

Comments
 (0)