141 lines
3.6 KiB
HTML
141 lines
3.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<title>Three.js + OrbitControls (importmap)</title>
|
|
<style>
|
|
body { margin: 0; overflow: hidden; }
|
|
canvas { display: block; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- Import map tells browser where "three" lives -->
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script type="module">
|
|
import * as THREE from "three"
|
|
import { OrbitControls } from "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/controls/OrbitControls.js"
|
|
|
|
// Scene
|
|
const scene = new THREE.Scene()
|
|
scene.background = new THREE.Color(0x202080)
|
|
|
|
// Camera
|
|
const perspCam = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
|
|
perspCam.position.set(3, 3, 5)
|
|
|
|
const aspect = window.innerWidth / window.innerHeight
|
|
const frustumSize = 10
|
|
const cam2d = new THREE.OrthographicCamera(
|
|
-frustumSize * aspect / 2,
|
|
frustumSize * aspect / 2,
|
|
frustumSize / 2,
|
|
-frustumSize / 2,
|
|
0.1,
|
|
1000
|
|
)
|
|
|
|
cam2d.position.set(0, 100, 0)
|
|
|
|
cam2d.lookAt(0, 0, 0)
|
|
|
|
let activeCam = perspCam
|
|
|
|
// Renderer
|
|
const renderer = new THREE.WebGLRenderer({ antialias: true })
|
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
|
document.body.appendChild(renderer.domElement)
|
|
|
|
// Cube
|
|
const geometry = new THREE.BoxGeometry()
|
|
const material = new THREE.MeshStandardMaterial({ color: 'red' })
|
|
const cube = new THREE.Mesh(geometry, material)
|
|
scene.add(cube)
|
|
cube.position.x+=2
|
|
|
|
|
|
// Light
|
|
const light = new THREE.DirectionalLight(0xffffff, 1)
|
|
light.position.set(5, 5, 5)
|
|
light.intensity = 2
|
|
scene.add(light)
|
|
this.scene.add(new THREE.AmbientLight(0xffffff, 0.4))
|
|
|
|
const snowman = new THREE.Group()
|
|
|
|
// Bottom sphere
|
|
const bottom = new THREE.Mesh(
|
|
new THREE.SphereGeometry(1, 32, 32),
|
|
new THREE.MeshStandardMaterial({ color: 'white' })
|
|
)
|
|
snowman.add(bottom)
|
|
|
|
// Middle sphere
|
|
const middle = new THREE.Mesh(
|
|
new THREE.SphereGeometry(0.7, 32, 32),
|
|
new THREE.MeshStandardMaterial({ color: 'white' })
|
|
)
|
|
middle.position.y = 1.3
|
|
snowman.add(middle)
|
|
|
|
// Head
|
|
const head = new THREE.Mesh(
|
|
new THREE.SphereGeometry(0.5, 32, 32),
|
|
new THREE.MeshStandardMaterial({ color: 'white' })
|
|
)
|
|
head.position.y = 2.3
|
|
snowman.add(head)
|
|
scene.add(new THREE.AmbientLight(0xffffff, 0.5) )
|
|
// Add the group to the scene
|
|
scene.add(snowman)
|
|
|
|
// Optional: expose to console
|
|
window.snowman = snowman
|
|
|
|
// Controls
|
|
const controls = new OrbitControls(perspCam, renderer.domElement)
|
|
|
|
// Resize handler
|
|
window.addEventListener('resize', () => {
|
|
perspCam.aspect = window.innerWidth / window.innerHeight
|
|
perspCam.updateProjectionMatrix()
|
|
renderer.setSize(window.innerWidth, window.innerHeight)
|
|
})
|
|
|
|
// Animation loop
|
|
function animate() {
|
|
requestAnimationFrame(animate)
|
|
cube.rotation.x += 0.01
|
|
cube.rotation.y += 0.01
|
|
controls.update()
|
|
renderer.render(scene, activeCam)
|
|
}
|
|
|
|
window.addEventListener('keydown', (e) => {
|
|
if (e.key.toLowerCase() === 'o') {
|
|
activeCam = (activeCam === perspCam ? cam2d : perspCam)
|
|
console.log('Switched to', activeCam.isPerspectiveCamera ? 'Perspective' : 'Orthographic')
|
|
}
|
|
})
|
|
|
|
animate()
|
|
|
|
window.THREE = THREE
|
|
window.scene = scene
|
|
window.renderer = renderer
|
|
window.cube = cube
|
|
window.light = light
|
|
light.intensity = 2
|
|
|
|
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|