JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
const postProcessingConfig = {
active: true,
passes: [{
name: 'bloomPass',
active: true,
constructor: new helpers.passes.BloomUnrealPass({
resolution: new THREE.Vector2(256, 256),
strength: 0.9,
radius: 1.0,
threshold: 0.8
})
}, {
name: 'postPass',
active: true,
constructor: new helpers.passes.PostPass()
}]
}
const assets = [{
id: 'spaceship',
type: 'bin',
url: '/uploads/161101/city/spaceship.awd'
}]
class Renderer extends THREE.WebGLRenderer {
constructor(options = {
antialias: true,
alpha: true
}) {
super(options)
this.setSize(window.innerWidth, window.innerHeight)
this.setPixelRatio(window.devicePixelRatio)
this.setClearColor(0x000000, 1.0)
helpers.Window.add(::this.resize)
}
resize(width, height) {
this.setSize(width, height)
}
}
class Camera extends THREE.PerspectiveCamera {
constructor(fov, aspect, near, far) {
super(fov, aspect, near, far)
this.controls = new helpers.OrbitControls(this, document.getElementById('webgl-container'))
this.controls.enabled = false
this.GUI = helpers.GUI
this.resize = this.resize.bind(this)
helpers.Window.add(this.resize)
// this.addGUI()
}
addGUI() {
let toggleSwitch = 0
this.GUI.add(this.controls, 'enabled', {
label: 'OrbitControls',
onChange: (value) => {
toggleSwitch++
if (toggleSwitch % 2) return
console.log(this.controls.enabled)
}
})
}
update(delta) {
this.controls.update(delta)
}
resize(width, height) {
this.aspect = width / height
this.updateProjectionMatrix()
}
}
class Scene extends THREE.Scene {
constructor(Renderer, Camera, Loader) {
super()
this.renderer = Renderer
this.camera = Camera
this.loader = Loader
this.postProcessing = new helpers.PostProcessing(this, this.camera, this.renderer, postProcessingConfig)
this.postPass = this.postProcessing.getPass('postPass')
this.clock = new helpers.Clock()
this.mousePos = new THREE.Vector2()
this.looped = false
this.direction = 1
this.acceleration = 0
this.accelerationProgress = 0
this.citySize = 1200
this.halfCitySize = this.citySize / 2
this.cityBound = this.halfCitySize - 200
this.bind()
this.createScene()
this.initTls()
}
bind() {
this.handleMouseDown = ::this.handleMouseDown
this.handleMouseMove = ::this.handleMouseMove
this.handleTouchMove = ::this.handleTouchMove
document.addEventListener('mousedown', this.handleMouseDown, false)
document.addEventListener('mousemove', this.handleMouseMove, false)
document.addEventListener('touchmove', this.handleTouchMove, false)
}
handleMouseDown(event) {
TweenMax.to(this.accelerationTl, 0.35, {
progress: utils.clamp(0, 1, this.accelerationTl.progress() + 0.3),
ease: Expo.easeOut,
onComplete: () => {
this.accelerationTl.reverse()
}
})
}
handleMouseMove(event) {
const clientX = event.clientX
const clientY = event.clientY
this.mousePos.x = (clientX / window.innerWidth) * 2 - 1
this.mousePos.y = -(clientY / window.innerHeight) * 2 + 1
this.spaceshipTargetPosition.x = utils.clamp(-16, 16, this.spaceshipBasePosition.x + this.mousePos.x * 15) * this.direction
this.spaceshipTargetPosition.y = utils.map(this.mousePos.y, -1, 1, 3, 80)
this.spaceshipTargetPosition.z = this.spaceshipMesh.position.z
this.spaceshipTargetRotation.z = this.mousePos.x * Math.PI / 30
}
handleTouchMove(event) {
const clientX = event.touches[0].clientX
const clientY = event.touches[0].clientY
this.mousePos.x = (clientX / window.innerWidth) * 2 - 1
this.mousePos.y = -(clientY / window.innerHeight) * 2 + 1
this.spaceshipTargetPosition.x = utils.clamp(-16, 16, this.spaceshipBasePosition.x + this.mousePos.x * 15) * this.direction
this.spaceshipTargetPosition.y = utils.map(this.mousePos.y, -1, 1, 3, 80)
this.spaceshipTargetPosition.z = this.spaceshipMesh.position.z
this.spaceshipTargetRotation.z = this.mousePos.x * Math.PI / 30
}
initTls() {
this.accelerationTl = new TimelineMax({
paused: true
})
this.accelerationTl
.fromTo(this, 0.4, {
acceleration: 0
}, {
acceleration: 4
})
.to(this.postPass.material.uniforms.uRgbSplit.value, 0.4, {
x: 120,
y: 120,
ease: Expo.easeOut
}, 0)
.to(this.camera, 0.4, {
fov: 110,
onUpdate: () => {
this.camera.updateProjectionMatrix()
}
}, 0)
}
createScene() {
this.fog = new THREE.FogExp2(0x000000, 0.006)
const scale = this.citySize
const gridHelper = new THREE.GridHelper(scale / 2, 100)
this.add(gridHelper)
const aLight = new THREE.AmbientLight(0x212121)
this.add(aLight)
const dLight1 = new THREE.DirectionalLight(0xd8d8d8, 0.5)
dLight1.position.set(10, 16, -10)
this.add(dLight1)
const dLight2 = new THREE.DirectionalLight(0xc4c4c4, 0.6)
dLight2.position.set(-15, 10, -30)
this.add(dLight2)
const dLight3 = new THREE.DirectionalLight(0xa9a9a9, 0.4)
dLight3.position.set(0, 10, 10)
this.add(dLight3)
const boxGeometry = new THREE.BoxGeometry(1, 1, 1)
const boxMaterial = new THREE.MeshPhongMaterial({
color: 0x253a3f,
specular: 0x499293,
shininess: 5
})
const edgesGeometry = new THREE.EdgesGeometry(boxGeometry)
const planeG = new THREE.PlaneGeometry(1, 1, 1)
const planeM = new THREE.MeshBasicMaterial({
color: 0xffffff
})
const lineMaterial = new THREE.LineBasicMaterial({
color: 0xffffff,
fog: true,
linewidth: 1.5
})
const lineWidth = 0.2
const groundMaterial = new THREE.MeshPhongMaterial({
color: 0x141f22,
specular: 0x141f22,
shininess: 15
})
const ground = new THREE.Mesh(planeG, groundMaterial)
ground.rotation.set(-Math.PI / 2, 0, 0)
ground.position.setY(-0.1)
ground.scale.multiplyScalar(scale)
this.add(ground)
const lines = [
[-12 * 2, 0, 0],
[12 * 2, 0, 0]
]
for (let i = 0; i < lines.length; i++) {
const line = new THREE.Mesh(boxGeometry, lineMaterial)
line.position.fromArray(lines[i])
line.scale.set(lineWidth, lineWidth, scale)
this.add(line)
}
for (let j = 0; j < 900; j++) {
const box = new THREE.Mesh(boxGeometry, boxMaterial)
const boxHeight = utils.randomInt(8, 50)
const boxXPos = utils.randomFloat(-scale / 2 * 0.45, -16 * 2 - 5)
box.position.set((j % 2) ? boxXPos : Math.abs(boxXPos), boxHeight / 2, utils.randomInt(-this.halfCitySize, this.halfCitySize))
box.scale.set(utils.randomInt(3, 10), boxHeight, utils.randomInt(3, 10))
this.add(box)
const edges = new THREE.LineSegments(edgesGeometry, lineMaterial)
edges.position.copy(box.position)
edges.scale.copy(box.scale).multiplyScalar(1.001)
this.add(edges)
if (boxHeight <= 13) {
for (let i = 0; i < 10; i++) {
const plane = new THREE.Mesh(planeG, planeM)
plane.rotation.set(-Math.PI / 2, 0, 0)
plane.position.copy(box.position)
plane.position.y += utils.randomInt(-boxHeight / 2 + 2, boxHeight / 2 - 1)
plane.scale.set(box.scale.x, box.scale.z, 1).multiplyScalar(utils.randomFloat(1.1, 1.3))
this.add(plane)
}
}
}
const awdLoader = new helpers.AWDLoader()
const spaceshipObj = awdLoader.parse(this.loader.get('spaceship'))
this.spaceshipMesh = spaceshipObj.children[0].clone()
this.spaceshipMesh.material = new THREE.MeshPhongMaterial({
color: 0xffffff,
specular: 0xffffff,
shininess: 20
})
this.spaceshipMesh.scale.multiplyScalar(0.35)
this.spaceshipBasePosition = new THREE.Vector3(0, 5, 390)
this.spaceshipBaseRotation = this.spaceshipMesh.rotation.clone()
this.spaceshipTargetPosition = this.spaceshipBasePosition.clone()
this.spaceshipTargetRotation = this.spaceshipBaseRotation.clone()
this.lookAtPosition = new THREE.Vector3(this.spaceshipBasePosition.x, this.spaceshipBasePosition.y, -this.citySize)
this.spaceshipMesh.position.copy(this.spaceshipBasePosition)
this.add(this.spaceshipMesh)
this.render = this.render.bind(this)
this.raf = requestAnimationFrame(this.render)
}
render() {
this.postProcessing.update()
this.camera.update(this.clock.delta)
if (!this.looped && this.spaceshipMesh.position.z < -this.cityBound || this.spaceshipMesh.position.z > this.cityBound) {
this.looped = true
this.lookAtPosition.z = this.lookAtPosition.z * -1
if (this.spaceshipMesh.position.z < -this.cityBound) {
console.log('1')
this.direction = -1
} else if (this.spaceshipMesh.position.z > this.cityBound) {
console.log('2')
this.direction = 1
}
const rotation = (this.direction === 1) ? Math.PI * 2 * this.direction : Math.PI * this.direction
TweenMax.to(this.spaceshipTargetPosition, 0.4, {
x: 0,
ease: Expo.easeOut
})
TweenMax.to(this.spaceshipMesh.rotation, 2, {
y: rotation,
ease: Expo.easeOut,
onComplete: () => this.looped = false
})
TweenMax.fromTo(this.camera.rotation, 2, {
y: 0
}, {
y: 2 * Math.PI * this.direction,
ease: Expo.easeOut
})
}
const movementX = Math.sin(this.clock.time) * 6
const movementY = Math.sin(this.clock.time) * 4
this.spaceshipMesh.position.x += (this.spaceshipTargetPosition.x - this.spaceshipMesh.position.x + movementX) * .05
this.spaceshipMesh.position.y += (this.spaceshipTargetPosition.y - this.spaceshipMesh.position.y + movementY) * .015
this.spaceshipMesh.position.z -= (1 + this.acceleration) * this.direction
this.spaceshipMesh.rotation.z += (this.spaceshipTargetRotation.z - this.spaceshipMesh.rotation.z) * .025;
this.camera.position.x += (this.spaceshipMesh.position.x - this.camera.position.x) * .9
this.camera.position.y += (this.spaceshipMesh.position.y + 2 - this.camera.position.y) * .2
this.camera.position.z = this.spaceshipMesh.position.z + 10 * this.direction
this.camera.lookAt(this.lookAtPosition)
requestAnimationFrame(this.render)
}
}
class App {
/**
* begin method
*/
static begin() {
const credits = document.querySelector('.credits')
const loadingEl = document.querySelector('.loading')
const progress = document.querySelector('.loading__progress')
const progressTextEl = document.querySelector('.loading__progress__text')
const progressBarEl = document.querySelector('.loading__progress__bar')
credits.style.opacity = 1
progress.style.opacity = 1
// Renderer
const renderer = new Renderer()
const container = document.getElementById('webgl-container')
container.appendChild(renderer.domElement)
// Camera
const camera = new Camera(90, window.innerWidth / window.innerHeight, 0.1, 10000)
camera.position.x = 0
camera.position.y = 1500
camera.position.z = 400
// Scene
if (assets.length) {
const loader = helpers.assetsLoader({
assets, crossOrigin: 'anonymous'
})
loader.on('progress', progress => {
progressTextEl.innerHTML = `${Math.floor(progress * 100)}%`
progressBarEl.style.transform = `scale(${progress}, ${progress})`
})
loader.on('complete', assets => {
const scene = new Scene(renderer, camera, loader)
loadingEl.style.opacity = 0
})
loader.start()
} else {
loadingEl.style.display = 'none'
const scene = new Scene(renderer, camera)
}
}
}
let the = App.begin()