|
@@ -11,14 +11,17 @@ import Scene from '../../mol-gl/scene';
|
|
|
import { PickingId } from '../../mol-geo/geometry/picking';
|
|
|
import { decodeFloatRGB } from '../../mol-util/float-packing';
|
|
|
|
|
|
-const readBuffer = new Uint8Array(4)
|
|
|
-
|
|
|
export class PickPass {
|
|
|
pickDirty = true
|
|
|
+
|
|
|
objectPickTarget: RenderTarget
|
|
|
instancePickTarget: RenderTarget
|
|
|
groupPickTarget: RenderTarget
|
|
|
|
|
|
+ private objectBuffer: Uint8Array
|
|
|
+ private instanceBuffer: Uint8Array
|
|
|
+ private groupBuffer: Uint8Array
|
|
|
+
|
|
|
private pickScale: number
|
|
|
private pickWidth: number
|
|
|
private pickHeight: number
|
|
@@ -31,18 +34,33 @@ export class PickPass {
|
|
|
this.pickScale = pickBaseScale / webgl.pixelRatio
|
|
|
this.pickWidth = Math.round(width * this.pickScale)
|
|
|
this.pickHeight = Math.round(height * this.pickScale)
|
|
|
+
|
|
|
this.objectPickTarget = createRenderTarget(webgl, this.pickWidth, this.pickHeight)
|
|
|
this.instancePickTarget = createRenderTarget(webgl, this.pickWidth, this.pickHeight)
|
|
|
this.groupPickTarget = createRenderTarget(webgl, this.pickWidth, this.pickHeight)
|
|
|
+
|
|
|
+ this.setupBuffers()
|
|
|
+ }
|
|
|
+
|
|
|
+ private setupBuffers() {
|
|
|
+ const bufferSize = this.pickWidth * this.pickHeight * 4
|
|
|
+ if (!this.objectBuffer || this.objectBuffer.length !== bufferSize) {
|
|
|
+ this.objectBuffer = new Uint8Array(bufferSize)
|
|
|
+ this.instanceBuffer = new Uint8Array(bufferSize)
|
|
|
+ this.groupBuffer = new Uint8Array(bufferSize)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
setSize(width: number, height: number) {
|
|
|
this.pickScale = this.pickBaseScale / this.webgl.pixelRatio
|
|
|
this.pickWidth = Math.round(width * this.pickScale)
|
|
|
this.pickHeight = Math.round(height * this.pickScale)
|
|
|
+
|
|
|
this.objectPickTarget.setSize(this.pickWidth, this.pickHeight)
|
|
|
this.instancePickTarget.setSize(this.pickWidth, this.pickHeight)
|
|
|
this.groupPickTarget.setSize(this.pickWidth, this.pickHeight)
|
|
|
+
|
|
|
+ this.setupBuffers()
|
|
|
}
|
|
|
|
|
|
render() {
|
|
@@ -54,12 +72,35 @@ export class PickPass {
|
|
|
renderer.render(scene, 'pickInstance', true);
|
|
|
this.groupPickTarget.bind();
|
|
|
renderer.render(scene, 'pickGroup', true);
|
|
|
+
|
|
|
+ this.pickDirty = false
|
|
|
+ }
|
|
|
+
|
|
|
+ private syncBuffers() {
|
|
|
+ const { webgl } = this
|
|
|
+
|
|
|
+ this.objectPickTarget.bind()
|
|
|
+ webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.objectBuffer)
|
|
|
+
|
|
|
+ this.instancePickTarget.bind()
|
|
|
+ webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.instanceBuffer)
|
|
|
+
|
|
|
+ this.groupPickTarget.bind()
|
|
|
+ webgl.readPixels(0, 0, this.pickWidth, this.pickHeight, this.groupBuffer)
|
|
|
+ }
|
|
|
+
|
|
|
+ private getId(x: number, y: number, buffer: Uint8Array) {
|
|
|
+ const idx = (y * this.pickWidth + x) * 4
|
|
|
+ return decodeFloatRGB(buffer[idx], buffer[idx + 1], buffer[idx + 2])
|
|
|
}
|
|
|
|
|
|
identify(x: number, y: number): PickingId | undefined {
|
|
|
const { webgl, pickScale } = this
|
|
|
const { gl } = webgl
|
|
|
- if (this.pickDirty) this.render()
|
|
|
+ if (this.pickDirty) {
|
|
|
+ this.render()
|
|
|
+ this.syncBuffers()
|
|
|
+ }
|
|
|
|
|
|
x *= webgl.pixelRatio
|
|
|
y *= webgl.pixelRatio
|
|
@@ -68,19 +109,13 @@ export class PickPass {
|
|
|
const xp = Math.round(x * pickScale)
|
|
|
const yp = Math.round(y * pickScale)
|
|
|
|
|
|
- this.objectPickTarget.bind()
|
|
|
- webgl.readPixels(xp, yp, 1, 1, readBuffer)
|
|
|
- const objectId = decodeFloatRGB(readBuffer[0], readBuffer[1], readBuffer[2])
|
|
|
+ const objectId = this.getId(xp, yp, this.objectBuffer)
|
|
|
if (objectId === -1) return
|
|
|
|
|
|
- this.instancePickTarget.bind()
|
|
|
- webgl.readPixels(xp, yp, 1, 1, readBuffer)
|
|
|
- const instanceId = decodeFloatRGB(readBuffer[0], readBuffer[1], readBuffer[2])
|
|
|
+ const instanceId = this.getId(xp, yp, this.instanceBuffer)
|
|
|
if (instanceId === -1) return
|
|
|
|
|
|
- this.groupPickTarget.bind()
|
|
|
- webgl.readPixels(xp, yp, 1, 1, readBuffer)
|
|
|
- const groupId = decodeFloatRGB(readBuffer[0], readBuffer[1], readBuffer[2])
|
|
|
+ const groupId = this.getId(xp, yp, this.groupBuffer)
|
|
|
if (groupId === -1) return
|
|
|
|
|
|
return { objectId, instanceId, groupId }
|