threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
210 lines • 8.06 kB
JavaScript
import { Camera, Color, Vector3, } from 'three';
import { ACameraHelperWidget } from './ACameraHelperWidget';
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
import { LineMaterial2 } from '../../core';
/**
* Fork of CameraHelper from three.js
* - shows frustum, line of sight and up of the camera
* - suitable for fast updates
* - based on frustum visualization in lightgl.js shadowmap example
* https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html
*/
export class CameraHelper2 extends ACameraHelperWidget {
constructor(camera) {
super(camera);
this._vector = new Vector3();
this._camera = new Camera();
const geometry = new LineSegmentsGeometry();
const material = new LineMaterial2({
color: 0xffffff,
linewidth: 5, // in world units with size attenuation, pixels otherwise
vertexColors: true,
worldUnits: false,
dashed: false,
alphaToCoverage: true,
toneMapped: false,
transparent: true,
depthTest: false,
depthWrite: false,
});
material.userData.renderToGBuffer = false;
material.userData.renderToDepth = false;
const { vertices, colors, pointMap } = generateVertices();
geometry.setPositions(vertices);
geometry.setColors(colors);
this.line = new LineSegments2(geometry, material);
this.line.frustumCulled = false;
this.add(this.line);
this.pointMap = pointMap;
this.update();
// 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);
this.setColors(colorFrustum, colorCone, colorUp, colorTarget, colorCross);
}
setColors(frustum, cone, up, target, cross) {
const geometry = this.line.geometry;
const colorAttribute = geometry.getAttribute('instanceColorStart');
const colorAttribute2 = geometry.getAttribute('instanceColorEnd');
function setXYZ(i, color) {
colorAttribute.setXYZ(i / 2, color.r, color.g, color.b);
colorAttribute2.setXYZ(i / 2, color.r, color.g, color.b);
}
// near
setXYZ(0, frustum); // n1, n2
setXYZ(2, frustum); // n2, n4
setXYZ(4, frustum); // n4, n3
setXYZ(6, frustum); // n3, n1
// far
setXYZ(8, frustum); // f1, f2
setXYZ(10, frustum); // f2, f4
setXYZ(12, frustum); // f4, f3
setXYZ(14, frustum); // f3, f1
// sides
setXYZ(16, frustum); // n1, f1
setXYZ(18, frustum); // n2, f2
setXYZ(20, frustum); // n3, f3
setXYZ(22, frustum); // n4, f4
// cone
setXYZ(24, cone); // p, n1
setXYZ(26, cone); // p, n2
setXYZ(28, cone); // p, n3
setXYZ(30, cone); // p, n4
// up
setXYZ(32, up); // u1, u2
setXYZ(34, up); // u2, u3
setXYZ(36, up); // u3, u1
// target
setXYZ(38, target); // c, t
setXYZ(40, cross); // p, c
// cross
setXYZ(42, cross); // cn1, cn2
setXYZ(44, cross); // cn3, cn4
setXYZ(46, cross); // cf1, cf2
setXYZ(48, cross); // cf3, cf4
colorAttribute.needsUpdate = true;
colorAttribute2.needsUpdate = true;
}
update() {
if (!this.camera)
return;
const geometry = this.line.geometry;
const pointMap = this.pointMap;
const w = 1, h = 1;
// we need just camera projection matrix inverse
// world matrix must be identity
// eslint-disable-next-line @typescript-eslint/naming-convention
const { _camera, _vector } = this;
_camera.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse);
// center / target
setPoint('c', pointMap, geometry, _camera, 0, 0, -1, _vector);
setPoint('t', pointMap, geometry, _camera, 0, 0, 1, _vector);
// near
setPoint('n1', pointMap, geometry, _camera, -w, -h, -1, _vector);
setPoint('n2', pointMap, geometry, _camera, w, -h, -1, _vector);
setPoint('n3', pointMap, geometry, _camera, -w, h, -1, _vector);
setPoint('n4', pointMap, geometry, _camera, w, h, -1, _vector);
// far
setPoint('f1', pointMap, geometry, _camera, -w, -h, 1, _vector);
setPoint('f2', pointMap, geometry, _camera, w, -h, 1, _vector);
setPoint('f3', pointMap, geometry, _camera, -w, h, 1, _vector);
setPoint('f4', pointMap, geometry, _camera, w, h, 1, _vector);
// up
setPoint('u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, -1, _vector);
setPoint('u2', pointMap, geometry, _camera, -w * 0.7, h * 1.1, -1, _vector);
setPoint('u3', pointMap, geometry, _camera, 0, h * 2, -1, _vector);
// cross
setPoint('cf1', pointMap, geometry, _camera, -w, 0, 1, _vector);
setPoint('cf2', pointMap, geometry, _camera, w, 0, 1, _vector);
setPoint('cf3', pointMap, geometry, _camera, 0, -h, 1, _vector);
setPoint('cf4', pointMap, geometry, _camera, 0, h, 1, _vector);
setPoint('cn1', pointMap, geometry, _camera, -w, 0, -1, _vector);
setPoint('cn2', pointMap, geometry, _camera, w, 0, -1, _vector);
setPoint('cn3', pointMap, geometry, _camera, 0, -h, -1, _vector);
setPoint('cn4', pointMap, geometry, _camera, 0, h, -1, _vector);
geometry.getAttribute('instanceStart').needsUpdate = true;
geometry.getAttribute('instanceEnd').needsUpdate = true;
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
super.update();
}
dispose() {
this.line.geometry.dispose();
this.line.material.dispose();
super.dispose();
}
static Check(camera) {
return camera.isCamera;
}
static Create(camera) {
return new CameraHelper2(camera);
}
}
function setPoint(point, pointMap, geometry, camera, x, y, z, _vector) {
_vector.set(x, y, z).unproject(camera);
const points = pointMap[point];
if (points !== undefined) {
const position1 = geometry.getAttribute('instanceStart');
const position2 = geometry.getAttribute('instanceEnd');
for (let i = 0, l = points.length; i < l; i++) {
const j = Math.floor(points[i] / 2.);
(points[i] % 2 === 0 ? position1 : position2).setXYZ(j, _vector.x, _vector.y, _vector.z);
// (i % 2 === 0 ? position1 : position2).setXYZ(points[ i ], _vector.x, _vector.y, _vector.z)
}
}
}
function generateVertices() {
const vertices = [];
const colors = [];
const pointMap = {};
// near
addLine('n1', 'n2');
addLine('n2', 'n4');
addLine('n4', 'n3');
addLine('n3', 'n1');
// far
addLine('f1', 'f2');
addLine('f2', 'f4');
addLine('f4', 'f3');
addLine('f3', 'f1');
// sides
addLine('n1', 'f1');
addLine('n2', 'f2');
addLine('n3', 'f3');
addLine('n4', 'f4');
// cone
addLine('p', 'n1');
addLine('p', 'n2');
addLine('p', 'n3');
addLine('p', 'n4');
// up
addLine('u1', 'u2');
addLine('u2', 'u3');
addLine('u3', 'u1');
// target
addLine('c', 't');
addLine('p', 'c');
// cross
addLine('cn1', 'cn2');
addLine('cn3', 'cn4');
addLine('cf1', 'cf2');
addLine('cf3', 'cf4');
function addLine(a, b) {
addPoint(a);
addPoint(b);
}
function addPoint(id) {
vertices.push(0, 0, 0);
colors.push(0, 0, 0);
if (pointMap[id] === undefined) {
pointMap[id] = [];
}
pointMap[id].push(vertices.length / 3 - 1);
}
return { vertices, colors, pointMap };
}
//# sourceMappingURL=CameraHelper2.js.map