From 16b0ec7ba8174ed13bbfe8bcb93c1cee9efd2eed Mon Sep 17 00:00:00 2001 From: tengge1 <930372551@qq.com> Date: Fri, 22 Nov 2019 22:21:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8GPU=E5=8F=8D=E7=AE=97?= =?UTF-8?q?=E4=B8=96=E7=95=8C=E5=9D=90=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/controls/ControlsManager.js | 0 .../src/event/GPUPickEvent copy.js | 86 ------------------- ShadowEditor.Web/src/event/GPUPickEvent.js | 37 +++++++- .../src/event/shader/depth_fragment.glsl | 6 +- .../src/event/shader/depth_vertex.glsl | 6 +- 5 files changed, 43 insertions(+), 92 deletions(-) create mode 100644 ShadowEditor.Web/src/controls/ControlsManager.js delete mode 100644 ShadowEditor.Web/src/event/GPUPickEvent copy.js diff --git a/ShadowEditor.Web/src/controls/ControlsManager.js b/ShadowEditor.Web/src/controls/ControlsManager.js new file mode 100644 index 00000000..e69de29b diff --git a/ShadowEditor.Web/src/event/GPUPickEvent copy.js b/ShadowEditor.Web/src/event/GPUPickEvent copy.js deleted file mode 100644 index 9e51f1b4..00000000 --- a/ShadowEditor.Web/src/event/GPUPickEvent copy.js +++ /dev/null @@ -1,86 +0,0 @@ -import BaseEvent from './BaseEvent'; -import DepthVertexShader from './shader/depth_vertex.glsl'; -import DepthFragmentShader from './shader/depth_fragment.glsl'; - -/** - * 使用GPU进行碰撞 - * @author tengge / https://github.com/tengge1 - * @param {*} app 应用程序 - */ -function GPUPickEvent(app) { - BaseEvent.call(this, app); - - this.offsetX = 0; - this.offsetY = 0; - - this.onMouseMove = this.onMouseMove.bind(this); - this.onAfterRender = this.onAfterRender.bind(this); -} - -GPUPickEvent.prototype = Object.create(BaseEvent.prototype); -GPUPickEvent.prototype.constructor = GPUPickEvent; - -GPUPickEvent.prototype.start = function () { - app.on(`mousemove.${this.id}`, this.onMouseMove); - app.on(`afterRender.${this.id}`, this.onAfterRender); -}; - -GPUPickEvent.prototype.stop = function () { - app.on(`mousemove.${this.id}`, null); - app.on(`afterRender.${this.id}`, null); -}; - -GPUPickEvent.prototype.onMouseMove = function (event) { - if (event.target !== app.editor.renderer.domElement) { - return; - } - this.offsetX = event.offsetX; - this.offsetY = event.offsetY; -}; - -GPUPickEvent.prototype.onAfterRender = function () { - let world = new THREE.Vector3(); - return function () { - let { scene, camera, renderer } = app.editor; - const { width, height } = renderer.domElement; - - if (this.init === undefined) { - this.init = true; - this.material = new THREE.ShaderMaterial({ - vertexShader: DepthVertexShader, - fragmentShader: DepthFragmentShader - }); - this.renderTarget = new THREE.WebGLRenderTarget(width, height); - this.pixel = new Uint8Array(4); - } - - // 记录旧属性 - const oldOverrideMaterial = scene.overrideMaterial; - const oldRenderTarget = renderer.getRenderTarget(); - - // 更换深度材质 - scene.overrideMaterial = this.material; - renderer.setRenderTarget(this.renderTarget); - renderer.clear(); - - // 读取深度 - this.pixel.set([0, 0, 0, 0]); - renderer.render(scene, camera); - renderer.readRenderTargetPixels(this.renderTarget, this.offsetX, height - this.offsetY, 1, 1, this.pixel); - - let depth = (this.pixel[0] * 65535 + this.pixel[1] * 255 + this.pixel[2]) / 16777215 * 80 - 1; - - world.set( - this.offsetX / width * 2 - 1, - - this.offsetY / height * 2 + 1, - depth - ); - world.unproject(camera); - - // 还原原来的属性 - scene.overrideMaterial = oldOverrideMaterial; - renderer.setRenderTarget(oldRenderTarget); - }; -}(); - -export default GPUPickEvent; \ No newline at end of file diff --git a/ShadowEditor.Web/src/event/GPUPickEvent.js b/ShadowEditor.Web/src/event/GPUPickEvent.js index 5cbd9a0b..d10e1f89 100644 --- a/ShadowEditor.Web/src/event/GPUPickEvent.js +++ b/ShadowEditor.Web/src/event/GPUPickEvent.js @@ -1,12 +1,14 @@ import BaseEvent from './BaseEvent'; import PickVertexShader from './shader/pick_vertex.glsl'; import PickFragmentShader from './shader/pick_fragment.glsl'; +import DepthVertexShader from './shader/depth_vertex.glsl'; +import DepthFragmentShader from './shader/depth_fragment.glsl'; import MeshUtils from '../utils/MeshUtils'; let maxHexColor = 1; /** - * 使用GPU进行碰撞 + * 使用GPU选取物体和计算鼠标世界坐标 * @author tengge / https://github.com/tengge1 */ function GPUPickEvent() { @@ -48,6 +50,9 @@ GPUPickEvent.prototype.onMouseMove = function (event) { this.offsetY = event.offsetY; }; +/** + * 由于需要较高性能,所以尽量不要拆分函数。 + */ GPUPickEvent.prototype.onAfterRender = function () { if (!this.isIn) { return; @@ -57,8 +62,13 @@ GPUPickEvent.prototype.onAfterRender = function () { if (this.init === undefined) { this.init = true; + this.depthMaterial = new THREE.ShaderMaterial({ + vertexShader: DepthVertexShader, + fragmentShader: DepthFragmentShader + }); this.renderTarget = new THREE.WebGLRenderTarget(width, height); this.pixel = new Uint8Array(4); + this.world = new THREE.Vector3(); } // 记录旧属性 @@ -66,6 +76,8 @@ GPUPickEvent.prototype.onAfterRender = function () { const oldOverrideMaterial = scene.overrideMaterial; const oldRenderTarget = renderer.getRenderTarget(); + // ---------------------------- 1. 使用GPU判断选中的物体 ----------------------------------- + scene.background = null; // 有背景图,可能导致提取的颜色不准 scene.overrideMaterial = null; renderer.setRenderTarget(this.renderTarget); @@ -129,6 +141,29 @@ GPUPickEvent.prototype.onAfterRender = function () { } } + // ------------------------- 2. 使用GPU反算世界坐标 ---------------------------------- + + scene.overrideMaterial = this.material; + + renderer.clear(); + renderer.render(scene, camera); + renderer.readRenderTargetPixels(this.renderTarget, this.offsetX, height - this.offsetY, 1, 1, this.pixel); + + let depth = (this.pixel[0] * 65535 + this.pixel[1] * 255 + this.pixel[2]) / 0xffffff; + + if (this.pixel[3] === 0) { + depth = -depth; + } + + this.world.set( + this.offsetX / width * 2 - 1, + - this.offsetY / height * 2 + 1, + depth + ); + this.world.unproject(camera); + + // console.log(`${this.pixel[0]}, ${this.pixel[1]}, ${this.pixel[2]}, ${depth}, ${this.world.x}, ${this.world.y}, ${this.world.z}`); + // 还原原来的属性 scene.background = oldBackground; scene.overrideMaterial = oldOverrideMaterial; diff --git a/ShadowEditor.Web/src/event/shader/depth_fragment.glsl b/ShadowEditor.Web/src/event/shader/depth_fragment.glsl index 74ed81bd..af2c9bfd 100644 --- a/ShadowEditor.Web/src/event/shader/depth_fragment.glsl +++ b/ShadowEditor.Web/src/event/shader/depth_fragment.glsl @@ -1,12 +1,14 @@ precision highp float; + varying float depth; void main() { - float hex = abs(depth) * 16777215.0; + float hex = abs(clamp(depth, -1.0, 1.0)) * 16777215.0; // 0xffffff float r = floor(hex / 65535.0); float g = floor((hex - r * 65535.0) / 255.0); float b = floor(hex - r * 65535.0 - g * 255.0); + float a = sign(depth) >= 0.0 ? 1.0 : 0.0; // depth大于等于0,为1.0;小于0,为0.0。 - gl_FragColor = vec4(r / 255.0, g / 255.0, b / 255.0, 1.0); + gl_FragColor = vec4(r / 255.0, g / 255.0, b / 255.0, a); } \ No newline at end of file diff --git a/ShadowEditor.Web/src/event/shader/depth_vertex.glsl b/ShadowEditor.Web/src/event/shader/depth_vertex.glsl index f45f9e14..fb6c04b0 100644 --- a/ShadowEditor.Web/src/event/shader/depth_vertex.glsl +++ b/ShadowEditor.Web/src/event/shader/depth_vertex.glsl @@ -1,8 +1,8 @@ precision highp float; + varying float depth; void main() { - vec4 transformed = modelViewMatrix * vec4(position, 1.0); - gl_Position = projectionMatrix * transformed; - depth = transformed.z; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + depth = gl_Position.z; } \ No newline at end of file