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.
120 lines (87 loc) • 3.39 kB
text/typescript
import {ColorRepresentation, Object3D, SpotLight, Vector3} from 'three'
import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js'
import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js'
import {onChange} from 'ts-browser-helpers'
import {ALightHelperWidget} from './ALightHelperWidget'
import {IUiConfigContainer, uiSlider} from 'uiconfig.js'
import {LineMaterial2} from '../../core'
export class SpotLightHelper2 extends ALightHelperWidget {
color: ColorRepresentation | undefined
cone: LineSegments2
declare light: (SpotLight & IUiConfigContainer) | undefined
hMaterial: LineMaterial2
lineWidth = 5
constructor(light: SpotLight, size?: number, color?: ColorRepresentation) {
super(light)
this.color = color
if (size === undefined) size = 0.5
const geometry = new LineSegmentsGeometry()
const positions = [
0, 0, 0, 0, 0, 1,
0, 0, 0, 1, 0, 1,
0, 0, 0, -1, 0, 1,
0, 0, 0, 0, 1, 1,
0, 0, 0, 0, -1, 1,
]
for (let i = 0, j = 1, l = 32; i < l; i++, j++) {
const p1 = i / l * Math.PI * 2
const p2 = j / l * Math.PI * 2
positions.push(
Math.cos(p1), Math.sin(p1), 1,
Math.cos(p2), Math.sin(p2), 1
)
}
geometry.setPositions(positions)
this.hMaterial = new LineMaterial2({
color: 0xff0000,
linewidth: 3, // in world units with size attenuation, pixels otherwise
vertexColors: false,
worldUnits: false,
dashed: false,
alphaToCoverage: true,
toneMapped: false,
transparent: true,
depthTest: true,
depthWrite: false,
allowOverride: false,
})
this.hMaterial.userData.renderToGBuffer = false
this.hMaterial.userData.renderToDepth = false
this.cone = new LineSegments2(geometry, this.hMaterial)
this.add(this.cone)
this.update()
this.traverse(o => {
o.userData.__keepShadowDef = true
o.castShadow = false
o.receiveShadow = false
})
}
dispose() {
this.cone.geometry.dispose()
this.cone.material.dispose()
super.dispose()
}
private _v1 = new Vector3()
update() {
if (!this.light || !this.cone) return
this.light.updateWorldMatrix(true, false)
this.light.target.updateWorldMatrix(true, false)
const coneLength = this.light.distance ? this.light.distance : 1000
const coneWidth = coneLength * Math.tan(this.light.angle)
this.cone.scale.set(coneWidth, coneWidth, coneLength)
this._v1.setFromMatrixPosition(this.light.target.matrixWorld)
this.cone.lookAt(this._v1)
this.hMaterial.color.set(this.color ?? this.light.color)
this.hMaterial.linewidth = this.lineWidth
super.update()
}
static Check(light: Object3D) {
return (light as SpotLight).isSpotLight
}
static Create(light: Object3D) {
return new SpotLightHelper2(light as SpotLight)
}
}