|
@@ -12,23 +12,24 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
|
import Scene from 'mol-gl/scene';
|
|
|
import { WebGLContext } from 'mol-gl/webgl/context';
|
|
|
import { Sphere3D } from 'mol-math/geometry';
|
|
|
+import { Vec3, Mat4 } from 'mol-math/linear-algebra';
|
|
|
|
|
|
export const DebugHelperParams = {
|
|
|
sceneBoundingSpheres: PD.Boolean(false, { description: 'Show scene bounding spheres.' }),
|
|
|
objectBoundingSpheres: PD.Boolean(false, { description: 'Show bounding spheres of render objects.' }),
|
|
|
+ instanceBoundingSpheres: PD.Boolean(false, { description: 'Show bounding spheres of instances.' }),
|
|
|
}
|
|
|
export type DebugHelperParams = typeof DebugHelperParams
|
|
|
export type DebugHelperProps = PD.Values<DebugHelperParams>
|
|
|
|
|
|
type BoundingSphereData = { boundingSphere: Sphere3D, renderObject: RenderObject }
|
|
|
|
|
|
-// TODO per-object-transform bounding spheres
|
|
|
-
|
|
|
export class BoundingSphereHelper {
|
|
|
readonly scene: Scene
|
|
|
private readonly parent: Scene
|
|
|
private _props: DebugHelperProps
|
|
|
private objectsData = new Map<RenderObject, BoundingSphereData>()
|
|
|
+ private instancesData = new Map<RenderObject, BoundingSphereData>()
|
|
|
private sceneData: BoundingSphereData | undefined
|
|
|
|
|
|
constructor(ctx: WebGLContext, parent: Scene, props: Partial<DebugHelperProps>) {
|
|
@@ -43,9 +44,16 @@ export class BoundingSphereHelper {
|
|
|
|
|
|
const oldRO = new Set<RenderObject>()
|
|
|
this.parent.forEach((r, ro) => {
|
|
|
- let objectData = this.objectsData.get(ro)
|
|
|
+ const objectData = this.objectsData.get(ro)
|
|
|
const newObjectData = updateBoundingSphereData(this.scene, r.boundingSphere, objectData)
|
|
|
if (newObjectData) this.objectsData.set(ro, newObjectData)
|
|
|
+
|
|
|
+ if (ro.type === 'mesh' || ro.type === 'lines' || ro.type === 'points') {
|
|
|
+ const instanceData = this.instancesData.get(ro)
|
|
|
+ const newInstanceData = updateBoundingSphereData(this.scene, ro.values.invariantBoundingSphere.ref.value, instanceData, ro.values.aTransform.ref.value, ro.values.instanceCount.ref.value)
|
|
|
+ if (newInstanceData) this.instancesData.set(ro, newInstanceData)
|
|
|
+ }
|
|
|
+
|
|
|
oldRO.delete(ro)
|
|
|
})
|
|
|
oldRO.forEach(ro => {
|
|
@@ -65,7 +73,9 @@ export class BoundingSphereHelper {
|
|
|
this.parent.forEach((_, ro) => {
|
|
|
const objectData = this.objectsData.get(ro)
|
|
|
if (objectData) objectData.renderObject.state.visible = ro.state.visible && this._props.objectBoundingSpheres
|
|
|
- else console.error('expected to have debug render object')
|
|
|
+
|
|
|
+ const instanceData = this.instancesData.get(ro)
|
|
|
+ if (instanceData) instanceData.renderObject.state.visible = ro.state.visible && this._props.instanceBoundingSpheres
|
|
|
})
|
|
|
}
|
|
|
|
|
@@ -76,7 +86,7 @@ export class BoundingSphereHelper {
|
|
|
}
|
|
|
|
|
|
get isEnabled() {
|
|
|
- return this._props.sceneBoundingSpheres || this._props.objectBoundingSpheres
|
|
|
+ return this._props.sceneBoundingSpheres || this._props.objectBoundingSpheres || this._props.instanceBoundingSpheres
|
|
|
}
|
|
|
get props() { return this._props as Readonly<DebugHelperProps> }
|
|
|
|
|
@@ -86,21 +96,28 @@ export class BoundingSphereHelper {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data?: BoundingSphereData) {
|
|
|
+function updateBoundingSphereData(scene: Scene, boundingSphere: Sphere3D, data: BoundingSphereData | undefined, transform?: Float32Array, transformCount?: number) {
|
|
|
if (!data || !Sphere3D.exactEquals(data.boundingSphere, boundingSphere)) {
|
|
|
if (data) scene.remove(data.renderObject)
|
|
|
- const renderObject = createBoundingSphereRenderObject(boundingSphere)
|
|
|
+ const renderObject = createBoundingSphereRenderObject(boundingSphere, transform, transformCount)
|
|
|
scene.add(renderObject)
|
|
|
return { boundingSphere, renderObject }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function createBoundingSphereRenderObject(boundingSphere: Sphere3D) {
|
|
|
+const tmpCenter = Vec3.zero()
|
|
|
+const tmpM = Mat4.identity()
|
|
|
+function createBoundingSphereRenderObject(boundingSphere: Sphere3D, transform?: Float32Array, transformCount?: number) {
|
|
|
const builderState = MeshBuilder.createState(1024, 512)
|
|
|
- if (boundingSphere.radius) {
|
|
|
- addSphere(builderState, boundingSphere.center, boundingSphere.radius, 2)
|
|
|
- } else if (isNaN(boundingSphere.radius)) {
|
|
|
- console.warn('boundingSphere.radius is NaN')
|
|
|
+ if (transform && transformCount) {
|
|
|
+ // TODO create instanced mesh?
|
|
|
+ for (let i = 0, _i = transformCount; i < _i; ++i) {
|
|
|
+ Mat4.fromArray(tmpM, transform, i * 16)
|
|
|
+ Vec3.transformMat4(tmpCenter, boundingSphere.center, tmpM)
|
|
|
+ if (boundingSphere.radius) addSphere(builderState, tmpCenter, boundingSphere.radius, 1)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (boundingSphere.radius) addSphere(builderState, boundingSphere.center, boundingSphere.radius, 2)
|
|
|
}
|
|
|
const mesh = MeshBuilder.getMesh(builderState)
|
|
|
const values = Mesh.createValuesSimple(mesh, { alpha: 0.1, doubleSided: false })
|