Spaces:
Running
Running
Add 2 files
Browse files- index.html +88 -39
- prompts.txt +2 -1
index.html
CHANGED
@@ -132,69 +132,104 @@
|
|
132 |
// Rocket materials
|
133 |
const rocketBodyMaterial = new THREE.MeshPhongMaterial({
|
134 |
color: 0xff3333,
|
135 |
-
shininess: 100
|
|
|
136 |
});
|
137 |
|
138 |
const rocketNoseMaterial = new THREE.MeshPhongMaterial({
|
139 |
color: 0xffffff,
|
140 |
-
shininess: 100
|
|
|
141 |
});
|
142 |
|
143 |
const rocketFinMaterial = new THREE.MeshPhongMaterial({
|
144 |
color: 0x3333ff,
|
145 |
-
shininess: 50
|
|
|
146 |
});
|
147 |
|
148 |
// Create a procedural rocket model
|
149 |
function createRocket() {
|
150 |
const rocketGroup = new THREE.Group();
|
151 |
|
152 |
-
// Rocket body (cylinder)
|
153 |
-
const bodyGeometry = new THREE.CylinderGeometry(0.
|
154 |
const body = new THREE.Mesh(bodyGeometry, rocketBodyMaterial);
|
155 |
body.position.y = 0.5;
|
|
|
156 |
rocketGroup.add(body);
|
157 |
|
158 |
-
// Rocket nose (cone)
|
159 |
-
const noseGeometry = new THREE.ConeGeometry(0.
|
160 |
const nose = new THREE.Mesh(noseGeometry, rocketNoseMaterial);
|
161 |
-
nose.position.y = 1.
|
|
|
162 |
rocketGroup.add(nose);
|
163 |
|
164 |
-
// Rocket fins (
|
165 |
-
const finGeometry = new THREE.BoxGeometry(0.
|
166 |
-
for (let i = 0; i <
|
167 |
const fin = new THREE.Mesh(finGeometry, rocketFinMaterial);
|
168 |
-
fin.position.y = 0.
|
169 |
-
fin.position.z = 0.
|
170 |
fin.rotation.x = Math.PI / 2;
|
171 |
-
fin.rotation.y = (i * Math.PI * 2 /
|
172 |
-
fin.position.x = Math.sin(fin.rotation.y) * 0.
|
173 |
-
fin.position.z = Math.cos(fin.rotation.y) * 0.
|
|
|
174 |
rocketGroup.add(fin);
|
175 |
}
|
176 |
|
177 |
-
// Rocket engine (small cylinder)
|
178 |
-
const engineGeometry = new THREE.CylinderGeometry(0.
|
179 |
-
const engine = new THREE.Mesh(engineGeometry, new THREE.MeshPhongMaterial({
|
|
|
|
|
|
|
180 |
engine.position.y = 0;
|
|
|
181 |
rocketGroup.add(engine);
|
182 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
return rocketGroup;
|
184 |
}
|
185 |
|
186 |
// Particle systems
|
187 |
function createFireParticles() {
|
188 |
-
const particleCount =
|
189 |
const particles = new THREE.BufferGeometry();
|
190 |
const positions = new Float32Array(particleCount * 3);
|
191 |
const colors = new Float32Array(particleCount * 3);
|
192 |
const sizes = new Float32Array(particleCount);
|
193 |
|
194 |
for (let i = 0; i < particleCount; i++) {
|
195 |
-
positions[i * 3] = (Math.random() - 0.5) * 0.
|
196 |
positions[i * 3 + 1] = Math.random() * -0.5;
|
197 |
-
positions[i * 3 + 2] = (Math.random() - 0.5) * 0.
|
198 |
|
199 |
// Fire colors (red, orange, yellow)
|
200 |
const color = new THREE.Color(
|
@@ -226,16 +261,16 @@
|
|
226 |
}
|
227 |
|
228 |
function createSmokeParticles() {
|
229 |
-
const particleCount =
|
230 |
const particles = new THREE.BufferGeometry();
|
231 |
const positions = new Float32Array(particleCount * 3);
|
232 |
const colors = new Float32Array(particleCount * 3);
|
233 |
const sizes = new Float32Array(particleCount);
|
234 |
|
235 |
for (let i = 0; i < particleCount; i++) {
|
236 |
-
positions[i * 3] = (Math.random() - 0.5) * 0.
|
237 |
positions[i * 3 + 1] = Math.random() * -1;
|
238 |
-
positions[i * 3 + 2] = (Math.random() - 0.5) * 0.
|
239 |
|
240 |
// Smoke colors (gray to white)
|
241 |
const gray = 0.5 + Math.random() * 0.5;
|
@@ -302,12 +337,8 @@
|
|
302 |
this.alive = true;
|
303 |
this.exploded = false;
|
304 |
|
305 |
-
//
|
306 |
-
this.
|
307 |
-
(Math.random() - 0.5) * 0.02,
|
308 |
-
(Math.random() - 0.5) * 0.02,
|
309 |
-
(Math.random() - 0.5) * 0.02
|
310 |
-
);
|
311 |
|
312 |
scene.add(this.group);
|
313 |
activeRockets.push(this);
|
@@ -328,10 +359,28 @@
|
|
328 |
const point = this.curve.getPoint(this.progress);
|
329 |
this.group.position.copy(point);
|
330 |
|
331 |
-
//
|
332 |
-
|
333 |
-
|
334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
|
336 |
// Update particles
|
337 |
this.updateParticles();
|
@@ -343,9 +392,9 @@
|
|
343 |
for (let i = 0; i < firePositions.length; i += 3) {
|
344 |
firePositions[i + 1] -= 0.01;
|
345 |
if (firePositions[i + 1] < -0.5) {
|
346 |
-
firePositions[i] = (Math.random() - 0.5) * 0.
|
347 |
firePositions[i + 1] = 0;
|
348 |
-
firePositions[i + 2] = (Math.random() - 0.5) * 0.
|
349 |
}
|
350 |
}
|
351 |
this.fireParticles.geometry.attributes.position.needsUpdate = true;
|
@@ -358,9 +407,9 @@
|
|
358 |
smokePositions[i + 2] += (Math.random() - 0.5) * 0.01;
|
359 |
|
360 |
if (smokePositions[i + 1] > 0) {
|
361 |
-
smokePositions[i] = (Math.random() - 0.5) * 0.
|
362 |
smokePositions[i + 1] = -1 + Math.random() * 0.5;
|
363 |
-
smokePositions[i + 2] = (Math.random() - 0.5) * 0.
|
364 |
}
|
365 |
}
|
366 |
this.smokeParticles.geometry.attributes.position.needsUpdate = true;
|
|
|
132 |
// Rocket materials
|
133 |
const rocketBodyMaterial = new THREE.MeshPhongMaterial({
|
134 |
color: 0xff3333,
|
135 |
+
shininess: 100,
|
136 |
+
specular: 0x111111
|
137 |
});
|
138 |
|
139 |
const rocketNoseMaterial = new THREE.MeshPhongMaterial({
|
140 |
color: 0xffffff,
|
141 |
+
shininess: 100,
|
142 |
+
specular: 0x111111
|
143 |
});
|
144 |
|
145 |
const rocketFinMaterial = new THREE.MeshPhongMaterial({
|
146 |
color: 0x3333ff,
|
147 |
+
shininess: 50,
|
148 |
+
specular: 0x111111
|
149 |
});
|
150 |
|
151 |
// Create a procedural rocket model
|
152 |
function createRocket() {
|
153 |
const rocketGroup = new THREE.Group();
|
154 |
|
155 |
+
// Rocket body (cylinder with more segments for better quality)
|
156 |
+
const bodyGeometry = new THREE.CylinderGeometry(0.15, 0.15, 1, 32, 32, false);
|
157 |
const body = new THREE.Mesh(bodyGeometry, rocketBodyMaterial);
|
158 |
body.position.y = 0.5;
|
159 |
+
body.castShadow = true;
|
160 |
rocketGroup.add(body);
|
161 |
|
162 |
+
// Rocket nose (cone with more segments)
|
163 |
+
const noseGeometry = new THREE.ConeGeometry(0.15, 0.3, 32, 1, true);
|
164 |
const nose = new THREE.Mesh(noseGeometry, rocketNoseMaterial);
|
165 |
+
nose.position.y = 1.15;
|
166 |
+
nose.castShadow = true;
|
167 |
rocketGroup.add(nose);
|
168 |
|
169 |
+
// Rocket fins (4 fins for better stability)
|
170 |
+
const finGeometry = new THREE.BoxGeometry(0.3, 0.05, 0.15);
|
171 |
+
for (let i = 0; i < 4; i++) {
|
172 |
const fin = new THREE.Mesh(finGeometry, rocketFinMaterial);
|
173 |
+
fin.position.y = 0.25;
|
174 |
+
fin.position.z = 0.075;
|
175 |
fin.rotation.x = Math.PI / 2;
|
176 |
+
fin.rotation.y = (i * Math.PI * 2 / 4);
|
177 |
+
fin.position.x = Math.sin(fin.rotation.y) * 0.25;
|
178 |
+
fin.position.z = Math.cos(fin.rotation.y) * 0.25;
|
179 |
+
fin.castShadow = true;
|
180 |
rocketGroup.add(fin);
|
181 |
}
|
182 |
|
183 |
+
// Rocket engine (small cylinder with more detail)
|
184 |
+
const engineGeometry = new THREE.CylinderGeometry(0.1, 0.1, 0.15, 32);
|
185 |
+
const engine = new THREE.Mesh(engineGeometry, new THREE.MeshPhongMaterial({
|
186 |
+
color: 0x222222,
|
187 |
+
shininess: 30
|
188 |
+
}));
|
189 |
engine.position.y = 0;
|
190 |
+
engine.castShadow = true;
|
191 |
rocketGroup.add(engine);
|
192 |
|
193 |
+
// Engine nozzle (cone)
|
194 |
+
const nozzleGeometry = new THREE.ConeGeometry(0.1, 0.1, 32);
|
195 |
+
const nozzle = new THREE.Mesh(nozzleGeometry, new THREE.MeshPhongMaterial({
|
196 |
+
color: 0x444444,
|
197 |
+
shininess: 50
|
198 |
+
}));
|
199 |
+
nozzle.position.y = -0.05;
|
200 |
+
nozzle.rotation.x = Math.PI;
|
201 |
+
nozzle.castShadow = true;
|
202 |
+
rocketGroup.add(nozzle);
|
203 |
+
|
204 |
+
// Add some details (rings around the body)
|
205 |
+
const ringGeometry = new THREE.TorusGeometry(0.15, 0.01, 16, 32);
|
206 |
+
const ringMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff });
|
207 |
+
|
208 |
+
const ring1 = new THREE.Mesh(ringGeometry, ringMaterial);
|
209 |
+
ring1.position.y = 0.8;
|
210 |
+
ring1.rotation.x = Math.PI / 2;
|
211 |
+
rocketGroup.add(ring1);
|
212 |
+
|
213 |
+
const ring2 = new THREE.Mesh(ringGeometry, ringMaterial);
|
214 |
+
ring2.position.y = 0.2;
|
215 |
+
ring2.rotation.x = Math.PI / 2;
|
216 |
+
rocketGroup.add(ring2);
|
217 |
+
|
218 |
return rocketGroup;
|
219 |
}
|
220 |
|
221 |
// Particle systems
|
222 |
function createFireParticles() {
|
223 |
+
const particleCount = 150;
|
224 |
const particles = new THREE.BufferGeometry();
|
225 |
const positions = new Float32Array(particleCount * 3);
|
226 |
const colors = new Float32Array(particleCount * 3);
|
227 |
const sizes = new Float32Array(particleCount);
|
228 |
|
229 |
for (let i = 0; i < particleCount; i++) {
|
230 |
+
positions[i * 3] = (Math.random() - 0.5) * 0.15;
|
231 |
positions[i * 3 + 1] = Math.random() * -0.5;
|
232 |
+
positions[i * 3 + 2] = (Math.random() - 0.5) * 0.15;
|
233 |
|
234 |
// Fire colors (red, orange, yellow)
|
235 |
const color = new THREE.Color(
|
|
|
261 |
}
|
262 |
|
263 |
function createSmokeParticles() {
|
264 |
+
const particleCount = 80;
|
265 |
const particles = new THREE.BufferGeometry();
|
266 |
const positions = new Float32Array(particleCount * 3);
|
267 |
const colors = new Float32Array(particleCount * 3);
|
268 |
const sizes = new Float32Array(particleCount);
|
269 |
|
270 |
for (let i = 0; i < particleCount; i++) {
|
271 |
+
positions[i * 3] = (Math.random() - 0.5) * 0.3;
|
272 |
positions[i * 3 + 1] = Math.random() * -1;
|
273 |
+
positions[i * 3 + 2] = (Math.random() - 0.5) * 0.3;
|
274 |
|
275 |
// Smoke colors (gray to white)
|
276 |
const gray = 0.5 + Math.random() * 0.5;
|
|
|
337 |
this.alive = true;
|
338 |
this.exploded = false;
|
339 |
|
340 |
+
// Store previous position for orientation calculation
|
341 |
+
this.prevPosition = startPosition.clone();
|
|
|
|
|
|
|
|
|
342 |
|
343 |
scene.add(this.group);
|
344 |
activeRockets.push(this);
|
|
|
359 |
const point = this.curve.getPoint(this.progress);
|
360 |
this.group.position.copy(point);
|
361 |
|
362 |
+
// Calculate direction vector
|
363 |
+
const direction = new THREE.Vector3().subVectors(point, this.prevPosition).normalize();
|
364 |
+
|
365 |
+
// Only update orientation if we have significant movement
|
366 |
+
if (direction.length() > 0.001) {
|
367 |
+
// Create a quaternion that orients the rocket along the direction vector
|
368 |
+
const targetQuaternion = new THREE.Quaternion();
|
369 |
+
const up = new THREE.Vector3(0, 1, 0);
|
370 |
+
|
371 |
+
// Create a matrix that looks in the direction we're moving
|
372 |
+
const rotationMatrix = new THREE.Matrix4();
|
373 |
+
rotationMatrix.lookAt(new THREE.Vector3(0, 0, 0), direction, up);
|
374 |
+
|
375 |
+
// Extract quaternion from matrix
|
376 |
+
targetQuaternion.setFromRotationMatrix(rotationMatrix);
|
377 |
+
|
378 |
+
// Apply rotation to the rocket (not the whole group)
|
379 |
+
this.rocket.quaternion.copy(targetQuaternion);
|
380 |
+
|
381 |
+
// Store current position for next frame
|
382 |
+
this.prevPosition.copy(point);
|
383 |
+
}
|
384 |
|
385 |
// Update particles
|
386 |
this.updateParticles();
|
|
|
392 |
for (let i = 0; i < firePositions.length; i += 3) {
|
393 |
firePositions[i + 1] -= 0.01;
|
394 |
if (firePositions[i + 1] < -0.5) {
|
395 |
+
firePositions[i] = (Math.random() - 0.5) * 0.15;
|
396 |
firePositions[i + 1] = 0;
|
397 |
+
firePositions[i + 2] = (Math.random() - 0.5) * 0.15;
|
398 |
}
|
399 |
}
|
400 |
this.fireParticles.geometry.attributes.position.needsUpdate = true;
|
|
|
407 |
smokePositions[i + 2] += (Math.random() - 0.5) * 0.01;
|
408 |
|
409 |
if (smokePositions[i + 1] > 0) {
|
410 |
+
smokePositions[i] = (Math.random() - 0.5) * 0.3;
|
411 |
smokePositions[i + 1] = -1 + Math.random() * 0.5;
|
412 |
+
smokePositions[i + 2] = (Math.random() - 0.5) * 0.3;
|
413 |
}
|
414 |
}
|
415 |
this.smokeParticles.geometry.attributes.position.needsUpdate = true;
|
prompts.txt
CHANGED
@@ -1 +1,2 @@
|
|
1 |
-
Create a fun 3d threejs toy to shoot rockets with fire and smoke particles, a detailed procedural rocket 3d model, threejs app, the rocket would alway start at the mouse cursors and fly back to the center of the circle in a indirect slow smooth random bezier trajectory to explode in the screen center.
|
|
|
|
1 |
+
Create a fun 3d threejs toy to shoot rockets with fire and smoke particles, a detailed procedural rocket 3d model, threejs app, the rocket would alway start at the mouse cursors and fly back to the center of the circle in a indirect slow smooth random bezier trajectory to explode in the screen center.
|
2 |
+
fix the rocket model quality and rocket orientation to the trajectory
|