UNPKG

awv3

Version:
198 lines (174 loc) 6.58 kB
import * as THREE from 'three'; import Object3 from '../three/object3'; import { Pool } from '../session/helpers'; import { exponential } from '../animation/easing'; export default class Presentation extends Pool { constructor(args) { super(args); this.options = { shadows: true, lights: true, ambient: 0, light: 0.95, shadowHeight: 0.9, shadowFactor: 1.2, ...args }; this._objects = new Objects({ pool: this }); super.add(this._objects); if (this.options.shadows) { this._stage = new Stage({ pool: this }); super.add(this._stage); } if (this.options.lights) { this._lights = new Lights({ pool: this }); super.add(this._lights); } } add(args) { this._objects.add(args); } addAsync(args) { return this._objects.addAsync(args); } remove(args) { this._objects.remove(args); } removeAsync(args) { return this._objects.removeAsync(args); } update() { if (this.view) { this._objects.update(); this.options.lights && this._lights.update(); this.options.shadows && this._stage.update(); } } } class Lights extends THREE.Group { constructor({ pool }) { super(); this.name = 'presentation.lights'; this.pool = pool; this.interactive = false; this.tweens = false; this.measurable = false; if (this.pool.options.ambient) { this.ambient = new THREE.AmbientLight(0xffffff, this.pool.options.ambient); this.add(this.ambient); } this.point1 = new THREE.DirectionalLight(0xffffff); this.point1.target = pool._objects; this.add(this.point1); this.point2 = new THREE.DirectionalLight(0xffffff); this.point2.target = pool._objects; this.add(this.point2); this.point3 = new THREE.DirectionalLight(0xffffff); this.point3.target = pool._objects; this.add(this.point3); this.point4 = new THREE.DirectionalLight(0xffffff); this.point4.target = pool._objects; this.add(this.point4); this.spot1 = new THREE.SpotLight(0xffffff); this.add(this.spot1); this.spot2 = new THREE.SpotLight(0xffffff); this.spot2.target = pool._objects; this.spot2.castShadow = true; this.spot2.penumbra = 1; this.spot2.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(20, 1, 100, 1000)); this.spot2.shadow.mapSize.width = 2048; this.spot2.shadow.mapSize.height = 2048; this.add(this.spot2); } update() { if (this.pool.parent) { this.quaternion.setFromUnitVectors(this.up, this.pool.view.camera.up); if (this.pool.options.ambient) { this.ambient.intensity = this.pool.options.ambient; } let radius = this.pool._objects.radius; let intensity = this.pool.options.light; let vec = this.pool.parent.worldToLocal(new THREE.Vector3(-radius / 2, radius, radius / 2)); this.point1.intensity = intensity / 2; this.point1.setPosition(-radius, 0, 0); this.point2.intensity = intensity / 2; this.point2.setPosition(radius, 0, 0); this.point3.intensity = intensity / 2; this.point3.setPosition(0, radius, 0); this.point4.intensity = intensity / 2; this.point4.setPosition(0, 0, radius); this.spot1.intensity = intensity / 2; this.spot1.setPosition(0, -radius, -radius * 2); this.spot2.intensity = intensity * 3; this.spot2.position.copy(vec); this.spot2.shadow.camera.far = radius * 1.5; this.spot2.shadow.camera.updateProjectionMatrix(); this.spot2.insensity = intensity; this.spot2.distance = radius * 1.5; this.spot2.angle = Math.PI / 6; } } } class Stage extends THREE.Group { constructor({ pool }) { super(); this.name = 'presentation.stage'; this.pool = pool; this.interactive = false; this.tweens = false; this.measurable = false; } update() { this.destroy(); if (!isNaN(this.pool._objects.width) && !isNaN(this.pool._objects.depth)) { this.quaternion.setFromUnitVectors(new THREE.Vector3(0, 0, 1), this.pool.view.camera.up); this.position.copy(this.pool._objects.getCenter()); this.position.addScaledVector(this.pool.view.camera.up, -this.pool._objects.height * this.pool.options.shadowHeight); var shadowGeo = new THREE.PlaneBufferGeometry( this.pool._objects.width * this.pool.options.shadowFactor, this.pool._objects.depth * this.pool.options.shadowFactor, 1, 1 ); var mesh = new THREE.Mesh(shadowGeo, shadowMaterial); this.add(mesh); } } } class Objects extends THREE.Group { constructor({ pool }) { super(); this.name = 'presentation.objects'; this.pool = pool; } update() { this.updateBounds(); this.min = this.bounds.box.min; this.max = this.bounds.box.max; this.width = this.max.distanceTo(new THREE.Vector3(this.min.x, this.max.y, this.max.z)); this.height = this.max.distanceTo(new THREE.Vector3(this.max.x, this.min.y, this.max.z)); this.depth = this.max.distanceTo(new THREE.Vector3(this.max.x, this.max.y, this.min.z)); this.radius = this.getRadius() * 6; } } function createShadowMaterial() { var canvas2d = document.createElement('canvas'); canvas2d.width = 128; canvas2d.height = 128; var context = canvas2d.getContext('2d'); var gradient = context.createRadialGradient( canvas2d.width / 2, canvas2d.height / 2, 0, canvas2d.width / 2, canvas2d.height / 2, canvas2d.width / 2 ); gradient.addColorStop(0.1, 'rgba(0,0,0,0.15)'); gradient.addColorStop(1, 'rgba(0,0,0,0)'); context.fillStyle = gradient; context.fillRect(0, 0, canvas2d.width, canvas2d.height); var shadowTexture = new THREE.CanvasTexture(canvas2d); return new THREE.MeshBasicMaterial({ map: shadowTexture, transparent: true }); } const shadowMaterial = createShadowMaterial();