|
| 1 | +import * as THREE from 'three'; |
| 2 | +import { FluidShadowsOptions } from '.'; |
| 3 | +import { hexToVec3 } from '../../utils'; |
| 4 | +//@ts-ignore |
| 5 | +import fragment from './fragment.glsl'; |
| 6 | +//@ts-ignore |
| 7 | +import vertex from './vertex.glsl'; |
| 8 | + |
| 9 | +export class FluidShadows { |
| 10 | + private scene!: THREE.Scene; |
| 11 | + private camera!: THREE.PerspectiveCamera; |
| 12 | + private geometry!: THREE.PlaneBufferGeometry | THREE.BoxGeometry; |
| 13 | + private light!: THREE.SpotLight; |
| 14 | + private material!: any; |
| 15 | + private mesh!: THREE.Mesh; |
| 16 | + private renderer!: THREE.WebGLRenderer; |
| 17 | + private clock!: THREE.Clock; |
| 18 | + |
| 19 | + private options = { |
| 20 | + backgroundColor: '0xffffff', |
| 21 | + shadowColor: '0xffffff', |
| 22 | + shadowIteration: 5, |
| 23 | + shadowSpectrum: 0.0, |
| 24 | + speed: 0.1 |
| 25 | + }; |
| 26 | + constructor(options?: FluidShadowsOptions) { |
| 27 | + if (options) { |
| 28 | + this.options = { ...this.options, ...options }; |
| 29 | + } |
| 30 | + } |
| 31 | + |
| 32 | + public init(canvas: HTMLCanvasElement) { |
| 33 | + this.scene = new THREE.Scene(); |
| 34 | + this.scene.background = new THREE.Color(this.options.backgroundColor); |
| 35 | + this.light = new THREE.SpotLight(this.options.backgroundColor, 1); |
| 36 | + |
| 37 | + const fov = 45; |
| 38 | + const aspect = window.innerWidth / window.innerHeight; |
| 39 | + const near = 1; |
| 40 | + const far = 100; |
| 41 | + this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far); |
| 42 | + this.geometry = new THREE.PlaneBufferGeometry(30, 10); |
| 43 | + this.material = new THREE.ShaderMaterial({ |
| 44 | + vertexShader: vertex, |
| 45 | + fragmentShader: fragment, |
| 46 | + uniforms: { |
| 47 | + uTime: { value: 0.0 }, |
| 48 | + uResolution: { value: { x: window.innerWidth, y: window.innerHeight } }, |
| 49 | + uColor: { value: hexToVec3(this.options.shadowColor) }, |
| 50 | + uMaxIter: { value: this.options.shadowIteration }, |
| 51 | + uSpectrum: { value: this.options.shadowSpectrum }, |
| 52 | + uSpeed: { value: this.options.speed } |
| 53 | + } |
| 54 | + }); |
| 55 | + this.mesh = new THREE.Mesh(this.geometry, this.material); |
| 56 | + this.renderer = new THREE.WebGLRenderer({ |
| 57 | + canvas: canvas |
| 58 | + }); |
| 59 | + this.renderer.setClearColor(this.options.backgroundColor, 1); |
| 60 | + this.renderer.setPixelRatio(window.devicePixelRatio); |
| 61 | + this.renderer.setSize(window.innerWidth, window.innerHeight); |
| 62 | + |
| 63 | + this.scene.add(this.camera); |
| 64 | + this.scene.add(this.mesh); |
| 65 | + this.scene.add(this.light); |
| 66 | + this.mesh.position.set(0, 0, 0); |
| 67 | + this.camera.position.set(0, 0, 10); |
| 68 | + this.light.position.set(0, 0, 10); |
| 69 | + |
| 70 | + this.light.lookAt(this.mesh.position); |
| 71 | + this.camera.lookAt(this.mesh.position); |
| 72 | + |
| 73 | + this.clock = new THREE.Clock(); |
| 74 | + |
| 75 | + this.addEvents(); |
| 76 | + } |
| 77 | + |
| 78 | + public run() { |
| 79 | + window.requestAnimationFrame(this.run.bind(this)); |
| 80 | + this.material.uniforms.uTime.value = this.clock.getElapsedTime(); |
| 81 | + this.renderer.render(this.scene, this.camera); |
| 82 | + } |
| 83 | + |
| 84 | + public setOptions(options?: FluidShadowsOptions) { |
| 85 | + if (options) { |
| 86 | + this.options = { ...this.options, ...options }; |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + private addEvents(): void { |
| 91 | + window.addEventListener('resize', this.onResize.bind(this), false); |
| 92 | + } |
| 93 | + |
| 94 | + private onResize() { |
| 95 | + this.material.uniforms.uResolution = { |
| 96 | + value: { x: window.innerWidth, y: window.innerHeight } |
| 97 | + }; |
| 98 | + this.camera.aspect = window.innerWidth / window.innerHeight; |
| 99 | + this.camera.updateProjectionMatrix(); |
| 100 | + this.renderer.setSize(window.innerWidth, window.innerHeight); |
| 101 | + } |
| 102 | +} |
0 commit comments