Skip to content

Instantly share code, notes, and snippets.

@PixxxeL
Created August 25, 2024 14:15
Show Gist options
  • Save PixxxeL/08fce298ff9b4d9e0317139eb4ad42c2 to your computer and use it in GitHub Desktop.
Save PixxxeL/08fce298ff9b4d9e0317139eb4ad42c2 to your computer and use it in GitHub Desktop.
Three.js Example: Camera Along Path
import * as THREE from 'three'
import { TeapotGeometry } from 'three/examples/jsm/geometries/TeapotGeometry'
const CAMERA_POSITION = [6, 3, 4]
const CAMERA_TARGET_POSITION = [0, 0, 0]
const ENV_MAPS = [
'assets/skybox/front.png',
'assets/skybox/back.png',
'assets/skybox/up.png',
'assets/skybox/down.png',
'assets/skybox/left.png',
'assets/skybox/right.png',
]
/**
* Usage:
* const app = new FlyingCamera('app-container')
* app.run()
*/
class FlyingCamera {
static id = 'FlyingCamera'
constructor (containerId) {
this.container = document.getElementById(containerId)
this.width = this.container.offsetWidth
this.height = this.container.offsetHeight
this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, .1, 1000)
this.camera.position.set(...CAMERA_POSITION)
this.camera.lookAt(...CAMERA_TARGET_POSITION)
this.cameraPath = null
this.cameraPosition = 1
// renderer
this.renderer = new THREE.WebGLRenderer({
antialias: true
})
this.renderer.outputEncoding = THREE.sRGBEncoding
this.renderer.setPixelRatio(window.devicePixelRatio)
this.renderer.setSize(this.width, this.height)
this.renderer.shadowMap.enabled = true
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
this.container.appendChild(this.renderer.domElement)
// scene
this.scene = new THREE.Scene()
this.setScene()
// on resize
window.addEventListener('resize', this.onResize.bind(this), false)
}
setScene() {
// scene
this.scene.background = new THREE.Color( 0xeeeeee )
this.scene.fog = new THREE.Fog( 0xeeeeee, 4, 20 )
// camera path
this.cameraPath = new THREE.CatmullRomCurve3(
[
new THREE.Vector3(6, 3, 4),
new THREE.Vector3(-5.5, 1.75, 3.5),
new THREE.Vector3(-5, .5, -3),
new THREE.Vector3(5.5, 1.75, -3.5)
]
)
this.cameraPath.curveType = 'centripetal'
this.cameraPath.closed = true
const v = new THREE.Vector3()
this.cameraPath.getPointAt(this.cameraPosition, v)
this.camera.position.set(...v.toArray())
// lights
const ambientLight = new THREE.HemisphereLight( 0xffffff, 0xbfd4d2, 4 )
this.scene.add( ambientLight )
const dirLight = new THREE.DirectionalLight( 0xffffff, 1 )
dirLight.position.set( 0, 2, 1 ).multiplyScalar( 6 )
dirLight.castShadow = true
dirLight.shadow.mapSize.setScalar( 2048 )
dirLight.shadow.bias = - 1e-4
dirLight.shadow.normalBias = 1e-4
this.scene.add( dirLight )
// geometry
const ground = new THREE.Mesh(
new THREE.PlaneGeometry(15, 15),
new THREE.MeshStandardMaterial( {
color: 0xaaaaaa,
side: THREE.DoubleSide
} ),
)
ground.receiveShadow = true
ground.rotation.x = - Math.PI / 2
ground.position.y = -0.9
this.scene.add( ground )
const envMap = new THREE.CubeTextureLoader().load( ENV_MAPS )
envMap.mapping = THREE.CubeRefractionMapping
const teapot = new THREE.Mesh(
new TeapotGeometry( 1, 10, false, true ),
new THREE.MeshPhysicalMaterial({
color: 0x0099cc,
metalness: 1.0,
roughness: 0.5,
clearcoat: 1.0,
clearcoatRoughness: 0.03,
envMap,
refractionRatio: 0.95,
side: THREE.DoubleSide
})
)
teapot.side = THREE.DoubleSide
teapot.castShadow = true
this.scene.add( teapot )
}
update() {
const v = new THREE.Vector3()
this.cameraPosition -= .001
if (this.cameraPosition < 0) {
this.cameraPosition = 1
}
this.cameraPath.getPointAt(this.cameraPosition, v)
this.camera.position.set(...v.toArray())
this.camera.lookAt(...CAMERA_TARGET_POSITION)
this.renderer.render(this.scene, this.camera)
}
run() {
requestAnimationFrame(() => this.run())
this.update()
}
onResize() {
this.width = this.container.offsetWidth
this.height = this.container.offsetHeight
this.camera.aspect = this.width / this.height
this.camera.updateProjectionMatrix()
this.renderer.setSize(this.width, this.height)
}
destroy() {}
}
export default FlyingCamera
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment