awacke1 commited on
Commit
ec2be1b
Β·
verified Β·
1 Parent(s): 1a55305

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -19
app.py CHANGED
@@ -4,11 +4,11 @@ import streamlit.components.v1 as components
4
  st.set_page_config(page_title="3D City Evolution Simulator", layout="wide")
5
 
6
  st.title("3D City Evolution Simulator")
7
- st.write("Watch a 3D city grow with lakes, hills, and evolving blocks")
8
 
9
  # Sliders for container size with initial 3:4 aspect ratio
10
- max_width = min(1200, st.session_state.get('window_width', 1200)) # Use a reasonable max or screen width
11
- max_height = min(1600, st.session_state.get('window_height', 1600)) # Use a reasonable max or screen height
12
 
13
  col1, col2 = st.columns(2)
14
  with col1:
@@ -102,14 +102,32 @@ html_code = f"""
102
  let position = basePos.clone();
103
  let direction = new THREE.Vector3(0, 1, 0);
104
  const structure = new THREE.Group();
105
- let baseWidth = 1.5; // Starting wider base
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  for (let char of this.generate()) {{
108
  switch(char) {{
109
  case 'F':
110
  if (height < maxHeight) {{
111
- const width = baseWidth * (1 - height / maxHeight); // Narrower as it goes up
112
- const floorHeight = 2 + Math.random() * 2; // Taller floors
113
  const geo = new THREE.BoxGeometry(width, floorHeight, width);
114
  const mat = new THREE.MeshPhongMaterial({{
115
  color: new THREE.Color(0.5 + Math.random() * 0.5,
@@ -118,6 +136,7 @@ html_code = f"""
118
  }});
119
  const floor = new THREE.Mesh(geo, mat);
120
  floor.position.copy(position).add(new THREE.Vector3(0, floorHeight/2, 0));
 
121
  structure.add(floor);
122
  position.y += floorHeight;
123
  height += floorHeight;
@@ -144,6 +163,7 @@ html_code = f"""
144
  class CitySimulator {{
145
  constructor() {{
146
  this.blocks = [];
 
147
  this.blockSize = 10;
148
  this.maxBuildingsPerBlock = 5;
149
  this.generation = 0;
@@ -189,14 +209,58 @@ html_code = f"""
189
  }}
190
  }}
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  evolve(scene) {{
193
  this.generation++;
194
  if (this.blocks.length < 20) {{
195
- const x = (Math.random() - 0.5) * 90; // Adjusted for 3:4
196
  const z = (Math.random() - 0.5) * 120;
197
- if (!this.isInLake(x, z)) this.addBlock(scene, x, z);
 
 
 
 
 
 
198
  }}
199
  this.blocks.forEach(block => this.evolveBlock(scene, block));
 
200
  this.updateStats();
201
  }}
202
 
@@ -218,7 +282,6 @@ html_code = f"""
218
  }}
219
 
220
  let scene, camera, renderer, controls;
221
- let city;
222
 
223
  function init() {{
224
  const container = document.getElementById('container');
@@ -238,6 +301,8 @@ html_code = f"""
238
  // Renderer
239
  renderer = new THREE.WebGLRenderer({{ antialias: true }});
240
  renderer.setSize({container_width}, {container_height});
 
 
241
  container.appendChild(renderer.domElement);
242
 
243
  // Lights
@@ -245,14 +310,41 @@ html_code = f"""
245
  scene.add(ambientLight);
246
  const sun = new THREE.DirectionalLight(0xffffff, 0.8);
247
  sun.position.set(50, 50, 50);
 
 
 
 
 
248
  scene.add(sun);
249
 
250
- // Ground with 3:4 ratio (90x120)
251
- const groundGeo = new THREE.PlaneGeometry(90, 120, 32, 32);
252
- const groundMat = new THREE.MeshPhongMaterial({{ color: 0x4a7043 }});
 
 
 
 
253
  const ground = new THREE.Mesh(groundGeo, groundMat);
254
  ground.rotation.x = -Math.PI / 2;
255
  ground.position.y = -0.1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  scene.add(ground);
257
 
258
  // Lakes
@@ -263,6 +355,7 @@ html_code = f"""
263
  const lake = new THREE.Mesh(lakeGeo, lakeMat);
264
  lake.rotation.x = -Math.PI / 2;
265
  lake.position.set(center.x, 0.01, center.y);
 
266
  scene.add(lake);
267
  }});
268
 
@@ -271,15 +364,31 @@ html_code = f"""
271
  const bridgeMat = new THREE.MeshPhongMaterial({{ color: 0x808080 }});
272
  const bridge = new THREE.Mesh(bridgeGeo, bridgeMat);
273
  bridge.position.set(15, 0.2, 20);
 
 
274
  scene.add(bridge);
275
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  // Controls
277
  controls = new THREE.OrbitControls(camera, renderer.domElement);
278
  controls.enableDamping = true;
279
  controls.target.set(0, 0, 0);
280
 
281
  // City
282
- city = new CitySimulator();
283
  city.addBlock(scene, 0, 0);
284
 
285
  // Events
@@ -323,7 +432,7 @@ st.sidebar.title("3D City Evolution Simulator")
323
  st.sidebar.write("""
324
  ## How to Play
325
 
326
- Watch a 3D city evolve with lakes, hills, and building blocks.
327
 
328
  ### Controls:
329
  - **Evolve City**: Grow the city
@@ -335,9 +444,9 @@ Watch a 3D city evolve with lakes, hills, and building blocks.
335
 
336
  ### Features:
337
  - 3:4 initial play area (768x1024)
338
- - Blocks (10x10 units) with up to 5 buildings
339
- - Buildings start wide, grow taller with smaller floors
340
- - Terrain with hills and lakes
341
- - Waterfront properties grow larger
342
- - Bridges connect land masses
343
  """)
 
4
  st.set_page_config(page_title="3D City Evolution Simulator", layout="wide")
5
 
6
  st.title("3D City Evolution Simulator")
7
+ st.write("Watch a 3D city grow with roads, vegetation, and dynamic weather")
8
 
9
  # Sliders for container size with initial 3:4 aspect ratio
10
+ max_width = min(1200, st.session_state.get('window_width', 1200))
11
+ max_height = min(1600, st.session_state.get('window_height', 1600))
12
 
13
  col1, col2 = st.columns(2)
14
  with col1:
 
102
  let position = basePos.clone();
103
  let direction = new THREE.Vector3(0, 1, 0);
104
  const structure = new THREE.Group();
105
+ let baseWidth = 1.5;
106
+
107
+ // Add small attached buildings horizontally
108
+ const attachCount = Math.floor(Math.random() * 3); // 0-2 attachments
109
+ for (let i = 0; i < attachCount; i++) {{
110
+ const attachWidth = baseWidth * 0.6;
111
+ const attachHeight = 1 + Math.random() * 2;
112
+ const geo = new THREE.BoxGeometry(attachWidth, attachHeight, attachWidth);
113
+ const mat = new THREE.MeshPhongMaterial({{
114
+ color: new THREE.Color(0.5 + Math.random() * 0.5,
115
+ 0.5 + Math.random() * 0.5,
116
+ 0.5 + Math.random() * 0.5)
117
+ }});
118
+ const attach = new THREE.Mesh(geo, mat);
119
+ const offsetX = (i + 1) * (baseWidth + attachWidth) * (Math.random() > 0.5 ? 1 : -1);
120
+ attach.position.set(position.x + offsetX, attachHeight / 2, position.z);
121
+ attach.castShadow = true;
122
+ structure.add(attach);
123
+ }}
124
 
125
  for (let char of this.generate()) {{
126
  switch(char) {{
127
  case 'F':
128
  if (height < maxHeight) {{
129
+ const width = baseWidth * (1 - height / maxHeight);
130
+ const floorHeight = 2 + Math.random() * 2;
131
  const geo = new THREE.BoxGeometry(width, floorHeight, width);
132
  const mat = new THREE.MeshPhongMaterial({{
133
  color: new THREE.Color(0.5 + Math.random() * 0.5,
 
136
  }});
137
  const floor = new THREE.Mesh(geo, mat);
138
  floor.position.copy(position).add(new THREE.Vector3(0, floorHeight/2, 0));
139
+ floor.castShadow = true;
140
  structure.add(floor);
141
  position.y += floorHeight;
142
  height += floorHeight;
 
163
  class CitySimulator {{
164
  constructor() {{
165
  this.blocks = [];
166
+ this.roads = [];
167
  this.blockSize = 10;
168
  this.maxBuildingsPerBlock = 5;
169
  this.generation = 0;
 
209
  }}
210
  }}
211
 
212
+ addRoad(scene, start, end) {{
213
+ const distance = start.distanceTo(end);
214
+ const roadGeo = new THREE.PlaneGeometry(2, distance);
215
+ const roadMat = new THREE.MeshPhongMaterial({{ color: 0x555555 }});
216
+ const road = new THREE.Mesh(roadGeo, roadMat);
217
+ road.rotation.x = -Math.PI / 2;
218
+ const midPoint = start.clone().add(end).multiplyScalar(0.5);
219
+ road.position.set(midPoint.x, 0.02, midPoint.y);
220
+ road.lookAt(new THREE.Vector3(end.x, 0, end.y));
221
+ road.receiveShadow = true;
222
+ scene.add(road);
223
+ this.roads.push(road);
224
+ }}
225
+
226
+ addVegetation(scene) {{
227
+ const treeGeo = new THREE.ConeGeometry(1, 3, 8);
228
+ const treeMat = new THREE.MeshPhongMaterial({{ color: 0x228B22 }});
229
+ const shrubGeo = new THREE.SphereGeometry(0.5, 8, 8);
230
+ const shrubMat = new THREE.MeshPhongMaterial({{ color: 0x32CD32 }});
231
+
232
+ for (let i = 0; i < 10; i++) {{
233
+ const x = (Math.random() - 0.5) * 90;
234
+ const z = (Math.random() - 0.5) * 120;
235
+ if (!this.isInLake(x, z)) {{
236
+ const tree = new THREE.Mesh(treeGeo, treeMat);
237
+ tree.position.set(x, this.getTerrainHeight(x, z) + 1.5, z);
238
+ tree.castShadow = true;
239
+ scene.add(tree);
240
+
241
+ const shrub = new THREE.Mesh(shrubGeo, shrubMat);
242
+ shrub.position.set(x + 1, this.getTerrainHeight(x, z) + 0.5, z + 1);
243
+ shrub.castShadow = true;
244
+ scene.add(shrub);
245
+ }}
246
+ }}
247
+ }}
248
+
249
  evolve(scene) {{
250
  this.generation++;
251
  if (this.blocks.length < 20) {{
252
+ const x = (Math.random() - 0.5) * 90;
253
  const z = (Math.random() - 0.5) * 120;
254
+ if (!this.isInLake(x, z)) {{
255
+ this.addBlock(scene, x, z);
256
+ if (this.blocks.length > 1) {{
257
+ const lastBlock = this.blocks[this.blocks.length - 2];
258
+ this.addRoad(scene, lastBlock.position, this.blocks[this.blocks.length - 1].position);
259
+ }}
260
+ }}
261
  }}
262
  this.blocks.forEach(block => this.evolveBlock(scene, block));
263
+ this.addVegetation(scene);
264
  this.updateStats();
265
  }}
266
 
 
282
  }}
283
 
284
  let scene, camera, renderer, controls;
 
285
 
286
  function init() {{
287
  const container = document.getElementById('container');
 
301
  // Renderer
302
  renderer = new THREE.WebGLRenderer({{ antialias: true }});
303
  renderer.setSize({container_width}, {container_height});
304
+ renderer.shadowMap.enabled = true;
305
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
306
  container.appendChild(renderer.domElement);
307
 
308
  // Lights
 
310
  scene.add(ambientLight);
311
  const sun = new THREE.DirectionalLight(0xffffff, 0.8);
312
  sun.position.set(50, 50, 50);
313
+ sun.castShadow = true;
314
+ sun.shadow.mapSize.width = 1024;
315
+ sun.shadow.mapSize.height = 1024;
316
+ sun.shadow.camera.near = 0.5;
317
+ sun.shadow.camera.far = 500;
318
  scene.add(sun);
319
 
320
+ // Ground with bump mapping
321
+ const groundGeo = new THREE.PlaneGeometry(1000, 1000, 32, 32); // Extended to horizon
322
+ const groundMat = new THREE.MeshPhongMaterial({{
323
+ color: 0x4a7043,
324
+ bumpScale: 0.5,
325
+ shininess: 10
326
+ }});
327
  const ground = new THREE.Mesh(groundGeo, groundMat);
328
  ground.rotation.x = -Math.PI / 2;
329
  ground.position.y = -0.1;
330
+ ground.receiveShadow = true;
331
+
332
+ // Simple bump map (noise)
333
+ const canvas = document.createElement('canvas');
334
+ canvas.width = 256;
335
+ canvas.height = 256;
336
+ const ctx = canvas.getContext('2d');
337
+ for (let x = 0; x < 256; x++) {{
338
+ for (let y = 0; y < 256; y++) {{
339
+ const value = Math.random() * 255;
340
+ ctx.fillStyle = `rgb(${value},${value},${value})`;
341
+ ctx.fillRect(x, y, 1, 1);
342
+ }}
343
+ }}
344
+ const bumpTexture = new THREE.Texture(canvas);
345
+ bumpTexture.needsUpdate = true;
346
+ groundMat.bumpMap = bumpTexture;
347
+
348
  scene.add(ground);
349
 
350
  // Lakes
 
355
  const lake = new THREE.Mesh(lakeGeo, lakeMat);
356
  lake.rotation.x = -Math.PI / 2;
357
  lake.position.set(center.x, 0.01, center.y);
358
+ lake.receiveShadow = true;
359
  scene.add(lake);
360
  }});
361
 
 
364
  const bridgeMat = new THREE.MeshPhongMaterial({{ color: 0x808080 }});
365
  const bridge = new THREE.Mesh(bridgeGeo, bridgeMat);
366
  bridge.position.set(15, 0.2, 20);
367
+ bridge.castShadow = true;
368
+ bridge.receiveShadow = true;
369
  scene.add(bridge);
370
 
371
+ // Clouds
372
+ const cloudGeo = new THREE.SphereGeometry(5, 8, 8);
373
+ const cloudMat = new THREE.MeshPhongMaterial({{ color: 0xFFFFFF, opacity: 0.8, transparent: true }});
374
+ for (let i = 0; i < 5; i++) {{
375
+ const cloud = new THREE.Mesh(cloudGeo, cloudMat);
376
+ cloud.position.set(
377
+ (Math.random() - 0.5) * 200,
378
+ 50 + Math.random() * 20,
379
+ (Math.random() - 0.5) * 200
380
+ );
381
+ cloud.castShadow = true;
382
+ scene.add(cloud);
383
+ }}
384
+
385
  // Controls
386
  controls = new THREE.OrbitControls(camera, renderer.domElement);
387
  controls.enableDamping = true;
388
  controls.target.set(0, 0, 0);
389
 
390
  // City
391
+ const city = new CitySimulator();
392
  city.addBlock(scene, 0, 0);
393
 
394
  // Events
 
432
  st.sidebar.write("""
433
  ## How to Play
434
 
435
+ Watch a 3D city evolve with roads, vegetation, and dynamic weather.
436
 
437
  ### Controls:
438
  - **Evolve City**: Grow the city
 
444
 
445
  ### Features:
446
  - 3:4 initial play area (768x1024)
447
+ - Roads connect blocks
448
+ - Trees and shrubs added each evolution
449
+ - Extended green ground with bump mapping
450
+ - Clouds and sunlight with shadows
451
+ - Buildings with horizontal attachments
452
  """)