awacke1 commited on
Commit
d046ba4
·
verified ·
1 Parent(s): 8ad17fe

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +191 -94
index.html CHANGED
@@ -1,12 +1,12 @@
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
- <title>Basic Three.js 2.5D Scene</title>
5
  <style>
6
- body { margin: 0; }
7
  canvas { display: block; }
8
  </style>
9
- </head>
10
  <body>
11
  <script type="importmap">
12
  {
@@ -16,136 +16,235 @@
16
  }
17
  }
18
  </script>
 
19
  <script type="module">
20
  import * as THREE from 'three';
21
 
22
- let scene, camera, renderer, playerMesh;
23
- let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
24
- const playerSpeed = 0.1;
 
 
 
 
25
 
26
  function init() {
27
  // --- Basic Setup ---
28
  scene = new THREE.Scene();
29
- scene.background = new THREE.Color(0x87CEEB); // Sky blue background
30
 
31
- // --- Camera (Orthographic for 2.5D feel) ---
32
  const aspect = window.innerWidth / window.innerHeight;
33
- const viewSize = 15; // How many units are visible vertically
34
  camera = new THREE.OrthographicCamera(
35
  -viewSize * aspect / 2, viewSize * aspect / 2,
36
  viewSize / 2, -viewSize / 2,
37
- 1, 1000
38
  );
39
- camera.position.set(5, 10, 5); // Positioned above and looking down
40
- camera.lookAt(0, 0, 0); // Look at the center of the scene
 
 
 
41
  scene.add(camera);
42
 
43
- // --- Lighting ---
44
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
 
45
  scene.add(ambientLight);
46
- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
47
- directionalLight.position.set(5, 10, 7.5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  scene.add(directionalLight);
 
 
 
49
 
50
 
51
  // --- Ground ---
52
- const groundGeometry = new THREE.PlaneGeometry(20, 20);
53
- const groundMaterial = new THREE.MeshLambertMaterial({ color: 0x228B22 }); // Forest green
54
- const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
55
- groundMesh.rotation.x = -Math.PI / 2; // Rotate to lie flat
56
- groundMesh.position.y = -0.5; // Slightly below origin
 
 
 
 
 
 
57
  scene.add(groundMesh);
58
 
59
- // --- Player Placeholder (Simple Cube) ---
60
- // In a real game, you'd load a sprite/texture here
61
- const playerGeometry = new THREE.BoxGeometry(0.8, 0.8, 0.8);
62
- const playerMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); // Red
63
- playerMesh = new THREE.Mesh(playerGeometry, playerMaterial);
64
- playerMesh.position.y = 0; // Place on top of the ground level
65
- scene.add(playerMesh);
66
-
67
 
68
- // --- Renderer ---
69
  renderer = new THREE.WebGLRenderer({ antialias: true });
70
  renderer.setSize(window.innerWidth, window.innerHeight);
 
 
71
  document.body.appendChild(renderer.domElement);
72
 
73
- // --- Event Listeners for Movement ---
74
- document.addEventListener('keydown', onKeyDown);
75
- document.addEventListener('keyup', onKeyUp);
76
- window.addEventListener('resize', onWindowResize); // Handle window resizing
77
 
78
  // --- Start Animation ---
79
  animate();
80
  }
81
 
82
- function onKeyDown(event) {
83
- switch (event.code) {
84
- case 'KeyW':
85
- case 'ArrowUp':
86
- moveForward = true;
87
- break;
88
- case 'KeyS':
89
- case 'ArrowDown':
90
- moveBackward = true;
91
- break;
92
- case 'KeyA':
93
- case 'ArrowLeft':
94
- moveLeft = true;
95
- break;
96
- case 'KeyD':
97
- case 'ArrowRight':
98
- moveRight = true;
99
- break;
100
- }
 
 
 
 
101
  }
102
 
103
- function onKeyUp(event) {
104
- switch (event.code) {
105
- case 'KeyW':
106
- case 'ArrowUp':
107
- moveForward = false;
108
- break;
109
- case 'KeyS':
110
- case 'ArrowDown':
111
- moveBackward = false;
112
- break;
113
- case 'KeyA':
114
- case 'ArrowLeft':
115
- moveLeft = false;
116
- break;
117
- case 'KeyD':
118
- case 'ArrowRight':
119
- moveRight = false;
120
- break;
121
- }
 
122
  }
123
 
124
- function updatePlayerPosition() {
125
- if (!playerMesh) return;
 
 
 
 
 
 
 
 
 
126
 
127
- const moveVector = new THREE.Vector3();
128
- if (moveForward) moveVector.z -= 1;
129
- if (moveBackward) moveVector.z += 1;
130
- if (moveLeft) moveVector.x -= 1;
131
- if (moveRight) moveVector.x += 1;
 
 
 
 
132
 
133
- // Normalize diagonal movement and apply speed
134
- if (moveVector.lengthSq() > 0) { // Check if there's any movement
135
- moveVector.normalize().multiplyScalar(playerSpeed);
136
- playerMesh.position.add(moveVector);
137
- }
138
 
139
- // Keep camera centered on player (optional basic follow)
140
- // camera.position.x = playerMesh.position.x;
141
- // camera.position.z = playerMesh.position.z + 5; // Adjust Z offset as needed
142
- // camera.lookAt(playerMesh.position);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
 
145
 
146
  function onWindowResize() {
147
  const aspect = window.innerWidth / window.innerHeight;
148
- const viewSize = 15;
149
  camera.left = -viewSize * aspect / 2;
150
  camera.right = viewSize * aspect / 2;
151
  camera.top = viewSize / 2;
@@ -155,11 +254,9 @@
155
  }
156
 
157
  function animate() {
158
- requestAnimationFrame(animate); // Loop the animation
159
-
160
- updatePlayerPosition(); // Update player based on input
161
-
162
- renderer.render(scene, camera); // Render the scene
163
  }
164
 
165
  // --- Start the app ---
 
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
+ <title>Three.js Pick and Place</title>
5
  <style>
6
+ body { margin: 0; overflow: hidden; } /* Hide scrollbars */
7
  canvas { display: block; }
8
  </style>
9
+ </head>
10
  <body>
11
  <script type="importmap">
12
  {
 
16
  }
17
  }
18
  </script>
19
+
20
  <script type="module">
21
  import * as THREE from 'three';
22
 
23
+ let scene, camera, renderer, groundMesh;
24
+ let raycaster, mouse;
25
+ const placedObjects = []; // Keep track of placed objects
26
+
27
+ // --- Access State from Streamlit (set in global scope via injection) ---
28
+ // Default value if injection fails for some reason
29
+ const selectedObjectType = window.SELECTED_OBJECT_TYPE || "None";
30
 
31
  function init() {
32
  // --- Basic Setup ---
33
  scene = new THREE.Scene();
34
+ scene.background = new THREE.Color(0xabcdef); // Light blue sky
35
 
36
+ // --- Camera (Orthographic adjusted for better view) ---
37
  const aspect = window.innerWidth / window.innerHeight;
38
+ const viewSize = 30; // Increase view size
39
  camera = new THREE.OrthographicCamera(
40
  -viewSize * aspect / 2, viewSize * aspect / 2,
41
  viewSize / 2, -viewSize / 2,
42
+ 0.1, 100 // Adjust near/far planes
43
  );
44
+ // Position camera higher and angled slightly for better 3D view
45
+ camera.position.set(10, 20, 10);
46
+ camera.lookAt(scene.position); // Look at the center
47
+ camera.zoom = 1.2; // Zoom in a bit
48
+ camera.updateProjectionMatrix();
49
  scene.add(camera);
50
 
51
+ // --- Lighting (Improved) ---
52
+ // Ambient light for overall illumination
53
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // Soft white light
54
  scene.add(ambientLight);
55
+
56
+ // Directional light for sunlight and shadows
57
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
58
+ directionalLight.position.set(15, 30, 20); // Adjust position for angle
59
+ directionalLight.castShadow = true;
60
+ // Configure shadow properties (important!)
61
+ directionalLight.shadow.mapSize.width = 2048; // Higher res shadows
62
+ directionalLight.shadow.mapSize.height = 2048;
63
+ directionalLight.shadow.camera.near = 0.5;
64
+ directionalLight.shadow.camera.far = 100;
65
+ // Adjust shadow camera frustum to cover the playable area
66
+ directionalLight.shadow.camera.left = -30;
67
+ directionalLight.shadow.camera.right = 30;
68
+ directionalLight.shadow.camera.top = 30;
69
+ directionalLight.shadow.camera.bottom = -30;
70
+ directionalLight.shadow.bias = -0.001; // Helps prevent shadow acne
71
+
72
  scene.add(directionalLight);
73
+ // Optional: Visualize the shadow camera
74
+ // const shadowHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
75
+ // scene.add(shadowHelper);
76
 
77
 
78
  // --- Ground ---
79
+ const groundGeometry = new THREE.PlaneGeometry(50, 50); // Larger ground
80
+ // Use MeshStandardMaterial for lighting/shadows
81
+ const groundMaterial = new THREE.MeshStandardMaterial({
82
+ color: 0x55aa55, // Grassy green
83
+ roughness: 0.9,
84
+ metalness: 0.1
85
+ });
86
+ groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
87
+ groundMesh.rotation.x = -Math.PI / 2; // Rotate flat
88
+ groundMesh.position.y = -0.05; // Position slightly below origin
89
+ groundMesh.receiveShadow = true; // Allow ground to receive shadows
90
  scene.add(groundMesh);
91
 
92
+ // --- Raycaster and Mouse Vector ---
93
+ raycaster = new THREE.Raycaster();
94
+ mouse = new THREE.Vector2();
 
 
 
 
 
95
 
96
+ // --- Renderer (Shadows Enabled) ---
97
  renderer = new THREE.WebGLRenderer({ antialias: true });
98
  renderer.setSize(window.innerWidth, window.innerHeight);
99
+ renderer.shadowMap.enabled = true; // Enable shadow map rendering
100
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Softer shadows
101
  document.body.appendChild(renderer.domElement);
102
 
103
+ // --- Event Listeners ---
104
+ document.addEventListener('mousemove', onMouseMove, false);
105
+ document.addEventListener('click', onDocumentClick, false);
106
+ window.addEventListener('resize', onWindowResize, false);
107
 
108
  // --- Start Animation ---
109
  animate();
110
  }
111
 
112
+ // --- Object Creation Functions (Using Primitives) ---
113
+
114
+ function createSimpleHouse() {
115
+ const group = new THREE.Group();
116
+ const mainMaterial = new THREE.MeshStandardMaterial({ color: 0xffccaa, roughness: 0.8 });
117
+ const roofMaterial = new THREE.MeshStandardMaterial({ color: 0xaa5533, roughness: 0.7 });
118
+
119
+ // Base (BoxGeometry)
120
+ const base = new THREE.Mesh(new THREE.BoxGeometry(2, 1.5, 2.5), mainMaterial);
121
+ base.position.y = 1.5 / 2; // Sit on ground
122
+ base.castShadow = true;
123
+ base.receiveShadow = true;
124
+ group.add(base);
125
+
126
+ // Roof (ConeGeometry or angled planes) - using Cone here
127
+ const roof = new THREE.Mesh(new THREE.ConeGeometry(1.8, 1, 4), roofMaterial); // Radius, Height, Segments (4 for pyramid)
128
+ roof.position.y = 1.5 + 1 / 2; // Place on top of base
129
+ roof.rotation.y = Math.PI / 4; // Align edges
130
+ roof.castShadow = true;
131
+ roof.receiveShadow = true;
132
+ group.add(roof);
133
+
134
+ return group;
135
  }
136
 
137
+ function createTree() {
138
+ const group = new THREE.Group();
139
+ const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513, roughness: 0.9 }); // Brown
140
+ const leavesMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22, roughness: 0.8 }); // Forest Green
141
+
142
+ // Trunk (CylinderGeometry)
143
+ const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.4, 2, 8), trunkMaterial); // RadiusTop, RadiusBottom, Height, Segments
144
+ trunk.position.y = 2 / 2;
145
+ trunk.castShadow = true;
146
+ trunk.receiveShadow = true;
147
+ group.add(trunk);
148
+
149
+ // Leaves (SphereGeometry or Icosahedron)
150
+ const leaves = new THREE.Mesh(new THREE.IcosahedronGeometry(1.2, 0), leavesMaterial); // Radius, Detail (0=less poly)
151
+ leaves.position.y = 2 + 0.8; // Place above trunk
152
+ leaves.castShadow = true;
153
+ leaves.receiveShadow = true;
154
+ group.add(leaves);
155
+
156
+ return group;
157
  }
158
 
159
+ function createRock() {
160
+ // Use Icosahedron for irregular shape, or Sphere with displacement later
161
+ const rockMaterial = new THREE.MeshStandardMaterial({ color: 0xaaaaaa, roughness: 0.8, metalness: 0.1 });
162
+ const rock = new THREE.Mesh(new THREE.IcosahedronGeometry(0.7, 0), rockMaterial); // Radius, Detail
163
+ rock.position.y = 0.7 / 2; // Sit on ground (approx)
164
+ rock.rotation.x = Math.random() * Math.PI;
165
+ rock.rotation.y = Math.random() * Math.PI;
166
+ rock.castShadow = true;
167
+ rock.receiveShadow = true;
168
+ return rock; // Simple mesh, no group needed
169
+ }
170
 
171
+ function createFencePost() {
172
+ const postMaterial = new THREE.MeshStandardMaterial({ color: 0xdeb887, roughness: 0.9 }); // BurlyWood
173
+ // Use BoxGeometry for a simple square post
174
+ const post = new THREE.Mesh(new THREE.BoxGeometry(0.2, 1.5, 0.2), postMaterial);
175
+ post.position.y = 1.5 / 2;
176
+ post.castShadow = true;
177
+ post.receiveShadow = true;
178
+ return post;
179
+ }
180
 
181
+ // --- Event Handlers ---
 
 
 
 
182
 
183
+ function onMouseMove(event) {
184
+ // Calculate mouse position in normalized device coordinates (-1 to +1)
185
+ mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
186
+ mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
187
+ }
188
+
189
+ function onDocumentClick(event) {
190
+ console.log("Click! Selected type:", selectedObjectType); // Debug
191
+ if (selectedObjectType === "None") {
192
+ console.log("No object type selected for placement.");
193
+ return; // Don't place anything if "None" is selected
194
+ }
195
+
196
+ // Update the picking ray with the camera and mouse position
197
+ raycaster.setFromCamera(mouse, camera);
198
+
199
+ // Calculate objects intersecting the picking ray - only check the ground
200
+ const intersects = raycaster.intersectObject(groundMesh);
201
+
202
+ if (intersects.length > 0) {
203
+ const intersectPoint = intersects[0].point;
204
+ console.log("Intersection at:", intersectPoint); // Debug
205
+
206
+ let newObject = null;
207
+
208
+ // Call the correct creation function based on the selected type
209
+ switch (selectedObjectType) {
210
+ case "Simple House":
211
+ newObject = createSimpleHouse();
212
+ break;
213
+ case "Tree":
214
+ newObject = createTree();
215
+ break;
216
+ case "Rock":
217
+ newObject = createRock();
218
+ break;
219
+ case "Fence Post":
220
+ newObject = createFencePost();
221
+ break;
222
+ default:
223
+ console.warn("Unknown object type:", selectedObjectType);
224
+ return; // Don't place unknown types
225
+ }
226
+
227
+ if (newObject) {
228
+ // Position the new object at the click point on the ground
229
+ // The Y position is handled within the create functions to sit on origin
230
+ newObject.position.x = intersectPoint.x;
231
+ newObject.position.z = intersectPoint.z;
232
+ // Y position might need slight adjustment depending on object origin
233
+ // For objects created with base at y=0, intersectPoint.y is close enough
234
+
235
+ scene.add(newObject);
236
+ placedObjects.push(newObject); // Track the object
237
+ console.log(`Placed ${selectedObjectType} at`, newObject.position);
238
+ }
239
+ } else {
240
+ console.log("Click did not intersect ground.");
241
+ }
242
  }
243
 
244
 
245
  function onWindowResize() {
246
  const aspect = window.innerWidth / window.innerHeight;
247
+ const viewSize = 30;
248
  camera.left = -viewSize * aspect / 2;
249
  camera.right = viewSize * aspect / 2;
250
  camera.top = viewSize / 2;
 
254
  }
255
 
256
  function animate() {
257
+ requestAnimationFrame(animate);
258
+ // Add any animations here later if needed
259
+ renderer.render(scene, camera);
 
 
260
  }
261
 
262
  // --- Start the app ---