init
This commit is contained in:
127
rse/src/scene.ts
Normal file
127
rse/src/scene.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import * as THREE from 'three'
|
||||
|
||||
export interface SceneObjects {
|
||||
renderer: THREE.WebGLRenderer
|
||||
scene: THREE.Scene
|
||||
camera: THREE.PerspectiveCamera
|
||||
starsFar: THREE.Points
|
||||
starsMid: THREE.Points
|
||||
starsClose: THREE.Points
|
||||
dust: THREE.Points
|
||||
nebulaGroup: THREE.Group
|
||||
light1: THREE.PointLight
|
||||
light2: THREE.PointLight
|
||||
}
|
||||
|
||||
function createStarLayer(
|
||||
count: number, spread: number, size: number, opacity: number
|
||||
): THREE.Points {
|
||||
const geo = new THREE.BufferGeometry()
|
||||
const pos = new Float32Array(count * 3)
|
||||
const col = new Float32Array(count * 3)
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const i3 = i * 3
|
||||
pos[i3] = (Math.random() - 0.5) * spread
|
||||
pos[i3 + 1] = (Math.random() - 0.5) * spread
|
||||
pos[i3 + 2] = (Math.random() - 0.5) * spread
|
||||
|
||||
// Dark particles on white background
|
||||
const shade = Math.random() * 0.08
|
||||
col[i3] = shade; col[i3+1] = shade; col[i3+2] = shade + 0.02
|
||||
}
|
||||
|
||||
geo.setAttribute('position', new THREE.BufferAttribute(pos, 3))
|
||||
geo.setAttribute('color', new THREE.BufferAttribute(col, 3))
|
||||
|
||||
const mat = new THREE.PointsMaterial({
|
||||
size, vertexColors: true, transparent: true, opacity,
|
||||
sizeAttenuation: true, depthWrite: false,
|
||||
})
|
||||
|
||||
return new THREE.Points(geo, mat)
|
||||
}
|
||||
|
||||
export function createScene(canvas: HTMLCanvasElement): SceneObjects {
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true })
|
||||
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
|
||||
renderer.setClearColor(0x000000, 0) // transparent, CSS handles bg
|
||||
|
||||
const scene = new THREE.Scene()
|
||||
scene.fog = new THREE.FogExp2(0xf5f5f8, 0.00025)
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 5000)
|
||||
camera.position.set(0, 0, 600)
|
||||
|
||||
// Stars (dark particles)
|
||||
const starsFar = createStarLayer(6000, 4000, 1.0, 0.3)
|
||||
const starsMid = createStarLayer(3000, 2500, 1.8, 0.45)
|
||||
const starsClose = createStarLayer(1000, 1500, 2.5, 0.6)
|
||||
scene.add(starsFar, starsMid, starsClose)
|
||||
|
||||
// Dust (dark)
|
||||
const dustGeo = new THREE.BufferGeometry()
|
||||
const dustCount = 2000
|
||||
const dustPos = new Float32Array(dustCount * 3)
|
||||
for (let i = 0; i < dustCount; i++) {
|
||||
dustPos[i*3] = (Math.random() - 0.5) * 3000
|
||||
dustPos[i*3+1] = (Math.random() - 0.5) * 3000
|
||||
dustPos[i*3+2] = (Math.random() - 0.5) * 3000
|
||||
}
|
||||
dustGeo.setAttribute('position', new THREE.BufferAttribute(dustPos, 3))
|
||||
const dust = new THREE.Points(dustGeo, new THREE.PointsMaterial({
|
||||
size: 0.5, color: 0x222233, transparent: true, opacity: 0.3,
|
||||
depthWrite: false, sizeAttenuation: true,
|
||||
}))
|
||||
scene.add(dust)
|
||||
|
||||
const nebulaGroup = new THREE.Group()
|
||||
|
||||
// Lights
|
||||
scene.add(new THREE.AmbientLight(0xffffff, 0.6))
|
||||
|
||||
const light1 = new THREE.PointLight(0xccddee, 1.5, 1200)
|
||||
light1.position.set(200, 200, 200)
|
||||
scene.add(light1)
|
||||
|
||||
const light2 = new THREE.PointLight(0xbbbbdd, 1.0, 1000)
|
||||
light2.position.set(-300, -100, 100)
|
||||
scene.add(light2)
|
||||
|
||||
return {
|
||||
renderer, scene, camera,
|
||||
starsFar, starsMid, starsClose, dust, nebulaGroup,
|
||||
light1, light2,
|
||||
}
|
||||
}
|
||||
|
||||
export function updateScene(objs: SceneObjects, time: number, _dt: number, smoothX: number, smoothY: number) {
|
||||
const {
|
||||
camera, starsFar, starsMid, starsClose, dust, nebulaGroup,
|
||||
light1, light2,
|
||||
} = objs
|
||||
|
||||
// Camera
|
||||
camera.position.x = smoothX * 150
|
||||
camera.position.y = -smoothY * 100
|
||||
camera.position.z = 600 + Math.sin(time * 0.08) * 30
|
||||
camera.lookAt(smoothX * 30, -smoothY * 20, -150)
|
||||
|
||||
// Star parallax
|
||||
starsFar.rotation.y = time * 0.008 + smoothX * 0.015
|
||||
starsFar.rotation.x = time * 0.004 + smoothY * 0.015
|
||||
starsMid.rotation.y = time * 0.015 + smoothX * 0.03
|
||||
starsMid.rotation.x = time * 0.008 + smoothY * 0.03
|
||||
starsClose.rotation.y = time * 0.025 + smoothX * 0.05
|
||||
starsClose.rotation.x = time * 0.012 + smoothY * 0.05
|
||||
|
||||
// Dust
|
||||
dust.rotation.y = time * 0.005 + smoothX * 0.01
|
||||
dust.rotation.x = time * 0.003 + smoothY * 0.01
|
||||
|
||||
|
||||
// Lights
|
||||
light1.position.x = 200 + Math.sin(time * 0.25) * 120
|
||||
light2.position.y = -100 + Math.cos(time * 0.3) * 100
|
||||
}
|
||||
Reference in New Issue
Block a user