import { Camera } from '../cameras/Camera.js'; import { Vector3 } from '../math/Vector3.js'; import { LineSegments } from '../objects/LineSegments.js'; import { Color } from '../math/Color.js'; import { LineBasicMaterial } from '../materials/LineBasicMaterial.js'; import { BufferGeometry } from '../core/BufferGeometry.js'; import { Float32BufferAttribute } from '../core/BufferAttribute.js'; const _vector = /*@__PURE__*/ new Vector3(); const _camera = /*@__PURE__*/ new Camera(); /** * - shows frustum, line of sight and up of the camera * - suitable for fast updates * - based on frustum visualization in lightgl.js shadowmap example * http://evanw.github.com/lightgl.js/tests/shadowmap.html */ class CameraHelper extends LineSegments { constructor( camera ) { const geometry = new BufferGeometry(); const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); const vertices = []; const colors = []; const pointMap = {}; // colors const colorFrustum = new Color( 0xffaa00 ); const colorCone = new Color( 0xff0000 ); const colorUp = new Color( 0x00aaff ); const colorTarget = new Color( 0xffffff ); const colorCross = new Color( 0x333333 ); // near addLine( 'n1', 'n2', colorFrustum ); addLine( 'n2', 'n4', colorFrustum ); addLine( 'n4', 'n3', colorFrustum ); addLine( 'n3', 'n1', colorFrustum ); // far addLine( 'f1', 'f2', colorFrustum ); addLine( 'f2', 'f4', colorFrustum ); addLine( 'f4', 'f3', colorFrustum ); addLine( 'f3', 'f1', colorFrustum ); // sides addLine( 'n1', 'f1', colorFrustum ); addLine( 'n2', 'f2', colorFrustum ); addLine( 'n3', 'f3', colorFrustum ); addLine( 'n4', 'f4', colorFrustum ); // cone addLine( 'p', 'n1', colorCone ); addLine( 'p', 'n2', colorCone ); addLine( 'p', 'n3', colorCone ); addLine( 'p', 'n4', colorCone ); // up addLine( 'u1', 'u2', colorUp ); addLine( 'u2', 'u3', colorUp ); addLine( 'u3', 'u1', colorUp ); // target addLine( 'c', 't', colorTarget ); addLine( 'p', 'c', colorCross ); // cross addLine( 'cn1', 'cn2', colorCross ); addLine( 'cn3', 'cn4', colorCross ); addLine( 'cf1', 'cf2', colorCross ); addLine( 'cf3', 'cf4', colorCross ); function addLine( a, b, color ) { addPoint( a, color ); addPoint( b, color ); } function addPoint( id, color ) { vertices.push( 0, 0, 0 ); colors.push( color.r, color.g, color.b ); if ( pointMap[ id ] === undefined ) { pointMap[ id ] = []; } pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); } geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); super( geometry, material ); this.type = 'CameraHelper'; this.camera = camera; if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); this.matrix = camera.matrixWorld; this.matrixAutoUpdate = false; this.pointMap = pointMap; this.update(); } update() { const geometry = this.geometry; const pointMap = this.pointMap; const w = 1, h = 1; // we need just camera projection matrix inverse // world matrix must be identity _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); // center / target setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); // near setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); // far setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); // up setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); // cross setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); geometry.getAttribute( 'position' ).needsUpdate = true; } dispose() { this.geometry.dispose(); this.material.dispose(); } } function setPoint( point, pointMap, geometry, camera, x, y, z ) { _vector.set( x, y, z ).unproject( camera ); const points = pointMap[ point ]; if ( points !== undefined ) { const position = geometry.getAttribute( 'position' ); for ( let i = 0, l = points.length; i < l; i ++ ) { position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); } } } export { CameraHelper };