zeroed-some/dougk / f9ef9de

Browse files

expand the scene a bit

Authored by espadonne
SHA
f9ef9de27bb6417dd48a6408d2da8e8883dc91e6
Parents
adccf1a
Tree
78019ea

1 changed file

StatusFile+-
M src/renderers/three/pond.js 249 0
src/renderers/three/pond.jsmodified
@@ -153,6 +153,223 @@ export function createPond(scene, gradientMap) {
153153
 
154154
   group.add(fenceGroup)
155155
 
156
+  // ============================================
157
+  // DISTANT SCENERY - Mountains and Village
158
+  // ============================================
159
+
160
+  const sceneDistance = 12 // How far away the scenery is
161
+
162
+  // Mountain range materials
163
+  const mountainMaterial = new THREE.MeshToonMaterial({
164
+    color: 0x6b8e7a, // Muted green-grey
165
+    gradientMap: gradientMap
166
+  })
167
+  const mountainSnowMaterial = new THREE.MeshToonMaterial({
168
+    color: 0xe8e8f0, // Snow white with slight blue
169
+    gradientMap: gradientMap
170
+  })
171
+  const mountainDarkMaterial = new THREE.MeshToonMaterial({
172
+    color: 0x4a6b5a, // Darker mountain
173
+    gradientMap: gradientMap
174
+  })
175
+
176
+  // Create mountain range (back-left)
177
+  const mountains = new THREE.Group()
178
+
179
+  // Large back mountain
180
+  const bigMountainGeom = new THREE.ConeGeometry(3, 5, 6)
181
+  const bigMountain = new THREE.Mesh(bigMountainGeom, mountainMaterial)
182
+  bigMountain.position.set(-sceneDistance, 2, -sceneDistance * 0.8)
183
+  bigMountain.rotation.y = 0.3
184
+  mountains.add(bigMountain)
185
+
186
+  // Snow cap for big mountain
187
+  const snowCapGeom = new THREE.ConeGeometry(1.2, 1.5, 6)
188
+  const snowCap = new THREE.Mesh(snowCapGeom, mountainSnowMaterial)
189
+  snowCap.position.set(-sceneDistance, 4.2, -sceneDistance * 0.8)
190
+  snowCap.rotation.y = 0.3
191
+  mountains.add(snowCap)
192
+
193
+  // Medium mountain
194
+  const medMountainGeom = new THREE.ConeGeometry(2.2, 3.5, 5)
195
+  const medMountain = new THREE.Mesh(medMountainGeom, mountainDarkMaterial)
196
+  medMountain.position.set(-sceneDistance * 0.7, 1.5, -sceneDistance)
197
+  medMountain.rotation.y = -0.2
198
+  mountains.add(medMountain)
199
+
200
+  // Small mountain
201
+  const smallMountainGeom = new THREE.ConeGeometry(1.8, 2.8, 5)
202
+  const smallMountain = new THREE.Mesh(smallMountainGeom, mountainMaterial)
203
+  smallMountain.position.set(-sceneDistance * 1.1, 1.2, -sceneDistance * 0.5)
204
+  mountains.add(smallMountain)
205
+
206
+  // Another range on the right side (further back)
207
+  const farMountainGeom = new THREE.ConeGeometry(2.5, 4, 5)
208
+  const farMountain = new THREE.Mesh(farMountainGeom, mountainDarkMaterial)
209
+  farMountain.position.set(sceneDistance * 0.5, 1.8, -sceneDistance * 1.2)
210
+  mountains.add(farMountain)
211
+
212
+  const farSnowGeom = new THREE.ConeGeometry(0.9, 1.2, 5)
213
+  const farSnow = new THREE.Mesh(farSnowGeom, mountainSnowMaterial)
214
+  farSnow.position.set(sceneDistance * 0.5, 3.6, -sceneDistance * 1.2)
215
+  mountains.add(farSnow)
216
+
217
+  group.add(mountains)
218
+
219
+  // ============================================
220
+  // VILLAGE
221
+  // ============================================
222
+
223
+  const village = new THREE.Group()
224
+  const villageX = sceneDistance * 0.8
225
+  const villageZ = -sceneDistance * 0.4
226
+
227
+  // House materials
228
+  const houseMaterial = new THREE.MeshToonMaterial({
229
+    color: 0xd4a574, // Warm beige/tan
230
+    gradientMap: gradientMap
231
+  })
232
+  const roofMaterial = new THREE.MeshToonMaterial({
233
+    color: 0x8b4513, // Brown roof
234
+    gradientMap: gradientMap
235
+  })
236
+  const roofRedMaterial = new THREE.MeshToonMaterial({
237
+    color: 0xb85450, // Red roof
238
+    gradientMap: gradientMap
239
+  })
240
+  const windowMaterial = new THREE.MeshToonMaterial({
241
+    color: 0x87ceeb, // Light blue windows
242
+    gradientMap: gradientMap
243
+  })
244
+
245
+  // Helper to create a simple house
246
+  function createHouse(x, z, scale, roofMat) {
247
+    const houseGroup = new THREE.Group()
248
+
249
+    // House body
250
+    const bodyGeom = new THREE.BoxGeometry(0.8, 0.6, 0.6)
251
+    const body = new THREE.Mesh(bodyGeom, houseMaterial)
252
+    body.position.y = 0.3
253
+    houseGroup.add(body)
254
+
255
+    // Roof
256
+    const roofGeom = new THREE.ConeGeometry(0.55, 0.5, 4)
257
+    const roof = new THREE.Mesh(roofGeom, roofMat)
258
+    roof.position.y = 0.75
259
+    roof.rotation.y = Math.PI / 4
260
+    houseGroup.add(roof)
261
+
262
+    // Window
263
+    const windowGeom = new THREE.PlaneGeometry(0.15, 0.15)
264
+    const windowMesh = new THREE.Mesh(windowGeom, windowMaterial)
265
+    windowMesh.position.set(0.401, 0.35, 0)
266
+    houseGroup.add(windowMesh)
267
+
268
+    houseGroup.position.set(x, 0, z)
269
+    houseGroup.scale.setScalar(scale)
270
+    houseGroup.rotation.y = Math.random() * 0.5 - 0.25
271
+
272
+    return houseGroup
273
+  }
274
+
275
+  // Create village houses
276
+  const house1 = createHouse(villageX, villageZ, 1.2, roofMaterial)
277
+  village.add(house1)
278
+
279
+  const house2 = createHouse(villageX + 1.5, villageZ + 0.8, 0.9, roofRedMaterial)
280
+  village.add(house2)
281
+
282
+  const house3 = createHouse(villageX + 0.5, villageZ + 1.5, 1.0, roofMaterial)
283
+  village.add(house3)
284
+
285
+  const house4 = createHouse(villageX - 0.8, villageZ + 0.6, 0.8, roofRedMaterial)
286
+  village.add(house4)
287
+
288
+  // Chimney on main house
289
+  const chimneyGeom = new THREE.BoxGeometry(0.15, 0.4, 0.15)
290
+  const chimney = new THREE.Mesh(chimneyGeom, new THREE.MeshToonMaterial({
291
+    color: 0x8b7355,
292
+    gradientMap: gradientMap
293
+  }))
294
+  chimney.position.set(villageX + 0.2, 1.1, villageZ + 0.1)
295
+  village.add(chimney)
296
+
297
+  // Smoke particles
298
+  const smokeParticles = []
299
+  const smokeMaterial = new THREE.MeshBasicMaterial({
300
+    color: 0xcccccc,
301
+    transparent: true,
302
+    opacity: 0.6
303
+  })
304
+
305
+  function createSmokeParticle() {
306
+    const size = 0.1 + Math.random() * 0.1
307
+    const smokeGeom = new THREE.SphereGeometry(size, 6, 4)
308
+    const smoke = new THREE.Mesh(smokeGeom, smokeMaterial.clone())
309
+    smoke.position.set(
310
+      villageX + 0.2 + (Math.random() - 0.5) * 0.1,
311
+      1.3,
312
+      villageZ + 0.1 + (Math.random() - 0.5) * 0.1
313
+    )
314
+    village.add(smoke)
315
+    smokeParticles.push({
316
+      mesh: smoke,
317
+      age: 0,
318
+      maxAge: 3 + Math.random() * 2,
319
+      driftX: (Math.random() - 0.5) * 0.3,
320
+      driftZ: (Math.random() - 0.5) * 0.3,
321
+      riseSpeed: 0.3 + Math.random() * 0.2
322
+    })
323
+  }
324
+
325
+  // Initial smoke
326
+  for (let i = 0; i < 5; i++) {
327
+    createSmokeParticle()
328
+    smokeParticles[i].age = Math.random() * 2 // Stagger initial ages
329
+  }
330
+
331
+  group.add(village)
332
+
333
+  // Small trees near village
334
+  const treeMaterial = new THREE.MeshToonMaterial({
335
+    color: 0x2d5a3d,
336
+    gradientMap: gradientMap
337
+  })
338
+  const trunkMaterial = new THREE.MeshToonMaterial({
339
+    color: 0x5c4033,
340
+    gradientMap: gradientMap
341
+  })
342
+
343
+  for (let i = 0; i < 6; i++) {
344
+    const treeGroup = new THREE.Group()
345
+
346
+    // Trunk
347
+    const trunkGeom = new THREE.CylinderGeometry(0.08, 0.12, 0.5, 6)
348
+    const trunk = new THREE.Mesh(trunkGeom, trunkMaterial)
349
+    trunk.position.y = 0.25
350
+    treeGroup.add(trunk)
351
+
352
+    // Foliage (stacked cones)
353
+    const foliage1 = new THREE.Mesh(new THREE.ConeGeometry(0.4, 0.6, 6), treeMaterial)
354
+    foliage1.position.y = 0.7
355
+    treeGroup.add(foliage1)
356
+
357
+    const foliage2 = new THREE.Mesh(new THREE.ConeGeometry(0.3, 0.5, 6), treeMaterial)
358
+    foliage2.position.y = 1.1
359
+    treeGroup.add(foliage2)
360
+
361
+    const angle = (i / 6) * Math.PI * 0.8 - 0.4
362
+    const dist = sceneDistance * 0.6 + Math.random() * 2
363
+    treeGroup.position.set(
364
+      Math.cos(angle) * dist + villageX * 0.3,
365
+      0,
366
+      Math.sin(angle) * dist + villageZ * 0.3
367
+    )
368
+    treeGroup.scale.setScalar(0.6 + Math.random() * 0.4)
369
+
370
+    group.add(treeGroup)
371
+  }
372
+
156373
   // Ripple system
157374
   const ripples = []
158375
   const rippleGeom = new THREE.RingGeometry(0.1, 0.15, 16)
@@ -176,6 +393,8 @@ export function createPond(scene, gradientMap) {
176393
     })
177394
   }
178395
 
396
+  let smokeSpawnTimer = 0
397
+
179398
   function update(delta, elapsed) {
180399
     // Animate water highlight
181400
     highlight.position.x = -radius * 0.35 + Math.sin(elapsed * 0.5) * 0.2
@@ -197,6 +416,36 @@ export function createPond(scene, gradientMap) {
197416
         ripples.splice(i, 1)
198417
       }
199418
     }
419
+
420
+    // Spawn new smoke particles
421
+    smokeSpawnTimer += delta
422
+    if (smokeSpawnTimer > 0.8) {
423
+      smokeSpawnTimer = 0
424
+      createSmokeParticle()
425
+    }
426
+
427
+    // Update smoke particles
428
+    for (let i = smokeParticles.length - 1; i >= 0; i--) {
429
+      const smoke = smokeParticles[i]
430
+      smoke.age += delta
431
+
432
+      // Rise and drift
433
+      smoke.mesh.position.y += smoke.riseSpeed * delta
434
+      smoke.mesh.position.x += smoke.driftX * delta
435
+      smoke.mesh.position.z += smoke.driftZ * delta
436
+
437
+      // Grow and fade
438
+      const progress = smoke.age / smoke.maxAge
439
+      smoke.mesh.scale.setScalar(1 + progress * 2)
440
+      smoke.mesh.material.opacity = 0.6 * (1 - progress)
441
+
442
+      if (smoke.age >= smoke.maxAge) {
443
+        village.remove(smoke.mesh)
444
+        smoke.mesh.geometry.dispose()
445
+        smoke.mesh.material.dispose()
446
+        smokeParticles.splice(i, 1)
447
+      }
448
+    }
200449
   }
201450
 
202451
   scene.add(group)