UNPKG

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.

129 lines (101 loc) 4.28 kB
import {Bone, Color, ColorRepresentation, Matrix4, Object3D, Vector3} from 'three' import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' import {onChange2} from 'ts-browser-helpers' import {AHelperWidget} from './AHelperWidget' import {IUiConfigContainer, uiColor, uiSlider, uiToggle} from 'uiconfig.js' import {LineMaterial2} from '../../core' export class BoneHelper extends AHelperWidget { lineSegments: LineSegments2 declare object: (Bone & IUiConfigContainer) | undefined private _vector = new Vector3() private _boneMatrix = new Matrix4() private _matrixWorldInv = new Matrix4() @onChange2(BoneHelper.prototype.update) hMaterial: LineMaterial2 @onChange2(BoneHelper.prototype.update) @uiSlider(undefined, [0.1, 20], 0.01) lineWidth = 5 @onChange2(BoneHelper.prototype.update) @uiColor() color1: Color = new Color(0, 0, 1) @onChange2(BoneHelper.prototype.update) @uiColor() color2: Color = new Color(0, 1, 0) @uiToggle() @onChange2(BoneHelper.prototype.update) autoUpdate = true // todo this shoudn't be needed, always update on before render constructor(bone: Bone, color1?: ColorRepresentation, color2?: ColorRepresentation) { super(bone) if (color1) this.color1.set(color1) if (color2) this.color2.set(color2) // Create geometry and hMaterial const geometry = new LineSegmentsGeometry() this.hMaterial = new LineMaterial2({ vertexColors: true, linewidth: this.lineWidth, worldUnits: false, dashed: false, alphaToCoverage: true, toneMapped: false, transparent: true, depthTest: true, depthWrite: false, }) this.hMaterial.userData.renderToGBuffer = false this.hMaterial.userData.renderToDepth = false this.lineSegments = new LineSegments2(geometry, this.hMaterial) this.lineSegments.frustumCulled = false this.add(this.lineSegments) this.matrix = bone.matrixWorld this.matrixAutoUpdate = false this.update() } updateMatrixWorld(force?: boolean) { if (this.object) this.autoUpdate && this.update(false) super.updateMatrixWorld(force) } update(setDirty = true) { if (!this.lineSegments || !this.object) return const bone = this.object as Bone // Update hMaterial properties this.hMaterial.linewidth = this.lineWidth const vertices: number[] = [] const colors: number[] = [] this._matrixWorldInv.copy(bone.matrixWorld).invert() // Only render line if bone has a parent bone if (bone.parent && (bone.parent as any).isBone) { // Parent position this._boneMatrix.multiplyMatrices(this._matrixWorldInv, bone.parent.matrixWorld) this._vector.setFromMatrixPosition(this._boneMatrix) vertices.push(this._vector.x, this._vector.y, this._vector.z) colors.push(this.color1.r, this.color1.g, this.color1.b) // Current bone position this._boneMatrix.multiplyMatrices(this._matrixWorldInv, bone.matrixWorld) this._vector.setFromMatrixPosition(this._boneMatrix) vertices.push(this._vector.x, this._vector.y, this._vector.z) colors.push(this.color2.r, this.color2.g, this.color2.b) } const geometry = this.lineSegments.geometry if (vertices.length > 0) { geometry.setPositions(vertices) geometry.setColors(colors) } else { // Clear geometry properly when no line to show geometry.setPositions([0, 0, 0, 0, 0, 0]) geometry.setColors([0, 0, 0, 0, 0, 0]) } super.update(setDirty) } dispose() { this.lineSegments.geometry.dispose() this.lineSegments.material.dispose() super.dispose() } static Check(object: Object3D): boolean { return (object as any).isBone } static Create(bone: Bone): BoneHelper { return new BoneHelper(bone) } }