Buckets:
| import Node from '../core/Node.js'; | |
| import { float, log, log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js'; | |
| import { cameraNear, cameraFar } from '../accessors/Camera.js'; | |
| import { positionView } from '../accessors/Position.js'; | |
| import { viewportDepthTexture } from './ViewportDepthTextureNode.js'; | |
| /** | |
| * This node offers a collection of features in context of the depth logic in the fragment shader. | |
| * Depending on {@link ViewportDepthNode#scope}, it can be used to define a depth value for the current | |
| * fragment or for depth evaluation purposes. | |
| * | |
| * @augments Node | |
| */ | |
| class ViewportDepthNode extends Node { | |
| static get type() { | |
| return 'ViewportDepthNode'; | |
| } | |
| /** | |
| * Constructs a new viewport depth node. | |
| * | |
| * @param {('depth'|'depthBase'|'linearDepth')} scope - The node's scope. | |
| * @param {?Node} [valueNode=null] - The value node. | |
| */ | |
| constructor( scope, valueNode = null ) { | |
| super( 'float' ); | |
| /** | |
| * The node behaves differently depending on which scope is selected. | |
| * | |
| * - `ViewportDepthNode.DEPTH_BASE`: Allows to define a value for the current fragment's depth. | |
| * - `ViewportDepthNode.DEPTH`: Represents the depth value for the current fragment (`valueNode` is ignored). | |
| * - `ViewportDepthNode.LINEAR_DEPTH`: Represents the linear (orthographic) depth value of the current fragment. | |
| * If a `valueNode` is set, the scope can be used to convert perspective depth data to linear data. | |
| * | |
| * @type {('depth'|'depthBase'|'linearDepth')} | |
| */ | |
| this.scope = scope; | |
| /** | |
| * Can be used to define a custom depth value. | |
| * The property is ignored in the `ViewportDepthNode.DEPTH` scope. | |
| * | |
| * @type {?Node} | |
| * @default null | |
| */ | |
| this.valueNode = valueNode; | |
| /** | |
| * This flag can be used for type testing. | |
| * | |
| * @type {boolean} | |
| * @readonly | |
| * @default true | |
| */ | |
| this.isViewportDepthNode = true; | |
| } | |
| generate( builder ) { | |
| const { scope } = this; | |
| if ( scope === ViewportDepthNode.DEPTH_BASE ) { | |
| return builder.getFragDepth(); | |
| } | |
| return super.generate( builder ); | |
| } | |
| setup( { camera } ) { | |
| const { scope } = this; | |
| const value = this.valueNode; | |
| let node = null; | |
| if ( scope === ViewportDepthNode.DEPTH_BASE ) { | |
| if ( value !== null ) { | |
| node = depthBase().assign( value ); | |
| } | |
| } else if ( scope === ViewportDepthNode.DEPTH ) { | |
| if ( camera.isPerspectiveCamera ) { | |
| node = viewZToPerspectiveDepth( positionView.z, cameraNear, cameraFar ); | |
| } else { | |
| node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); | |
| } | |
| } else if ( scope === ViewportDepthNode.LINEAR_DEPTH ) { | |
| if ( value !== null ) { | |
| if ( camera.isPerspectiveCamera ) { | |
| const viewZ = perspectiveDepthToViewZ( value, cameraNear, cameraFar ); | |
| node = viewZToOrthographicDepth( viewZ, cameraNear, cameraFar ); | |
| } else { | |
| node = value; | |
| } | |
| } else { | |
| node = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar ); | |
| } | |
| } | |
| return node; | |
| } | |
| } | |
| ViewportDepthNode.DEPTH_BASE = 'depthBase'; | |
| ViewportDepthNode.DEPTH = 'depth'; | |
| ViewportDepthNode.LINEAR_DEPTH = 'linearDepth'; | |
| export default ViewportDepthNode; | |
| // NOTE: viewZ, the z-coordinate in camera space, is negative for points in front of the camera | |
| /** | |
| * TSL function for converting a viewZ value to an orthographic depth value. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} viewZ - The viewZ node. | |
| * @param {Node<float>} near - The camera's near value. | |
| * @param {Node<float>} far - The camera's far value. | |
| * @returns {Node<float>} | |
| */ | |
| export const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); | |
| /** | |
| * TSL function for converting an orthographic depth value to a viewZ value. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} depth - The orthographic depth. | |
| * @param {Node<float>} near - The camera's near value. | |
| * @param {Node<float>} far - The camera's far value. | |
| * @returns {Node<float>} | |
| */ | |
| export const orthographicDepthToViewZ = ( depth, near, far ) => near.sub( far ).mul( depth ).sub( near ); | |
| /** | |
| * TSL function for converting a viewZ value to a perspective depth value. | |
| * | |
| * Note: {link https://twitter.com/gonnavis/status/1377183786949959682}. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} viewZ - The viewZ node. | |
| * @param {Node<float>} near - The camera's near value. | |
| * @param {Node<float>} far - The camera's far value. | |
| * @returns {Node<float>} | |
| */ | |
| export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); | |
| /** | |
| * TSL function for converting a perspective depth value to a viewZ value. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} depth - The perspective depth. | |
| * @param {Node<float>} near - The camera's near value. | |
| * @param {Node<float>} far - The camera's far value. | |
| * @returns {Node<float>} | |
| */ | |
| export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); | |
| /** | |
| * TSL function for converting a viewZ value to a logarithmic depth value. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} viewZ - The viewZ node. | |
| * @param {Node<float>} near - The camera's near value. | |
| * @param {Node<float>} far - The camera's far value. | |
| * @returns {Node<float>} | |
| */ | |
| export const viewZToLogarithmicDepth = ( viewZ, near, far ) => { | |
| // NOTE: viewZ must be negative--see explanation at the end of this comment block. | |
| // The final logarithmic depth formula used here is adapted from one described in an | |
| // article by Thatcher Ulrich (see http://tulrich.com/geekstuff/log_depth_buffer.txt), | |
| // which was an improvement upon an earlier formula one described in an | |
| // Outerra article (https://outerra.blogspot.com/2009/08/logarithmic-z-buffer.html). | |
| // Ulrich's formula is the following: | |
| // z = K * log( w / cameraNear ) / log( cameraFar / cameraNear ) | |
| // where K = 2^k - 1, and k is the number of bits in the depth buffer. | |
| // The Outerra variant ignored the camera near plane (it assumed it was 0) and instead | |
| // opted for a "C-constant" for resolution adjustment of objects near the camera. | |
| // Outerra states: "Notice that the 'C' variant doesn’t use a near plane distance, it has it | |
| // set at 0" (quote from https://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html). | |
| // Ulrich's variant has the benefit of constant relative precision over the whole near-far range. | |
| // It was debated here whether Outerra's "C-constant" or Ulrich's "near plane" variant should | |
| // be used, and ultimately Ulrich's "near plane" version was chosen. | |
| // Outerra eventually made another improvement to their original "C-constant" variant, | |
| // but it still does not incorporate the camera near plane (for this version, | |
| // see https://outerra.blogspot.com/2013/07/logarithmic-depth-buffer-optimizations.html). | |
| // Here we make 4 changes to Ulrich's formula: | |
| // 1. Clamp the camera near plane so we don't divide by 0. | |
| // 2. Use log2 instead of log to avoid an extra multiply (shaders implement log using log2). | |
| // 3. Assume K is 1 (K = maximum value in depth buffer; see Ulrich's formula above). | |
| // 4. To maintain consistency with the functions "viewZToOrthographicDepth" and "viewZToPerspectiveDepth", | |
| // we modify the formula here to use 'viewZ' instead of 'w'. The other functions expect a negative viewZ, | |
| // so we do the same here, hence the 'viewZ.negate()' call. | |
| // For visual representation of this depth curve, see https://www.desmos.com/calculator/uyqk0vex1u | |
| near = near.max( 1e-6 ).toVar(); | |
| const numerator = log2( viewZ.negate().div( near ) ); | |
| const denominator = log2( far.div( near ) ); | |
| return numerator.div( denominator ); | |
| }; | |
| /** | |
| * TSL function for converting a logarithmic depth value to a viewZ value. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} depth - The logarithmic depth. | |
| * @param {Node<float>} near - The camera's near value. | |
| * @param {Node<float>} far - The camera's far value. | |
| * @returns {Node<float>} | |
| */ | |
| export const logarithmicDepthToViewZ = ( depth, near, far ) => { | |
| // NOTE: we add a 'negate()' call to the return value here to maintain consistency with | |
| // the functions "orthographicDepthToViewZ" and "perspectiveDepthToViewZ" (they return | |
| // a negative viewZ). | |
| const exponent = depth.mul( log( far.div( near ) ) ); | |
| return float( Math.E ).pow( exponent ).mul( near ).negate(); | |
| }; | |
| /** | |
| * TSL function for defining a value for the current fragment's depth. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {Node<float>} value - The depth value to set. | |
| * @returns {ViewportDepthNode<float>} | |
| */ | |
| const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); | |
| /** | |
| * TSL object that represents the depth value for the current fragment. | |
| * | |
| * @tsl | |
| * @type {ViewportDepthNode} | |
| */ | |
| export const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); | |
| /** | |
| * TSL function for converting a perspective depth value to linear depth. | |
| * | |
| * @tsl | |
| * @function | |
| * @param {?Node<float>} [value=null] - The perspective depth. If `null` is provided, the current fragment's depth is used. | |
| * @returns {ViewportDepthNode<float>} | |
| */ | |
| export const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ).setParameterLength( 0, 1 ); | |
| /** | |
| * TSL object that represents the linear (orthographic) depth value of the current fragment | |
| * | |
| * @tsl | |
| * @type {ViewportDepthNode} | |
| */ | |
| export const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); | |
| depth.assign = ( value ) => depthBase( value ); | |
Xet Storage Details
- Size:
- 9.58 kB
- Xet hash:
- 9e0db49167379ccb8a8c75437e25cd532978d058a2032e0c406db93ef11a1346
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.