Skip to content

Commit 584b132

Browse files
committed
Examples: Add DepthTextureUtils
1 parent 3e39fcc commit 584b132

File tree

7 files changed

+448
-2
lines changed

7 files changed

+448
-2
lines changed

examples/files.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@
219219
"webgl_postprocessing_afterimage",
220220
"webgl_postprocessing_backgrounds",
221221
"webgl_postprocessing_transition",
222+
"webgl_postprocessing_interactive_displacement",
222223
"webgl_postprocessing_dof",
223224
"webgl_postprocessing_dof2",
224225
"webgl_postprocessing_fxaa",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {
2+
WebGLRenderTarget,
3+
FloatType
4+
} from 'three';
5+
6+
import { SavePass } from 'three/addons/postprocessing/SavePass.js';
7+
8+
9+
/**
10+
* A pass that saves the depth contents of the current read buffer in a render target.
11+
*
12+
* ```js
13+
* const depthSavePass = new DepthSavePass( customRenderTarget );
14+
* composer.addPass( depthSavePass );
15+
* ```
16+
*
17+
* @augments SavePass
18+
* @three_import import { SavePass } from 'three/addons/postprocessing/SavePass.js';
19+
*/
20+
21+
class DepthSavePass extends SavePass {
22+
23+
constructor( renderTarget ) {
24+
25+
if ( renderTarget === undefined ) {
26+
27+
renderTarget = new WebGLRenderTarget( 1, 1, { type: FloatType } ); // will be resized later
28+
renderTarget.texture.name = 'DepthSavePass.rt';
29+
30+
}
31+
32+
super( renderTarget );
33+
34+
}
35+
36+
/**
37+
* Performs the depth save pass.
38+
*
39+
* @param {WebGLRenderer} renderer - The renderer.
40+
* @param {WebGLRenderTarget} writeBuffer - The write buffer. This buffer is intended as the rendering
41+
* destination for the pass.
42+
* @param {WebGLRenderTarget} readBuffer - The read buffer. The pass can access the result from the
43+
* previous pass from this buffer.
44+
* @param {number} deltaTime - The delta time in seconds.
45+
* @param {boolean} maskActive - Whether masking is active or not.
46+
*/
47+
48+
render( renderer, writeBuffer, readBuffer, /* deltaTime , maskActive */ ) {
49+
50+
this.uniforms[ 'tDiffuse' ].value = readBuffer.depthTexture;
51+
52+
renderer.setRenderTarget( this.renderTarget );
53+
if ( this.clear ) renderer.clear();
54+
this._fsQuad.render( renderer );
55+
56+
}
57+
58+
}
59+
60+
export { DepthSavePass };
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { Vector2, Vector3 } from 'three';
2+
3+
const NDC = new Vector3();
4+
const cursorNDC = new Vector2();
5+
const z_Axis = new Vector3( 0, 0, - 1 );
6+
/**
7+
* Converts depth to view position.
8+
* @param {Vector2} cursorNDC - Normalized device coordinates of the cursor.
9+
* @param {number} depth - Depth value.
10+
* @param {Camera} camera - Camera object.
11+
* @returns {Vector3} - View position.
12+
*/
13+
function depthToViewPosition( cursorNDC, depth, camera ) {
14+
15+
// depth to Z NDC
16+
const zNDC = 2.0 * depth - 1.0;
17+
18+
NDC.set( cursorNDC.x, cursorNDC.y, zNDC );
19+
20+
const viewPosition = NDC.applyMatrix4( camera.projectionMatrixInverse );
21+
22+
return viewPosition;
23+
24+
}
25+
26+
/**
27+
* Converts logarithmic depth to view position.
28+
* @param {Vector2} cursorNDC - Normalized device coordinates of the cursor.
29+
* @param {number} logDepth - Logarithmic depth value.
30+
* @param {Camera} camera - Camera object.
31+
* @returns {Vector3} - View position.
32+
*/
33+
function logDepthToViewPosition( cursorNDC, logDepth, camera ) {
34+
35+
const w = ( camera.far + 1.0 ) ** logDepth - 1;
36+
37+
NDC.set( cursorNDC.x, cursorNDC.y, - 1 );
38+
const viewPosition = NDC.applyMatrix4( camera.projectionMatrixInverse );
39+
40+
const angle = viewPosition.angleTo( z_Axis );
41+
viewPosition.setLength( w / Math.cos( angle ) );
42+
43+
return viewPosition;
44+
45+
}
46+
47+
const buffer = new Float32Array( 4 );
48+
49+
/**
50+
* Computes the 3D world position corresponding to a given 2D mouse position on the screen,
51+
* using depth information from a render target.
52+
*
53+
* @param {Object} mouse - The mouse position in screen coordinates.
54+
* @param {number} mouse.x - The x-coordinate of the mouse on the screen.
55+
* @param {number} mouse.y - The y-coordinate of the mouse on the screen.
56+
* @param {THREE.WebGLRenderer} renderer - The WebGL renderer used to access the render target and canvas size.
57+
* @param {THREE.WebGLRenderTarget} renderTarget - The render target that contains depth data.
58+
* @param {THREE.Camera} camera - The camera used for the scene. Supports both perspective and orthographic cameras.
59+
* @param {THREE.Vector3} target - A pre-allocated Vector3 to store the resulting world position.
60+
* @returns {THREE.Vector3} The computed world position corresponding to the mouse input.
61+
*
62+
* This function:
63+
* 1. Converts the mouse position from screen space to canvas space.
64+
* 2. Reads the depth value from the render target at that position.
65+
* 3. Converts the position from normalized device coordinates (NDC) and depth into view space.
66+
* 4. Transforms the result into world space using the camera's world matrix.
67+
*
68+
* It supports both regular and logarithmic depth buffers.
69+
*/
70+
71+
const pickWorldPosition = ( mouse, renderer, renderTarget, camera, target ) => {
72+
73+
const canvasRect = renderer.domElement.getBoundingClientRect();
74+
75+
const left = mouse.x - canvasRect.left;
76+
const bottom = canvasRect.bottom - mouse.y;
77+
78+
renderer.readRenderTargetPixels( renderTarget, left, bottom, 1, 1, buffer );
79+
80+
const depth = buffer[ 0 ];
81+
82+
cursorNDC.setX( ( left / canvasRect.width ) * 2 - 1 );
83+
cursorNDC.setY( ( bottom / canvasRect.height ) * 2 - 1 );
84+
85+
if ( renderer.capabilities.logarithmicDepthBuffer && camera.isPerspectiveCamera ) {
86+
87+
target.copy( logDepthToViewPosition( cursorNDC, depth, camera ) );
88+
89+
} else {
90+
91+
target.copy( depthToViewPosition( cursorNDC, depth, camera ) );
92+
93+
}
94+
95+
target.applyMatrix4( camera.matrixWorld );
96+
97+
return target;
98+
99+
};
100+
101+
export { pickWorldPosition };
Loading
Loading

0 commit comments

Comments
 (0)