ReallyFloppyPenguin commited on
Commit
efb7f30
·
verified ·
1 Parent(s): 5ff1975

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +0 -904
index.html CHANGED
@@ -1,904 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
6
- <title>DRIVE // SIM - Physics Sandbox</title>
7
- <link rel="preconnect" href="https://fonts.googleapis.com">
8
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
10
- <script type="importmap">
11
- {
12
- "imports": {
13
- "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
14
- "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
15
- }
16
- }
17
- </script>
18
- <script type="module">
19
- import * as THREE from 'three';
20
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
21
- import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
22
- import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
23
- import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
24
- import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js';
25
- import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
26
- import { FXAAShader } from 'three/addons/shaders/FXAAShader.js';
27
-
28
- let scene, camera, renderer, composer, bloomPass;
29
- let terrain, water, sky, groundMaterial, carBody, carMesh, carGroup, tireTrackGeometry, tireTrackMesh;
30
- let wheelMeshes = [], wheels = [];
31
- let clock = new THREE.Clock();
32
- let keys = {};
33
- let speed = 0, steeringAngle = 0;
34
- let physics = { velocity: new THREE.Vector3(), angularVelocity: 0, mass: 1800 };
35
- let engineOn = true;
36
- let cameraMode = 0;
37
- let timeOfDay = 0.4;
38
- let dayNightCycle = true;
39
- let dustParticles = [];
40
- let terrainCanvas, terrainCtx;
41
- let globalTime = 0;
42
- let autoDriveEnabled = false;
43
- let perfStats = { fps: 0, frameCount: 0, lastTime: 0 };
44
- let uiVisible = true;
45
-
46
- const WHEEL_FRICTION = 0.95;
47
- const STEER_SPEED = 3.5;
48
- const MAX_STEER = 0.65;
49
- const ACCEL = 45;
50
- const BRAKE_FORCE = 80;
51
- const MAX_SPEED = 85;
52
- const DRAG = 0.985;
53
- const SUSPENSION_REST = 0.45;
54
- const SUSPENSION_K = 22;
55
- const SUSPENSION_DAMPING = 2.8;
56
- const GRAVITY = 12;
57
-
58
- const SKY_COLORS = {
59
- dawn: new THREE.Color(0xFFF3E0),
60
- noon: new THREE.Color(0x87CEEB),
61
- dusk: new THREE.Color(0x4A148C),
62
- night: new THREE.Color(0x0A0A1A),
63
- };
64
-
65
- init();
66
- animate();
67
-
68
- function init() {
69
- const container = document.createElement('div');
70
- container.style.position = 'fixed';
71
- container.style.top = '0';
72
- container.style.left = '0';
73
- container.style.width = '100%';
74
- container.style.height = '100%';
75
- container.style.zIndex = '1';
76
- document.body.appendChild(container);
77
-
78
- renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: 'high-performance' });
79
- renderer.setSize(window.innerWidth, window.innerHeight);
80
- renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
81
- renderer.shadowMap.enabled = true;
82
- renderer.shadowMap.type = THREE.PCFSoftShadowMap;
83
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
84
- renderer.toneMappingExposure = 1.0;
85
- renderer.outputColorSpace = THREE.SRGBColorSpace;
86
- container.appendChild(renderer.domElement);
87
-
88
- scene = new THREE.Scene();
89
- scene.fog = new THREE.FogExp2(SKY_COLORS.noon, 0.004);
90
-
91
- camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 1500);
92
-
93
- buildSky();
94
- buildLights();
95
- buildTerrain();
96
- buildWater();
97
- buildCityscape();
98
- buildRoad();
99
- buildVehicles();
100
- buildDust();
101
- buildTireTrackSystem();
102
- buildPostProcessing();
103
-
104
- window.addEventListener('resize', onWindowResize);
105
- document.addEventListener('keydown', e => {
106
- keys[e.key.toLowerCase()] = true;
107
- if (e.key === '1') cameraMode = 0;
108
- if (e.key === '2') cameraMode = 1;
109
- if (e.key === '3') cameraMode = 2;
110
- if (e.key === '4') cameraMode = 3;
111
- if (e.key === 'l') dayNightCycle = !dayNightCycle;
112
- if (e.key === 'r') resetCar();
113
- if (e.key === 't') toggleEngine();
114
- if (e.key === 'h') toggleUI();
115
- if (e.key === 'a') toggleAutoDrive();
116
- if (e.key.toLowerCase() === 'p') togglePause();
117
- });
118
- document.addEventListener('keyup', e => keys[e.key.toLowerCase()] = false);
119
-
120
- setupTouchControls();
121
- buildUI();
122
- buildIntroOverlay();
123
- }
124
-
125
- function buildSky() {
126
- sky = new THREE.Group();
127
-
128
- const vertexShader = `
129
- varying vec3 vWorldPosition;
130
- void main() {
131
- vec4 worldPosition = modelMatrix * vec4(position, 1.0);
132
- vWorldPosition = worldPosition.xyz;
133
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
134
- }
135
- `;
136
-
137
- const fragmentShader = `
138
- uniform vec3 topColor;
139
- uniform vec3 bottomColor;
140
- uniform float offset;
141
- uniform float exponent;
142
- varying vec3 vWorldPosition;
143
- void main() {
144
- float h = normalize(vWorldPosition + offset).y;
145
- gl_FragColor = vec4(mix(bottomColor, topColor, max(pow(max(h, 0.0), exponent), 0.0)), 1.0);
146
- }
147
- `;
148
-
149
- const uniforms = {
150
- topColor: { value: new THREE.Color(0x0077ff) },
151
- bottomColor: { value: new THREE.Color(0xffffff) },
152
- offset: { value: 33 },
153
- exponent: { value: 0.6 }
154
- };
155
-
156
- const skyGeo = new THREE.SphereGeometry(800, 32, 15);
157
- const skyMat = new THREE.ShaderMaterial({
158
- vertexShader,
159
- fragmentShader,
160
- uniforms,
161
- side: THREE.BackSide
162
- });
163
-
164
- const skyMesh = new THREE.Mesh(skyGeo, skyMat);
165
- sky.add(skyMesh);
166
-
167
- const sunGeo = new THREE.SphereGeometry(25, 32, 32);
168
- const sunMat = new THREE.MeshBasicMaterial({ color: 0xFFE4B5 });
169
- const sun = new THREE.Mesh(sunGeo, sunMat);
170
- sun.position.set(200, 300, -400);
171
- sun.name = 'sun';
172
- sky.add(sun);
173
-
174
- const sunGlowGeo = new THREE.SphereGeometry(45, 32, 32);
175
- const sunGlowMat = new THREE.MeshBasicMaterial({
176
- color: 0xFFD700,
177
- transparent: true,
178
- opacity: 0.15
179
- });
180
- const sunGlow = new THREE.Mesh(sunGlowGeo, sunGlowMat);
181
- sun.add(sunGlow);
182
-
183
- const moonGeo = new THREE.SphereGeometry(18, 32, 32);
184
- const moonMat = new THREE.MeshBasicMaterial({ color: 0xDDDDDD });
185
- const moon = new THREE.Mesh(moonGeo, moonMat);
186
- moon.position.set(-200, 280, 400);
187
- moon.name = 'moon';
188
- sky.add(moon);
189
-
190
- const moonGlowGeo = new THREE.SphereGeometry(35, 32, 32);
191
- const moonGlowMat = new THREE.MeshBasicMaterial({
192
- color: 0xB0C4DE,
193
- transparent: true,
194
- opacity: 0.1
195
- });
196
- const moonGlow = new THREE.Mesh(moonGlowGeo, moonGlowMat);
197
- moon.add(moonGlow);
198
-
199
- scene.add(sky);
200
-
201
- for (let i = 0; i < 60; i++) {
202
- const cloud = buildCloud();
203
- cloud.position.set(
204
- (Math.random() - 0.5) * 600,
205
- 40 + Math.random() * 50,
206
- (Math.random() - 0.5) * 600
207
- );
208
- cloud.scale.setScalar(0.8 + Math.random() * 1.5);
209
- sky.add(cloud);
210
- }
211
-
212
- const starGeo = new THREE.BufferGeometry();
213
- const starCount = 1500;
214
- const starPos = new Float32Array(starCount * 3);
215
- const starSizes = new Float32Array(starCount);
216
- for (let i = 0; i < starCount; i++) {
217
- const r = 750;
218
- const theta = Math.random() * Math.PI * 2;
219
- const phi = Math.acos(2 * Math.random() - 1);
220
- starPos[i * 3] = r * Math.sin(phi) * Math.cos(theta);
221
- starPos[i * 3 + 1] = Math.abs(r * Math.cos(phi));
222
- starPos[i * 3 + 2] = r * Math.sin(phi) * Math.sin(theta);
223
- starSizes[i] = 0.5 + Math.random() * 1.5;
224
- }
225
- starGeo.setAttribute('position', new THREE.BufferAttribute(starPos, 3));
226
- starGeo.setAttribute('size', new THREE.BufferAttribute(starSizes, 1));
227
-
228
- const starMat = new THREE.PointsMaterial({
229
- color: 0xffffff,
230
- size: 1.5,
231
- transparent: true,
232
- opacity: 0.0,
233
- sizeAttenuation: true
234
- });
235
- starMat.name = 'starOpacity';
236
- const stars = new THREE.Points(starGeo, starMat);
237
- stars.name = 'stars';
238
- sky.add(stars);
239
- }
240
-
241
- function buildCloud() {
242
- const cloud = new THREE.Group();
243
- const geo = new THREE.SphereGeometry(1, 12, 8);
244
- const mat = new THREE.MeshStandardMaterial({
245
- color: 0xffffff,
246
- roughness: 1,
247
- flatShading: true,
248
- transparent: true,
249
- opacity: 0.75
250
- });
251
-
252
- const puffs = 5 + Math.floor(Math.random() * 4);
253
- for (let i = 0; i < puffs; i++) {
254
- const m = new THREE.Mesh(geo, mat);
255
- m.position.set(
256
- (Math.random() - 0.5) * 8,
257
- (Math.random() - 0.5) * 1.5,
258
- (Math.random() - 0.5) * 5
259
- );
260
- m.scale.setScalar(2 + Math.random() * 4);
261
- cloud.add(m);
262
- }
263
- cloud.name = 'cloud';
264
- return cloud;
265
- }
266
-
267
- function buildLights() {
268
- scene.add(new THREE.AmbientLight(0x444466, 0.6));
269
-
270
- const sunLight = new THREE.DirectionalLight(0xffffff, 1.2);
271
- sunLight.position.set(200, 300, -400);
272
- sunLight.castShadow = true;
273
- sunLight.shadow.mapSize.width = 4096;
274
- sunLight.shadow.mapSize.height = 4096;
275
- sunLight.shadow.camera.near = 10;
276
- sunLight.shadow.camera.far = 800;
277
- sunLight.shadow.camera.left = -200;
278
- sunLight.shadow.camera.right = 200;
279
- sunLight.shadow.camera.top = 200;
280
- sunLight.shadow.camera.bottom = -200;
281
- sunLight.shadow.bias = -0.0005;
282
- sunLight.shadow.normalBias = 0.02;
283
- sunLight.name = 'sunLight';
284
- scene.add(sunLight);
285
-
286
- const fillLight = new THREE.DirectionalLight(0x8899ff, 0.3);
287
- fillLight.position.set(-100, 100, 100);
288
- fillLight.name = 'fillLight';
289
- scene.add(fillLight);
290
-
291
- const hemiLight = new THREE.HemisphereLight(0x87CEEB, 0x555555, 0.4);
292
- hemiLight.name = 'hemiLight';
293
- scene.add(hemiLight);
294
- }
295
-
296
- function buildTerrain() {
297
- const size = 600;
298
- const segs = 200;
299
-
300
- terrainCanvas = document.createElement('canvas');
301
- terrainCanvas.width = segs + 1;
302
- terrainCanvas.height = segs + 1;
303
- terrainCtx = terrainCanvas.getContext('2d');
304
-
305
- const geo = new THREE.PlaneGeometry(size, size, segs, segs);
306
- geo.rotateX(-Math.PI / 2);
307
-
308
- const pos = geo.attributes.position;
309
- const colors = [];
310
- const vertex = new THREE.Vector3();
311
-
312
- for (let i = 0; i < pos.count; i++) {
313
- vertex.fromBufferAttribute(pos, i);
314
- let h = getTerrainHeight(vertex.x, vertex.z);
315
- pos.setY(i, h);
316
-
317
- let grass = new THREE.Color(0x3A7D44);
318
- let dirt = new THREE.Color(0x8B6F47);
319
- let sand = new THREE.Color(0xD4C4A8);
320
- let rock = new THREE.Color(0x666666);
321
-
322
- let blend = THREE.MathUtils.smoothstep(h, -5, 15);
323
- let col = sand.clone().lerp(grass, blend);
324
-
325
- let slope = 0;
326
- if (i > 0 && i < pos.count - 1) {
327
- let v1 = new THREE.Vector3(), v2 = new THREE.Vector3();
328
- v1.fromBufferAttribute(pos, i);
329
- v2.fromBufferAttribute(pos, (i + 1) % pos.count);
330
- slope = Math.abs(v2.y - v1.y);
331
- }
332
- col.lerp(rock, Math.min(slope * 3, 0.4));
333
-
334
- col.r += (Math.random() - 0.5) * 0.02;
335
- col.g += (Math.random() - 0.5) * 0.02;
336
- col.b += (Math.random() - 0.5) * 0.02;
337
- colors.push(col.r, col.g, col.b);
338
- }
339
- geo.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
340
- geo.computeVertexNormals();
341
-
342
- groundMaterial = new THREE.MeshStandardMaterial({
343
- vertexColors: true,
344
- roughness: 0.92,
345
- metalness: 0.0,
346
- side: THREE.DoubleSide
347
- });
348
-
349
- terrain = new THREE.Mesh(geo, groundMaterial);
350
- terrain.receiveShadow = true;
351
- terrain.name = 'terrain';
352
- scene.add(terrain);
353
-
354
- buildProps();
355
- }
356
-
357
- function buildProps() {
358
- const props = new THREE.Group();
359
-
360
- const treeColors = [
361
- 0x1B4332, 0x2D6A4F, 0x40916C, 0x52B788, 0x3A7D44, 0x2E7D32, 0x1B5E20, 0x33691E
362
- ];
363
-
364
- const trunkGeo = new THREE.CylinderGeometry(0.2, 0.4, 2, 7);
365
- const trunkMat = new THREE.MeshStandardMaterial({ color: 0x3E2723, roughness: 0.9 });
366
-
367
- for (let i = 0; i < 250; i++) {
368
- const x = (Math.random() - 0.5) * 500;
369
- const z = (Math.random() - 0.5) * 500;
370
-
371
- if (Math.abs(x) < 25 && Math.abs(z) < 30) continue;
372
- if (Math.abs(x - 70) < 35 && Math.abs(z + 60) < 35) continue;
373
-
374
- const h = getTerrainHeight(x, z);
375
- if (h < -2) continue;
376
-
377
- const treeGroup = new THREE.Group();
378
- treeGroup.position.set(x, h, z);
379
-
380
- const trunk = new THREE.Mesh(trunkGeo, trunkMat);
381
- trunk.position.y = 1;
382
- trunk.castShadow = true;
383
- treeGroup.add(trunk);
384
-
385
- const foliageCount = 2 + Math.floor(Math.random() * 3);
386
- for (let f = 0; f < foliageCount; f++) {
387
- const fGeo = new THREE.SphereGeometry(1.2 + Math.random() * 1.5, 8, 6);
388
- const fMat = new THREE.MeshStandardMaterial({
389
- color: treeColors[Math.floor(Math.random() * treeColors.length)],
390
- roughness: 0.85
391
- });
392
- const foliage = new THREE.Mesh(fGeo, fMat);
393
- foliage.position.set(
394
- (Math.random() - 0.5) * 1.5,
395
- 3.5 + Math.random() * 2.5,
396
- (Math.random() - 0.5) * 1.5
397
- );
398
- foliage.scale.y = 1.2;
399
- foliage.castShadow = true;
400
- treeGroup.add(foliage);
401
- }
402
-
403
- const scale = 0.7 + Math.random() * 0.8;
404
- treeGroup.scale.setScalar(scale);
405
- treeGroup.rotation.y = Math.random() * Math.PI * 2;
406
- props.add(treeGroup);
407
- }
408
-
409
- for (let i = 0; i < 80; i++) {
410
- const x = (Math.random() - 0.5) * 500;
411
- const z = (Math.random() - 0.5) * 500;
412
-
413
- if (Math.abs(x) < 25 && Math.abs(z) < 30) continue;
414
-
415
- const h = getTerrainHeight(x, z);
416
- if (h > 5) continue;
417
-
418
- const rockGeo = new THREE.DodecahedronGeometry(0.4 + Math.random() * 1.5, 0);
419
- const rockMat = new THREE.MeshStandardMaterial({
420
- color: 0x6B6B6B,
421
- roughness: 0.95,
422
- metalness: 0.1
423
- });
424
- const rock = new THREE.Mesh(rockGeo, rockMat);
425
- rock.position.set(x, h + 0.3, z);
426
- rock.rotation.set(Math.random(), Math.random(), Math.random());
427
- rock.scale.y = 0.6 + Math.random() * 0.5;
428
- rock.castShadow = true;
429
- rock.receiveShadow = true;
430
- props.add(rock);
431
- }
432
-
433
- const fenceMat = new THREE.MeshStandardMaterial({ color: 0x8D6E63, roughness: 0.9 });
434
- for (let i = -40; i <= 40; i += 4) {
435
- const post = new THREE.Mesh(
436
- new THREE.CylinderGeometry(0.06, 0.06, 1.2, 6),
437
- fenceMat
438
- );
439
- post.position.set(i, getTerrainHeight(i, -40) + 0.6, -40);
440
- post.castShadow = true;
441
- props.add(post);
442
- }
443
- const railGeo = new THREE.BoxGeometry(84, 0.06, 0.06);
444
- const rail = new THREE.Mesh(railGeo, fenceMat);
445
- rail.position.set(0, getTerrainHeight(0, -40) + 1.1, -40);
446
- props.add(rail);
447
-
448
- const bushColors = [0x2E7D32, 0x33691E, 0x1B5E20, 0x558B2F];
449
- for (let i = 0; i < 50; i++) {
450
- const x = (Math.random() - 0.5) * 500;
451
- const z = (Math.random() - 0.5) * 500;
452
- const h = getTerrainHeight(x, z);
453
- const bushGeo = new THREE.SphereGeometry(0.5 + Math.random() * 1, 8, 6);
454
- const bushMat = new THREE.MeshStandardMaterial({
455
- color: bushColors[Math.floor(Math.random() * bushColors.length)],
456
- roughness: 0.95
457
- });
458
- const bush = new THREE.Mesh(bushGeo, bushMat);
459
- bush.position.set(x, h + 0.4, z);
460
- bush.scale.y = 0.7;
461
- bush.castShadow = true;
462
- props.add(bush);
463
- }
464
-
465
- scene.add(props);
466
- }
467
-
468
- function buildWater() {
469
- const waterGeo = new THREE.PlaneGeometry(600, 600, 100, 100);
470
- waterGeo.rotateX(-Math.PI / 2);
471
-
472
- const waterMat = new THREE.MeshPhysicalMaterial({
473
- color: 0x1A5276,
474
- roughness: 0.15,
475
- metalness: 0.3,
476
- transparent: true,
477
- opacity: 0.6,
478
- transmission: 0.4,
479
- thickness: 2.0,
480
- clearcoat: 1.0,
481
- clearcoatRoughness: 0.1
482
- });
483
-
484
- water = new THREE.Mesh(waterGeo, waterMat);
485
- water.position.set(0, -6, 0);
486
- water.name = 'water';
487
- scene.add(water);
488
- }
489
-
490
- function buildCityscape() {
491
- const cityGroup = new THREE.Group();
492
- const colors = [0x546E7A, 0x607D8B, 0x78909C, 0x455A64, 0x37474F];
493
-
494
- for (let i = 0; i < 30; i++) {
495
- const w = 8 + Math.random() * 20;
496
- const d = 8 + Math.random() * 20;
497
- const h = 25 + Math.random() * 60;
498
- const x = (Math.random() > 0.5 ? 1 : -1) * (180 + Math.random() * 150);
499
- const z = (Math.random() - 0.5) * 400;
500
-
501
- const geo = new THREE.BoxGeometry(w, h, d);
502
- const mat = new THREE.MeshStandardMaterial({
503
- color: colors[Math.floor(Math.random() * colors.length)],
504
- roughness: 0.7,
505
- metalness: 0.2
506
- });
507
- const b = new THREE.Mesh(geo, mat);
508
- b.position.set(x, h / 2 - 5, z);
509
- b.castShadow = true;
510
- b.receiveShadow = true;
511
- cityGroup.add(b);
512
-
513
- if (Math.random() > 0.5) {
514
- const roofGeo = new THREE.BoxGeometry(w + 2, 2, d + 2);
515
- const roofMat = new THREE.MeshStandardMaterial({
516
- color: 0x263238,
517
- roughness: 0.8
518
- });
519
- const roof = new THREE.Mesh(roofGeo, roofMat);
520
- roof.position.set(x, h - 4, z);
521
- cityGroup.add(roof);
522
- }
523
- }
524
- scene.add(cityGroup);
525
- }
526
-
527
- function buildRoad() {
528
- const roadGroup = new THREE.Group();
529
-
530
- const roadMat = new THREE.MeshStandardMaterial({
531
- color: 0x333333,
532
- roughness: 0.85
533
- });
534
-
535
- const roadGeo = new THREE.PlaneGeometry(14, 140);
536
- roadGeo.rotateX(-Math.PI / 2);
537
- const road = new THREE.Mesh(roadGeo, roadMat);
538
- road.position.y = 0.05;
539
- road.receiveShadow = true;
540
- roadGroup.add(road);
541
-
542
- const shoulderMat = new THREE.MeshStandardMaterial({
543
- color: 0x555555,
544
- roughness: 0.9
545
- });
546
- const shoulderGeo = new THREE.PlaneGeometry(3, 140);
547
- shoulderGeo.rotateX(-Math.PI / 2);
548
- const leftShoulder = new THREE.Mesh(shoulderGeo, shoulderMat);
549
- leftShoulder.position.set(-8.5, 0.03, 0);
550
- leftShoulder.receiveShadow = true;
551
- roadGroup.add(leftShoulder);
552
-
553
- const rightShoulder = new THREE.Mesh(shoulderGeo, shoulderMat);
554
- rightShoulder.position.set(8.5, 0.03, 0);
555
- rightShoulder.receiveShadow = true;
556
- roadGroup.add(rightShoulder);
557
-
558
- const lineMat = new THREE.MeshBasicMaterial({ color: 0xFFD54F });
559
- const lineGeo = new THREE.PlaneGeometry(0.3, 6);
560
- lineGeo.rotateX(-Math.PI / 2);
561
- for (let z = -60; z < 60; z += 12) {
562
- const line = new THREE.Mesh(lineGeo, lineMat);
563
- line.position.set(0, 0.06, z);
564
- roadGroup.add(line);
565
- }
566
-
567
- const edgeLineGeo = new THREE.PlaneGeometry(0.2, 140);
568
- edgeLineGeo.rotateX(-Math.PI / 2);
569
- const edgeMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF });
570
-
571
- const leftEdge = new THREE.Mesh(edgeLineGeo, edgeMat);
572
- leftEdge.position.set(-7, 0.055, 0);
573
- roadGroup.add(leftEdge);
574
-
575
- const rightEdge = new THREE.Mesh(edgeLineGeo, edgeMat);
576
- rightEdge.position.set(7, 0.055, 0);
577
- roadGroup.add(rightEdge);
578
-
579
- const streetLightMat = new THREE.MeshStandardMaterial({ color: 0x444444, metalness: 0.5, roughness: 0.5 });
580
- const streetLightHeadMat = new THREE.MeshStandardMaterial({ color: 0xFFFAE0, emissive: 0xFFFAE0, emissiveIntensity: 0.3 });
581
-
582
- for (let z = -50; z <= 50; z += 25) {
583
- const pole = new THREE.Mesh(
584
- new THREE.CylinderGeometry(0.1, 0.15, 8, 8),
585
- streetLightMat
586
- );
587
- pole.position.set(-8, 4, z);
588
- pole.castShadow = true;
589
- roadGroup.add(pole);
590
-
591
- const arm = new THREE.Mesh(
592
- new THREE.BoxGeometry(3, 0.08, 0.08),
593
- streetLightMat
594
- );
595
- arm.position.set(-6.5, 7.8, z);
596
- roadGroup.add(arm);
597
-
598
- const head = new THREE.Mesh(
599
- new THREE.BoxGeometry(1, 0.15, 0.4),
600
- streetLightHeadMat
601
- );
602
- head.position.set(-5, 7.7, z);
603
- roadGroup.add(head);
604
-
605
- const light = new THREE.PointLight(0xFFFAE0, 0.6, 40, 1.5);
606
- light.position.set(-5, 7.2, z);
607
- roadGroup.add(light);
608
- }
609
-
610
- const billboardMat = new THREE.MeshStandardMaterial({ color: 0x1565C0, metalness: 0.1, roughness: 0.4 });
611
- const billboardGeo = new THREE.BoxGeometry(10, 5, 0.5);
612
- const billboard = new THREE.Mesh(billboardGeo, billboardMat);
613
- billboard.position.set(20, 7, -50);
614
- billboard.castShadow = true;
615
- roadGroup.add(billboard);
616
-
617
- const signPole = new THREE.Mesh(
618
- new THREE.CylinderGeometry(0.15, 0.2, 7, 6),
619
- streetLightMat
620
- );
621
- signPole.position.set(20, 3.5, -50);
622
- signPole.castShadow = true;
623
- roadGroup.add(signPole);
624
-
625
- const guardrailMat = new THREE.MeshStandardMaterial({ color: 0xAAAAAA, metalness: 0.6, roughness: 0.3 });
626
- for (let z = -60; z < 60; z += 3) {
627
- const rail = new THREE.Mesh(
628
- new THREE.BoxGeometry(0.1, 0.6, 2.8),
629
- guardrailMat
630
- );
631
- rail.position.set(7.2, 0.5, z);
632
- roadGroup.add(rail);
633
-
634
- const post = new THREE.Mesh(
635
- new THREE.CylinderGeometry(0.06, 0.06, 0.8, 4),
636
- guardrailMat
637
- );
638
- post.position.set(7.2, 0.4, z + 1.4);
639
- roadGroup.add(post);
640
- }
641
-
642
- scene.add(roadGroup);
643
- }
644
-
645
- function buildVehicles() {
646
- carGroup = new THREE.Group();
647
- scene.add(carGroup);
648
-
649
- const bodyMat = new THREE.MeshPhysicalMaterial({
650
- color: 0xE53935,
651
- roughness: 0.3,
652
- metalness: 0.4,
653
- clearcoat: 0.8,
654
- clearcoatRoughness: 0.1
655
- });
656
-
657
- const carBodyShape = new THREE.Shape();
658
- carBodyShape.moveTo(-2.1, 0.55);
659
- carBodyShape.lineTo(-2.1, 1.1);
660
- carBodyShape.lineTo(-1.6, 1.25);
661
- carBodyShape.lineTo(-1.1, 1.6);
662
- carBodyShape.lineTo(1.1, 1.6);
663
- carBodyShape.lineTo(1.6, 1.25);
664
- carBodyShape.lineTo(2.1, 1.1);
665
- carBodyShape.lineTo(2.1, 0.55);
666
- carBodyShape.lineTo(-2.1, 0.55);
667
-
668
- const bodyExtrudeSettings = {
669
- steps: 1,
670
- depth: 1.8,
671
- bevelEnabled: true,
672
- bevelThickness: 0.05,
673
- bevelSize: 0.05,
674
- bevelSegments: 3
675
- };
676
-
677
- const bodyGeo = new THREE.ExtrudeGeometry(carBodyShape, bodyExtrudeSettings);
678
- bodyGeo.center();
679
- carBody = new THREE.Mesh(bodyGeo, bodyMat);
680
- carBody.castShadow = true;
681
- carBody.receiveShadow = true;
682
- carGroup.add(carBody);
683
-
684
- const cabinShape = new THREE.Shape();
685
- cabinShape.moveTo(-1.05, 1.4);
686
- cabinShape.lineTo(-0.7, 2.1);
687
- cabinShape.lineTo(0.7, 2.1);
688
- cabinShape.lineTo(1.05, 1.4);
689
- cabinShape.lineTo(-1.05, 1.4);
690
-
691
- const cabinGeo = new THREE.ExtrudeGeometry(cabinShape, {
692
- steps: 1,
693
- depth: 1.4,
694
- bevelEnabled: true,
695
- bevelThickness: 0.03,
696
- bevelSize: 0.03,
697
- bevelSegments: 2
698
- });
699
- cabinGeo.center();
700
- const cabinMat = new THREE.MeshPhysicalMaterial({
701
- color: 0x111111,
702
- roughness: 0.05,
703
- metalness: 0.9,
704
- transparent: true,
705
- opacity: 0.5,
706
- transmission: 0.3
707
- });
708
- const cabin = new THREE.Mesh(cabinGeo, cabinMat);
709
- cabin.position.y = 0.9;
710
- carGroup.add(cabin);
711
-
712
- const frameMat = new THREE.MeshStandardMaterial({ color: 0x1A1A1A, roughness: 0.5, metalness: 0.7 });
713
- const pillarGeo = new THREE.BoxGeometry(0.06, 0.8, 0.06);
714
-
715
- const aPillarL = new THREE.Mesh(pillarGeo, frameMat);
716
- aPillarL.position.set(0.65, 1.75, -0.68);
717
- aPillarL.rotation.z = -0.15;
718
- carGroup.add(aPillarL);
719
- const aPillarR = new THREE.Mesh(pillarGeo, frameMat);
720
- aPillarR.position.set(0.65, 1.75, 0.68);
721
- aPillarR.rotation.z = -0.15;
722
- carGroup.add(aPillarR);
723
-
724
- const cPillarL = new THREE.Mesh(pillarGeo, frameMat);
725
- cPillarL.position.set(-0.65, 1.75, -0.68);
726
- cPillarL.rotation.z = 0.15;
727
- carGroup.add(cPillarL);
728
- const cPillarR = new THREE.Mesh(pillarGeo, frameMat);
729
- cPillarR.position.set(-0.65, 1.75, 0.68);
730
- cPillarR.rotation.z = 0.15;
731
- carGroup.add(cPillarR);
732
-
733
- const roofGeo = new THREE.BoxGeometry(1.1, 0.05, 1.3);
734
- const roofMat = new THREE.MeshStandardMaterial({ color: 0xE53935, roughness: 0.3, metalness: 0.4 });
735
- const roof = new THREE.Mesh(roofGeo, roofMat);
736
- roof.position.set(0, 2.15, 0);
737
- roof.castShadow = true;
738
- carGroup.add(roof);
739
-
740
- const grillGeo = new THREE.BoxGeometry(0.12, 0.25, 1.3);
741
- const grillMat = new THREE.MeshStandardMaterial({ color: 0x1A1A1A, roughness: 0.4, metalness: 0.8 });
742
- const grill = new THREE.Mesh(grillGeo, grillMat);
743
- grill.position.set(2.05, 0.82, 0);
744
- carGroup.add(grill);
745
-
746
- const bumperFGeo = new THREE.BoxGeometry(0.2, 0.15, 1.9);
747
- const bumperMat = new THREE.MeshStandardMaterial({ color: 0x212121, roughness: 0.6, metalness: 0.3 });
748
- const bumperF = new THREE.Mesh(bumperFGeo, bumperMat);
749
- bumperF.position.set(2.15, 0.6, 0);
750
- carGroup.add(bumperF);
751
-
752
- const bumperR = new THREE.Mesh(bumperFGeo, bumperMat);
753
- bumperR.position.set(-2.15, 0.6, 0);
754
- carGroup.add(bumperR);
755
-
756
- const headlightGeo = new THREE.BoxGeometry(0.1, 0.18, 0.45);
757
- const headlightMat = new THREE.MeshStandardMaterial({
758
- color: 0xFFFFE0,
759
- emissive: 0xFFFFE0,
760
- emissiveIntensity: 3.0,
761
- roughness: 0.1,
762
- metalness: 0.5
763
- });
764
- const hlL = new THREE.Mesh(headlightGeo, headlightMat);
765
- hlL.position.set(2.1, 0.92, 0.55);
766
- hlL.name = 'headlightL';
767
- carGroup.add(hlL);
768
- const hlR = new THREE.Mesh(headlightGeo, headlightMat);
769
- hlR.position.set(2.1, 0.92, -0.55);
770
- hlR.name = 'headlightR';
771
- carGroup.add(hlR);
772
-
773
- const taillightGeo = new THREE.BoxGeometry(0.1, 0.2, 0.45);
774
- const taillightMat = new THREE.MeshStandardMaterial({
775
- color: 0xFF0000,
776
- emissive: 0xFF0000,
777
- emissiveIntensity: 2.5,
778
- roughness: 0.2,
779
- metalness: 0.5
780
- });
781
- const tlL = new THREE.Mesh(taillightGeo, taillightMat);
782
- tlL.position.set(-2.1, 0.92, 0.55);
783
- tlL.name = 'taillightL';
784
- carGroup.add(tlL);
785
- const tlR = new THREE.Mesh(taillightGeo, taillightMat);
786
- tlR.position.set(-2.1, 0.92, -0.55);
787
- tlR.name = 'taillightR';
788
- carGroup.add(tlR);
789
-
790
- const hoodGeo = new THREE.BoxGeometry(0.9, 0.03, 1.7);
791
- const hoodMat = new THREE.MeshStandardMaterial({ color: 0xE53935, roughness: 0.25, metalness: 0.5 });
792
- const hood = new THREE.Mesh(hoodGeo, hoodMat);
793
- hood.position.set(1.3, 1.14, 0);
794
- carGroup.add(hood);
795
-
796
- const trunkGeo = new THREE.BoxGeometry(0.6, 0.03, 1.7);
797
- const trunk = new THREE.Mesh(trunkGeo, hoodMat);
798
- trunk.position.set(-1.5, 1.14, 0);
799
- carGroup.add(trunk);
800
-
801
- const mirrorGeo = new THREE.BoxGeometry(0.15, 0.12, 0.25);
802
- const mirrorMat = new THREE.MeshStandardMaterial({ color: 0x212121, roughness: 0.3, metalness: 0.6 });
803
- const mirrorL = new THREE.Mesh(mirrorGeo, mirrorMat);
804
- mirrorL.position.set(0.4, 1.45, 0.95);
805
- carGroup.add(mirrorL);
806
- const mirrorR = new THREE.Mesh(mirrorGeo, mirrorMat);
807
- mirrorR.position.set(0.4, 1.45, -0.95);
808
- carGroup.add(mirrorR);
809
-
810
- const spoilerGeo = new THREE.BoxGeometry(0.4, 0.05, 1.6);
811
- const spoilerMat = new THREE.MeshStandardMaterial({ color: 0x212121, roughness: 0.3, metalness: 0.7 });
812
- const spoiler = new THREE.Mesh(spoilerGeo, spoilerMat);
813
- spoiler.position.set(-1.8, 1.55, 0);
814
- carGroup.add(spoiler);
815
-
816
- const spoilerSupportGeo = new THREE.BoxGeometry(0.08, 0.25, 0.08);
817
- const supportL = new THREE.Mesh(spoilerSupportGeo, spoilerMat);
818
- supportL.position.set(-1.8, 1.4, 0.5);
819
- carGroup.add(supportL);
820
- const supportR = new THREE.Mesh(spoilerSupportGeo, spoilerMat);
821
- supportR.position.set(-1.8, 1.4, -0.5);
822
- carGroup.add(supportR);
823
-
824
- const wheelGeo = new THREE.CylinderGeometry(0.38, 0.38, 0.28, 24);
825
- const wheelMat = new THREE.MeshStandardMaterial({ color: 0x1A1A1A, roughness: 0.95 });
826
- const rimGeo = new THREE.CylinderGeometry(0.22, 0.22, 0.29, 16);
827
- const rimMat = new THREE.MeshStandardMaterial({ color: 0xCCCCCC, roughness: 0.2, metalness: 0.9 });
828
-
829
- const spokeGeo = new THREE.BoxGeometry(0.3, 0.02, 0.04);
830
- const spokeMat = new THREE.MeshStandardMaterial({ color: 0x999999, roughness: 0.3, metalness: 0.8 });
831
-
832
- const wheelPositions = [
833
- [1.55, 0.38, 0.85],
834
- [1.55, 0.38, -0.85],
835
- [-1.55, 0.38, 0.85],
836
- [-1.55, 0.38, -0.85]
837
- ];
838
-
839
- wheelPositions.forEach((pos, i) => {
840
- const wGroup = new THREE.Group();
841
- wGroup.position.set(pos[0], pos[1], pos[2]);
842
- const tire = new THREE.Mesh(wheelGeo, wheelMat);
843
- tire.rotation.z = Math.PI / 2;
844
- tire.castShadow = true;
845
- wGroup.add(tire);
846
-
847
- const rim = new THREE.Mesh(rimGeo, rimMat);
848
- rim.rotation.z = Math.PI / 2;
849
- wGroup.add(rim);
850
-
851
- for (let s = 0; s < 5; s++) {
852
- const spoke = new THREE.Mesh(spokeGeo, spokeMat);
853
- spoke.rotation.z = Math.PI / 2;
854
- spoke.rotation.x = (s / 5) * Math.PI * 2;
855
- wGroup.add(spoke);
856
- }
857
-
858
- const centerCap = new THREE.Mesh(
859
- new THREE.CylinderGeometry(0.06, 0.06, 0.3, 8),
860
- rimMat
861
- );
862
- centerCap.rotation.z = Math.PI / 2;
863
- wGroup.add(centerCap);
864
-
865
- carGroup.add(wGroup);
866
- wheelMeshes.push(wGroup);
867
- wheels.push({ position: new THREE.Vector3(pos[0], pos[1], pos[2]), suspension: 0, angularVel: 0, steer: 0 });
868
- });
869
-
870
- const headlightBeamMat = new THREE.MeshBasicMaterial({
871
- color: 0xFFF8DC,
872
- transparent: true,
873
- opacity: 0.05,
874
- side: THREE.DoubleSide,
875
- depthWrite: false,
876
- blending: THREE.AdditiveBlending
877
- });
878
-
879
- const beamGeo = new THREE.ConeGeometry(2.5, 18, 32, 1, true);
880
- const beamL = new THREE.Mesh(beamGeo, headlightBeamMat);
881
- beamL.position.set(2.2, 0.92, 0.55);
882
- beamL.rotation.z = -Math.PI / 2;
883
- beamL.rotation.y = 0.05;
884
- beamL.name = 'headlightBeamL';
885
- carGroup.add(beamL);
886
-
887
- const beamR = new THREE.Mesh(beamGeo, headlightBeamMat);
888
- beamR.position.set(2.2, 0.92, -0.55);
889
- beamR.rotation.z = -Math.PI / 2;
890
- beamR.rotation.y = -0.05;
891
- beamR.name = 'headlightBeamR';
892
- carGroup.add(beamR);
893
-
894
- const headLightObj = new THREE.SpotLight(0xFFF8DC, 4.0, 80, Math.PI / 5, 0.6, 1.5);
895
- headLightObj.position.set(2.1, 0.92, 0);
896
- headLightObj.target.position.set(12, -2, 0);
897
- headLightObj.castShadow = true;
898
- headLightObj.shadow.mapSize.width = 1024;
899
- headLightObj.shadow.mapSize.height = 1024;
900
- headLightObj.name = 'headLightObj';
901
- carGroup.add(headLightObj);
902
- carGroup.add(headLightObj.target);
903
-
904
- const tailLightObj = new THREE.Point