123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { WebGLContext } from '../../mol-gl/webgl/context';
- import { RenderTarget } from '../../mol-gl/webgl/render-target';
- import Renderer from '../../mol-gl/renderer';
- import Scene from '../../mol-gl/scene';
- import { PickingId } from '../../mol-geo/geometry/picking';
- import { decodeFloatRGB } from '../../mol-util/float-packing';
- import { Camera } from '../camera';
- import { HandleHelper } from '../helper/handle-helper';
- const NullId = Math.pow(2, 24) - 2;
- 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
- constructor(private webgl: WebGLContext, private renderer: Renderer, private scene: Scene, private camera: Camera, private handleHelper: HandleHelper, private pickBaseScale: number) {
- const { gl } = webgl;
- const width = gl.drawingBufferWidth;
- const height = gl.drawingBufferHeight;
- this.pickScale = pickBaseScale / webgl.pixelRatio;
- this.pickWidth = Math.round(width * this.pickScale);
- this.pickHeight = Math.round(height * this.pickScale);
- this.objectPickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
- this.instancePickTarget = webgl.createRenderTarget(this.pickWidth, this.pickHeight);
- this.groupPickTarget = webgl.createRenderTarget(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() {
- const { renderer, scene, camera, handleHelper: { scene: handleScene } } = this;
- renderer.setViewport(0, 0, this.pickWidth, this.pickHeight);
- this.objectPickTarget.bind();
- renderer.render(scene, camera, 'pickObject', true, false);
- renderer.render(handleScene, camera, 'pickObject', false, false);
- this.instancePickTarget.bind();
- renderer.render(scene, camera, 'pickInstance', true, false);
- renderer.render(handleScene, camera, 'pickInstance', false, false);
- this.groupPickTarget.bind();
- renderer.render(scene, camera, 'pickGroup', true, false);
- renderer.render(handleScene, camera, 'pickGroup', false, false);
- 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;
- if (webgl.isContextLost) return;
- const { gl } = webgl;
- if (this.pickDirty) {
- this.render();
- this.syncBuffers();
- }
- x *= webgl.pixelRatio;
- y *= webgl.pixelRatio;
- y = gl.drawingBufferHeight - y; // flip y
- const xp = Math.round(x * pickScale);
- const yp = Math.round(y * pickScale);
- const objectId = this.getId(xp, yp, this.objectBuffer);
- if (objectId === -1 || objectId === NullId) return;
- const instanceId = this.getId(xp, yp, this.instanceBuffer);
- if (instanceId === -1 || instanceId === NullId) return;
- const groupId = this.getId(xp, yp, this.groupBuffer);
- if (groupId === -1 || groupId === NullId) return;
- return { objectId, instanceId, groupId };
- }
- }
|