WebGPUTest / index.html
awacke1's picture
Update index.html
f3968a6 verified
raw
history blame
7.91 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGPU Three.js Spaceship Fly-Through</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { WebGPURenderer } from 'three/addons/renderers/webgpu/WebGPURenderer.js';
// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
const renderer = new WebGPURenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
// Spaceship (simple geometry)
const shipGeometry = new THREE.ConeGeometry(0.5, 2, 32);
const shipMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00, metalness: 0.8, roughness: 0.2 });
const spaceship = new THREE.Mesh(shipGeometry, shipMaterial);
spaceship.position.set(0, 0, 0);
scene.add(spaceship);
// Particle system for buildings
const buildingCount = 100;
const buildingGeometry = new THREE.BufferGeometry();
const buildingPositions = new Float32Array(buildingCount * 3);
const buildingColors = new Float32Array(buildingCount * 3);
const buildingSizes = new Float32Array(buildingCount);
for (let i = 0; i < buildingCount; i++) {
buildingPositions[i * 3] = (Math.random() - 0.5) * 200;
buildingPositions[i * 3 + 1] = Math.random() * 10;
buildingPositions[i * 3 + 2] = (Math.random() - 0.5) * 200;
buildingColors[i * 3] = 0.2;
buildingColors[i * 3 + 1] = 0.6;
buildingColors[i * 3 + 2] = 1.0;
buildingSizes[i] = Math.random() * 2 + 1;
}
buildingGeometry.setAttribute('position', new THREE.BufferAttribute(buildingPositions, 3));
buildingGeometry.setAttribute('color', new THREE.BufferAttribute(buildingColors, 3));
buildingGeometry.setAttribute('size', new THREE.BufferAttribute(buildingSizes, 1));
const buildingMaterial = new THREE.PointsMaterial({
size: 2,
vertexColors: true,
transparent: true,
opacity: 0.7,
sizeAttenuation: true
});
const buildings = new THREE.Points(buildingGeometry, buildingMaterial);
scene.add(buildings);
// Particle system for people
const peopleCount = 200;
const peopleGeometry = new THREE.BufferGeometry();
const peoplePositions = new Float32Array(peopleCount * 3);
const peopleColors = new Float32Array(peopleCount * 3);
const peopleSizes = new Float32Array(peopleCount);
for (let i = 0; i < peopleCount; i++) {
peoplePositions[i * 3] = (Math.random() - 0.5) * 150;
peoplePositions[i * 3 + 1] = Math.random() * 5;
peoplePositions[i * 3 + 2] = (Math.random() - 0.5) * 150;
peopleColors[i * 3] = 1.0;
peopleColors[i * 3 + 1] = 0.8;
peopleColors[i * 3 + 2] = 0.8;
peopleSizes[i] = Math.random() * 0.5 + 0.2;
}
peopleGeometry.setAttribute('position', new THREE.BufferAttribute(peoplePositions, 3));
peopleGeometry.setAttribute('color', new THREE.BufferAttribute(peopleColors, 3));
peopleGeometry.setAttribute('size', new THREE.BufferAttribute(peopleSizes, 1));
const peopleMaterial = new THREE.PointsMaterial({
size: 0.5,
vertexColors: true,
transparent: true,
opacity: 0.6,
sizeAttenuation: true
});
const people = new THREE.Points(peopleGeometry, peopleMaterial);
scene.add(people);
// Instanced geometry for repeating objects (cubes)
const cubeCount = 50;
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshStandardMaterial({ color: 0xff00ff, metalness: 0.5, roughness: 0.4 });
const cubeMesh = new THREE.InstancedMesh(cubeGeometry, cubeMaterial, cubeCount);
const dummy = new THREE.Object3D();
for (let i = 0; i < cubeCount; i++) {
dummy.position.set(
(Math.random() - 0.5) * 100,
Math.random() * 10,
(Math.random() - 0.5) * 100
);
dummy.scale.setScalar(Math.random() * 0.5 + 0.5);
dummy.updateMatrix();
cubeMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(cubeMesh);
// Camera movement
let time = 0;
function updateCamera() {
time += 0.01;
camera.position.z -= 0.5; // Continuous forward movement
camera.position.x = Math.sin(time * 0.5) * 5; // Gentle side-to-side
camera.position.y = Math.cos(time * 0.3) * 2 + 5; // Up and down
camera.lookAt(new THREE.Vector3(0, 0, camera.position.z - 100));
}
// Parallax and repetition
function updateObjects() {
const positions = buildings.geometry.attributes.position.array;
for (let i = 0; i < buildingCount; i++) {
positions[i * 3 + 2] += 0.5; // Move towards camera
if (positions[i * 3 + 2] > camera.position.z + 100) {
positions[i * 3 + 2] -= 200; // Reset to back
}
}
buildings.geometry.attributes.position.needsUpdate = true;
const peoplePos = people.geometry.attributes.position.array;
for (let i = 0; i < peopleCount; i++) {
peoplePos[i * 3 + 2] += 0.7; // Faster movement for parallax
if (peoplePos[i * 3 + 2] > camera.position.z + 100) {
peoplePos[i * 3 + 2] -= 200;
}
}
people.geometry.attributes.position.needsUpdate = true;
for (let i = 0; i < cubeCount; i++) {
cubeMesh.getMatrixAt(i, dummy.matrix);
dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale);
dummy.position.z += 0.6;
if (dummy.position.z > camera.position.z + 100) {
dummy.position.z -= 200;
}
dummy.updateMatrix();
cubeMesh.setMatrixAt(i, dummy.matrix);
}
cubeMesh.instanceMatrix.needsUpdate = true;
}
// Animation loop
function animate() {
requestAnimationFrame(animate);
updateCamera();
updateObjects();
renderer.render(scene, camera);
}
animate();
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>