3d-blog/src/javascript/Application.js
2024-01-21 11:21:47 +08:00

295 lines
9.7 KiB
JavaScript

import * as THREE from 'three'
import * as dat from 'dat.gui'
import Sizes from './Utils/Sizes.js'
import Time from './Utils/Time.js'
import World from './World/index.js'
import Resources from './Resources.js'
import Camera from './Camera.js'
import ThreejsJourney from './ThreejsJourney.js'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js'
import BlurPass from './Passes/Blur.js'
import GlowsPass from './Passes/Glows.js'
export default class Application
{
/**
* Constructor
*/
constructor(_options)
{
// Options
this.$canvas = _options.$canvas
// Set up
this.time = new Time()
this.sizes = new Sizes()
this.resources = new Resources()
this.setConfig()
this.setDebug()
this.setRenderer()
this.setCamera()
this.setPasses()
this.setWorld()
this.setTitle()
this.setThreejsJourney()
}
/**
* Set config
*/
setConfig()
{
this.config = {}
this.config.debug = window.location.hash === '#debug'
this.config.cyberTruck = window.location.hash === '#cybertruck'
this.config.touch = false
window.addEventListener('touchstart', () =>
{
this.config.touch = true
this.world.controls.setTouch()
this.passes.horizontalBlurPass.strength = 1
this.passes.horizontalBlurPass.material.uniforms.uStrength.value = new THREE.Vector2(this.passes.horizontalBlurPass.strength, 0)
this.passes.verticalBlurPass.strength = 1
this.passes.verticalBlurPass.material.uniforms.uStrength.value = new THREE.Vector2(0, this.passes.verticalBlurPass.strength)
}, { once: true })
}
/**
* Set debug
*/
setDebug()
{
if(this.config.debug)
{
this.debug = new dat.GUI({ width: 420 })
}
}
/**
* Set renderer
*/
setRenderer()
{
// Scene
this.scene = new THREE.Scene()
// Renderer
this.renderer = new THREE.WebGLRenderer({
canvas: this.$canvas,
alpha: true
})
// this.renderer.setClearColor(0x414141, 1)
this.renderer.setClearColor(0x000000, 1)
// this.renderer.setPixelRatio(Math.min(Math.max(window.devicePixelRatio, 1.5), 2))
this.renderer.setPixelRatio(2)
this.renderer.setSize(this.sizes.viewport.width, this.sizes.viewport.height)
this.renderer.physicallyCorrectLights = true
this.renderer.gammaFactor = 2.2
this.renderer.gammaOutPut = true
this.renderer.autoClear = false
// Resize event
this.sizes.on('resize', () =>
{
this.renderer.setSize(this.sizes.viewport.width, this.sizes.viewport.height)
})
}
/**
* Set camera
*/
setCamera()
{
this.camera = new Camera({
time: this.time,
sizes: this.sizes,
renderer: this.renderer,
debug: this.debug,
config: this.config
})
this.scene.add(this.camera.container)
this.time.on('tick', () =>
{
if(this.world && this.world.car)
{
this.camera.target.x = this.world.car.chassis.object.position.x
this.camera.target.y = this.world.car.chassis.object.position.y
}
})
}
setPasses()
{
this.passes = {}
// Debug
if(this.debug)
{
this.passes.debugFolder = this.debug.addFolder('postprocess')
// this.passes.debugFolder.open()
}
this.passes.composer = new EffectComposer(this.renderer)
// Create passes
this.passes.renderPass = new RenderPass(this.scene, this.camera.instance)
this.passes.horizontalBlurPass = new ShaderPass(BlurPass)
this.passes.horizontalBlurPass.strength = this.config.touch ? 0 : 1
this.passes.horizontalBlurPass.material.uniforms.uResolution.value = new THREE.Vector2(this.sizes.viewport.width, this.sizes.viewport.height)
this.passes.horizontalBlurPass.material.uniforms.uStrength.value = new THREE.Vector2(this.passes.horizontalBlurPass.strength, 0)
this.passes.verticalBlurPass = new ShaderPass(BlurPass)
this.passes.verticalBlurPass.strength = this.config.touch ? 0 : 1
this.passes.verticalBlurPass.material.uniforms.uResolution.value = new THREE.Vector2(this.sizes.viewport.width, this.sizes.viewport.height)
this.passes.verticalBlurPass.material.uniforms.uStrength.value = new THREE.Vector2(0, this.passes.verticalBlurPass.strength)
// Debug
if(this.debug)
{
const folder = this.passes.debugFolder.addFolder('blur')
folder.open()
folder.add(this.passes.horizontalBlurPass.material.uniforms.uStrength.value, 'x').step(0.001).min(0).max(10)
folder.add(this.passes.verticalBlurPass.material.uniforms.uStrength.value, 'y').step(0.001).min(0).max(10)
}
this.passes.glowsPass = new ShaderPass(GlowsPass)
this.passes.glowsPass.color = '#ffcfe0'
this.passes.glowsPass.material.uniforms.uPosition.value = new THREE.Vector2(0, 0.25)
this.passes.glowsPass.material.uniforms.uRadius.value = 0.7
this.passes.glowsPass.material.uniforms.uColor.value = new THREE.Color(this.passes.glowsPass.color)
this.passes.glowsPass.material.uniforms.uAlpha.value = 0.55
// Debug
if(this.debug)
{
const folder = this.passes.debugFolder.addFolder('glows')
folder.open()
folder.add(this.passes.glowsPass.material.uniforms.uPosition.value, 'x').step(0.001).min(- 1).max(2).name('positionX')
folder.add(this.passes.glowsPass.material.uniforms.uPosition.value, 'y').step(0.001).min(- 1).max(2).name('positionY')
folder.add(this.passes.glowsPass.material.uniforms.uRadius, 'value').step(0.001).min(0).max(2).name('radius')
folder.addColor(this.passes.glowsPass, 'color').name('color').onChange(() =>
{
this.passes.glowsPass.material.uniforms.uColor.value = new THREE.Color(this.passes.glowsPass.color)
})
folder.add(this.passes.glowsPass.material.uniforms.uAlpha, 'value').step(0.001).min(0).max(1).name('alpha')
}
// Add passes
this.passes.composer.addPass(this.passes.renderPass)
this.passes.composer.addPass(this.passes.horizontalBlurPass)
this.passes.composer.addPass(this.passes.verticalBlurPass)
this.passes.composer.addPass(this.passes.glowsPass)
// Time tick
this.time.on('tick', () =>
{
this.passes.horizontalBlurPass.enabled = this.passes.horizontalBlurPass.material.uniforms.uStrength.value.x > 0
this.passes.verticalBlurPass.enabled = this.passes.verticalBlurPass.material.uniforms.uStrength.value.y > 0
// Renderer
this.passes.composer.render()
// this.renderer.domElement.style.background = 'black'
// this.renderer.render(this.scene, this.camera.instance)
})
// Resize event
this.sizes.on('resize', () =>
{
this.renderer.setSize(this.sizes.viewport.width, this.sizes.viewport.height)
this.passes.composer.setSize(this.sizes.viewport.width, this.sizes.viewport.height)
this.passes.horizontalBlurPass.material.uniforms.uResolution.value.x = this.sizes.viewport.width
this.passes.horizontalBlurPass.material.uniforms.uResolution.value.y = this.sizes.viewport.height
this.passes.verticalBlurPass.material.uniforms.uResolution.value.x = this.sizes.viewport.width
this.passes.verticalBlurPass.material.uniforms.uResolution.value.y = this.sizes.viewport.height
})
}
/**
* Set world
*/
setWorld()
{
this.world = new World({
config: this.config,
debug: this.debug,
resources: this.resources,
time: this.time,
sizes: this.sizes,
camera: this.camera,
renderer: this.renderer,
passes: this.passes
})
this.scene.add(this.world.container)
}
/**
* Set title
*/
setTitle()
{
this.title = {}
this.title.frequency = 300
this.title.width = 20
this.title.position = 0
this.title.$element = document.querySelector('title')
this.title.absolutePosition = Math.round(this.title.width * 0.25)
this.time.on('tick', () =>
{
if(this.world.physics)
{
this.title.absolutePosition += this.world.physics.car.forwardSpeed
if(this.title.absolutePosition < 0)
{
this.title.absolutePosition = 0
}
}
})
window.setInterval(() =>
{
this.title.position = Math.round(this.title.absolutePosition % this.title.width)
document.title = `${'_'.repeat(this.title.width - this.title.position)}🚗${'_'.repeat(this.title.position)}`
}, this.title.frequency)
}
/**
* Set Three.js Journey
*/
setThreejsJourney()
{
this.threejsJourney = new ThreejsJourney({
config: this.config,
time: this.time,
world: this.world
})
}
/**
* Destructor
*/
destructor()
{
this.time.off('tick')
this.sizes.off('resize')
this.camera.orbitControls.dispose()
this.renderer.dispose()
this.debug.destroy()
}
}