1
0
This commit is contained in:
2026-03-06 16:50:21 +09:00
commit 3375790f93
50 changed files with 2439 additions and 0 deletions

127
rse/src/scene.ts Normal file
View 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
}