|
|
@@ -7162,25 +7162,23 @@ class MathNode extends TempNode {
|
|
|
|
|
|
} else if ( method === MathNode.TRANSFORM_DIRECTION ) {
|
|
|
|
|
|
- // dir can be either a direction vector or a normal vector
|
|
|
- // upper-left 3x3 of matrix is assumed to be orthogonal
|
|
|
+ // pre-multiplies the direction by the matrix and normalizes the result
|
|
|
|
|
|
- let tA = aNode;
|
|
|
- let tB = bNode;
|
|
|
+ let matrixNode, directionNode;
|
|
|
|
|
|
- if ( builder.isMatrix( tA.getNodeType( builder ) ) ) {
|
|
|
+ if ( builder.isMatrix( aNode.getNodeType( builder ) ) ) {
|
|
|
|
|
|
- tB = vec4( vec3( tB ), 0.0 );
|
|
|
+ matrixNode = aNode;
|
|
|
+ directionNode = bNode;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- tA = vec4( vec3( tA ), 0.0 );
|
|
|
+ matrixNode = bNode;
|
|
|
+ directionNode = aNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
- const mulNode = mul( tA, tB ).xyz;
|
|
|
-
|
|
|
- outputNode = normalize( mulNode );
|
|
|
+ outputNode = normalize( mul( matrixNode, vec4( vec3( directionNode ), 0.0 ) ).xyz );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -7967,6 +7965,34 @@ const pow4 = ( x ) => mul( x, x, x, x );
|
|
|
*/
|
|
|
const transformDirection = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.TRANSFORM_DIRECTION ).setParameterLength( 2 );
|
|
|
|
|
|
+/**
|
|
|
+ * Transforms a normal vector by the view matrix and then normalizes the result.
|
|
|
+ *
|
|
|
+ * The upper-left 3x3 of the view matrix is assumed to be orthonormal, so the
|
|
|
+ * normal can be transformed directly without involving the normal matrix.
|
|
|
+ *
|
|
|
+ * @tsl
|
|
|
+ * @function
|
|
|
+ * @param {Node<vec3>} normal - The normal vector, given in world space.
|
|
|
+ * @param {Node<mat3|mat4>} viewMatrix - The view matrix.
|
|
|
+ * @returns {Node<vec3>} The normal vector in view space.
|
|
|
+ */
|
|
|
+const transformNormalByViewMatrix = ( normal, viewMatrix ) => normalize( mul( viewMatrix, vec4( vec3( normal ), 0.0 ) ).xyz );
|
|
|
+
|
|
|
+/**
|
|
|
+ * Transforms a normal vector by the inverse of the view matrix and then normalizes the result.
|
|
|
+ *
|
|
|
+ * The upper-left 3x3 of the view matrix is assumed to be orthonormal, so post-multiplying
|
|
|
+ * by the view matrix is equivalent to pre-multiplying by its inverse.
|
|
|
+ *
|
|
|
+ * @tsl
|
|
|
+ * @function
|
|
|
+ * @param {Node<vec3>} normal - The normal vector, given in view space.
|
|
|
+ * @param {Node<mat3|mat4>} viewMatrix - The view matrix.
|
|
|
+ * @returns {Node<vec3>} The normal vector in world space.
|
|
|
+ */
|
|
|
+const transformNormalByInverseViewMatrix = ( normal, viewMatrix ) => normalize( vec4( vec3( normal ), 0.0 ).mul( viewMatrix ).xyz );
|
|
|
+
|
|
|
/**
|
|
|
* Returns the cube root of a number.
|
|
|
*
|
|
|
@@ -8167,6 +8193,8 @@ addMethodChaining( 'pow2', pow2 );
|
|
|
addMethodChaining( 'pow3', pow3 );
|
|
|
addMethodChaining( 'pow4', pow4 );
|
|
|
addMethodChaining( 'transformDirection', transformDirection );
|
|
|
+addMethodChaining( 'transformNormalByViewMatrix', transformNormalByViewMatrix );
|
|
|
+addMethodChaining( 'transformNormalByInverseViewMatrix', transformNormalByInverseViewMatrix );
|
|
|
addMethodChaining( 'mix', mixElement );
|
|
|
addMethodChaining( 'clamp', clamp );
|
|
|
addMethodChaining( 'refract', refract );
|
|
|
@@ -15103,33 +15131,60 @@ const frontFacing = /*@__PURE__*/ nodeImmutable( FrontFacingNode );
|
|
|
const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 );
|
|
|
|
|
|
/**
|
|
|
- * Converts a direction vector to a face direction vector based on the material's side.
|
|
|
+ * Negates a vector if the rendering occurs on the back side of a face,
|
|
|
+ * based on the material's side configuration.
|
|
|
*
|
|
|
- * If the material is set to `BackSide`, the direction is inverted.
|
|
|
- * If the material is set to `DoubleSide`, the direction is multiplied by `faceDirection`.
|
|
|
+ * - If the material's side is `BackSide`, the vector is inverted (negated).
|
|
|
+ * - If the material's side is `DoubleSide`, the vector is multiplied by `faceDirection`
|
|
|
+ * (negated only for back-facing fragments).
|
|
|
+ * - If the material's side is `FrontSide` (default), the vector remains unchanged.
|
|
|
*
|
|
|
* @tsl
|
|
|
- * @param {Node<vec3>} direction - The direction vector to convert.
|
|
|
- * @returns {Node<vec3>} The converted direction vector.
|
|
|
+ * @function
|
|
|
+ * @param {Node<vec3>} vector - The vector to process.
|
|
|
+ * @returns {Node<vec3>} The processed vector.
|
|
|
*/
|
|
|
-const directionToFaceDirection = /*@__PURE__*/ Fn( ( [ direction ], { material } ) => {
|
|
|
+const negateOnBackSide = /*@__PURE__*/ Fn( ( [ vector ], { material } ) => {
|
|
|
|
|
|
const side = material.side;
|
|
|
|
|
|
if ( side === BackSide ) {
|
|
|
|
|
|
- direction = direction.mul( -1 );
|
|
|
+ vector = vector.mul( -1 );
|
|
|
|
|
|
} else if ( side === DoubleSide ) {
|
|
|
|
|
|
- direction = direction.mul( faceDirection );
|
|
|
+ vector = vector.mul( faceDirection );
|
|
|
|
|
|
}
|
|
|
|
|
|
- return direction;
|
|
|
+ return vector;
|
|
|
|
|
|
} );
|
|
|
|
|
|
+/**
|
|
|
+ * Negates a vector if the rendering occurs on the back side of a face,
|
|
|
+ * based on the material's side configuration.
|
|
|
+ *
|
|
|
+ * - If the material's side is `BackSide`, the vector is inverted (negated).
|
|
|
+ * - If the material's side is `DoubleSide`, the vector is multiplied by `faceDirection`
|
|
|
+ * (negated only for back-facing fragments).
|
|
|
+ * - If the material's side is `FrontSide` (default), the vector remains unchanged.
|
|
|
+ *
|
|
|
+ * @tsl
|
|
|
+ * @function
|
|
|
+ * @deprecated since r185. Use {@link negateOnBackSide} instead.
|
|
|
+ * @param {Node<vec3>} vector - The vector to convert.
|
|
|
+ * @returns {Node<vec3>} The converted vector.
|
|
|
+ */
|
|
|
+const directionToFaceDirection = ( vector ) => {
|
|
|
+
|
|
|
+ warnOnce( 'TSL: "directionToFaceDirection()" has been renamed to "negateOnBackSide()".' ); // @deprecated r185
|
|
|
+
|
|
|
+ return negateOnBackSide( vector );
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* TSL object that represents the normal attribute of the current rendered object in local space.
|
|
|
*
|
|
|
@@ -15198,7 +15253,7 @@ const normalViewGeometry = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
*/
|
|
|
const normalWorldGeometry = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
|
|
|
- let normal = normalViewGeometry.transformDirection( cameraViewMatrix );
|
|
|
+ let normal = normalViewGeometry.transformNormalByInverseViewMatrix( cameraViewMatrix );
|
|
|
|
|
|
if ( builder.isFlatShading() !== true ) {
|
|
|
|
|
|
@@ -15226,7 +15281,7 @@ const normalView = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
|
|
|
if ( builder.isFlatShading() !== true ) {
|
|
|
|
|
|
- node = directionToFaceDirection( node );
|
|
|
+ node = negateOnBackSide( node );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -15248,7 +15303,7 @@ const normalView = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
* @tsl
|
|
|
* @type {Node<vec3>}
|
|
|
*/
|
|
|
-const normalWorld = /*@__PURE__*/ normalView.transformDirection( cameraViewMatrix ).toVar( 'normalWorld' );
|
|
|
+const normalWorld = /*@__PURE__*/ normalView.transformNormalByInverseViewMatrix( cameraViewMatrix ).toVar( 'normalWorld' );
|
|
|
|
|
|
/**
|
|
|
* TSL object that represents the clearcoat vertex normal of the current rendered object in view space.
|
|
|
@@ -15277,24 +15332,24 @@ const clearcoatNormalView = /*@__PURE__*/ ( Fn( ( { subBuildFn, context } ) => {
|
|
|
}, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'clearcoatNormalView' );
|
|
|
|
|
|
/**
|
|
|
- * Transforms the normal with the given matrix.
|
|
|
+ * Transforms the normal by the normal matrix of the given matrix and then normalizes the result.
|
|
|
*
|
|
|
* @tsl
|
|
|
* @function
|
|
|
* @param {Node<vec3>} normal - The normal.
|
|
|
- * @param {Node<mat3>} [matrix=modelWorldMatrix] - The matrix.
|
|
|
+ * @param {Node<mat3|mat4>} [matrix=modelWorldMatrix] - The matrix.
|
|
|
* @return {Node<vec3>} The transformed normal.
|
|
|
*/
|
|
|
const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix ] ) => {
|
|
|
|
|
|
- const m = mat3( matrix );
|
|
|
+ const normalMatrix = mat3( matrix ).inverse().transpose();
|
|
|
|
|
|
- const transformedNormal = normal.div( vec3( m[ 0 ].dot( m[ 0 ] ), m[ 1 ].dot( m[ 1 ] ), m[ 2 ].dot( m[ 2 ] ) ) );
|
|
|
-
|
|
|
- return m.mul( transformedNormal ).xyz;
|
|
|
+ return normalMatrix.mul( normal ).normalize();
|
|
|
|
|
|
} );
|
|
|
|
|
|
+addMethodChaining( 'transformNormal', transformNormal );
|
|
|
+
|
|
|
/**
|
|
|
* Transforms the given normal from local to view space.
|
|
|
*
|
|
|
@@ -15310,7 +15365,7 @@ const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => {
|
|
|
|
|
|
if ( modelNormalViewMatrix ) {
|
|
|
|
|
|
- return modelNormalViewMatrix.transformDirection( normal );
|
|
|
+ return normal.transformNormalByViewMatrix( modelNormalViewMatrix );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -15318,7 +15373,7 @@ const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => {
|
|
|
|
|
|
const transformedNormal = modelNormalMatrix.mul( normal );
|
|
|
|
|
|
- return cameraViewMatrix.transformDirection( transformedNormal );
|
|
|
+ return transformedNormal.transformNormalByViewMatrix( cameraViewMatrix );
|
|
|
|
|
|
} );
|
|
|
|
|
|
@@ -15442,7 +15497,7 @@ const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( normal
|
|
|
* @tsl
|
|
|
* @type {Node<vec3>}
|
|
|
*/
|
|
|
-const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' );
|
|
|
+const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraWorldMatrix ).toVar( 'reflectVector' );
|
|
|
|
|
|
/**
|
|
|
* Used for sampling cube maps when using cube refraction mapping.
|
|
|
@@ -15450,7 +15505,7 @@ const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMa
|
|
|
* @tsl
|
|
|
* @type {Node<vec3>}
|
|
|
*/
|
|
|
-const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' );
|
|
|
+const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraWorldMatrix ).toVar( 'refractVector' );
|
|
|
|
|
|
const EmptyTexture = /*@__PURE__*/ new CubeTexture();
|
|
|
|
|
|
@@ -16230,7 +16285,7 @@ const tangentView = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
|
|
|
if ( builder.isFlatShading() !== true ) {
|
|
|
|
|
|
- node = directionToFaceDirection( node );
|
|
|
+ node = negateOnBackSide( node );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -16244,7 +16299,7 @@ const tangentView = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
* @tsl
|
|
|
* @type {Node<vec3>}
|
|
|
*/
|
|
|
-const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).toVarying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' );
|
|
|
+const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraWorldMatrix ).toVarying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' );
|
|
|
|
|
|
/**
|
|
|
* Returns the bitangent node and assigns it to a varying if the material is not flat shaded.
|
|
|
@@ -16307,7 +16362,7 @@ const bitangentView = /*@__PURE__*/ ( Fn( ( builder ) => {
|
|
|
|
|
|
if ( builder.isFlatShading() !== true ) {
|
|
|
|
|
|
- node = directionToFaceDirection( node );
|
|
|
+ node = negateOnBackSide( node );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -16528,7 +16583,7 @@ class NormalMapNode extends TempNode {
|
|
|
|
|
|
if ( builder.isFlatShading() === true ) {
|
|
|
|
|
|
- scale = directionToFaceDirection( scale );
|
|
|
+ scale = negateOnBackSide( scale );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -22822,18 +22877,42 @@ class MeshNormalNodeMaterial extends NodeMaterial {
|
|
|
*
|
|
|
* @tsl
|
|
|
* @function
|
|
|
- * @param {?Node<vec3>} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`.
|
|
|
+ * @param {?Node<vec3>} [direction=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`.
|
|
|
* @returns {Node<vec2>}
|
|
|
*/
|
|
|
-const equirectUV = /*@__PURE__*/ Fn( ( [ dir = positionWorldDirection ] ) => {
|
|
|
+const equirectUV = /*@__PURE__*/ Fn( ( [ direction = positionWorldDirection ] ) => {
|
|
|
|
|
|
- const u = dir.z.atan( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 );
|
|
|
- const v = dir.y.clamp( -1, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 );
|
|
|
+ const u = direction.z.atan( direction.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 );
|
|
|
+ const v = direction.y.clamp( -1, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 );
|
|
|
|
|
|
return vec2( u, v );
|
|
|
|
|
|
} );
|
|
|
|
|
|
+/**
|
|
|
+ * TSL function for creating an equirect direction node.
|
|
|
+ *
|
|
|
+ * Can be used to compute a direction vector from the given equirectangular
|
|
|
+ * UV coordinates.
|
|
|
+ *
|
|
|
+ * @tsl
|
|
|
+ * @function
|
|
|
+ * @param {?Node<vec2>} [uv=UV()] - The equirectangular UV coordinates.
|
|
|
+ * @returns {Node<vec3>} The computed direction vector.
|
|
|
+ */
|
|
|
+const equirectDirection = /*@__PURE__*/ Fn( ( [ uv = uv$1() ] ) => {
|
|
|
+
|
|
|
+ const theta = uv.x.sub( 0.5 ).mul( Math.PI * 2 );
|
|
|
+ const phi = uv.y.sub( 0.5 ).mul( Math.PI );
|
|
|
+ const cosPhi = phi.cos();
|
|
|
+ const x = cosPhi.mul( theta.cos() );
|
|
|
+ const y = phi.sin();
|
|
|
+ const z = cosPhi.mul( theta.sin() );
|
|
|
+
|
|
|
+ return vec3( x, y, z );
|
|
|
+
|
|
|
+} );
|
|
|
+
|
|
|
/**
|
|
|
* This class represents a cube render target. It is a special version
|
|
|
* of `WebGLCubeRenderTarget` which is compatible with `WebGPURenderer`.
|
|
|
@@ -23509,7 +23588,7 @@ class MeshBasicNodeMaterial extends NodeMaterial {
|
|
|
*/
|
|
|
setupNormal() {
|
|
|
|
|
|
- return directionToFaceDirection( normalViewGeometry ); // see #28839
|
|
|
+ return negateOnBackSide( normalViewGeometry ); // see #28839
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -27233,7 +27312,7 @@ const createRadianceContext = ( roughnessNode, normalViewNode ) => {
|
|
|
// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
|
|
|
reflectVec = pow4( roughnessNode ).mix( reflectVec, normalViewNode ).normalize();
|
|
|
|
|
|
- reflectVec = reflectVec.transformDirection( cameraViewMatrix );
|
|
|
+ reflectVec = reflectVec.transformDirection( cameraWorldMatrix );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -44850,7 +44929,7 @@ class ShadowNode extends ShadowBaseNode {
|
|
|
|
|
|
if ( this.shadowMap.texture.isCubeTexture ) {
|
|
|
|
|
|
- return cubeTexture( this.shadowMap.texture );
|
|
|
+ return cubeTexture( this.shadowMap.texture, equirectDirection() );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -44862,15 +44941,36 @@ class ShadowNode extends ShadowBaseNode {
|
|
|
|
|
|
return shadowOutput.toInspector( `${ inspectName } / Depth`, () => {
|
|
|
|
|
|
- // TODO: Use linear depth
|
|
|
+ const shadowCameraNear = reference( 'near', 'float', this.shadow.camera );
|
|
|
+ const shadowCameraFar = reference( 'far', 'float', this.shadow.camera );
|
|
|
+
|
|
|
+ let depthNode;
|
|
|
|
|
|
if ( this.shadowMap.texture.isCubeTexture ) {
|
|
|
|
|
|
- return cubeTexture( this.shadowMap.texture ).r.oneMinus();
|
|
|
+ depthNode = cubeTexture( this.shadowMap.depthTexture, equirectDirection() ).r;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ depthNode = texture( this.shadowMap.depthTexture ).r;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return textureLoad( this.shadowMap.depthTexture, uv$1().mul( textureSize( texture( this.shadowMap.depthTexture ) ) ) ).r.oneMinus();
|
|
|
+ let linearDepth;
|
|
|
+
|
|
|
+ if ( this.shadow.camera.isPerspectiveCamera ) {
|
|
|
+
|
|
|
+ linearDepth = perspectiveDepthToViewZ( depthNode, shadowCameraNear, shadowCameraFar );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ linearDepth = orthographicDepthToViewZ( depthNode, shadowCameraNear, shadowCameraFar );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ linearDepth = viewZToOrthographicDepth( linearDepth, shadowCameraNear, shadowCameraFar );
|
|
|
+
|
|
|
+ return linearDepth.oneMinus();
|
|
|
|
|
|
} );
|
|
|
|
|
|
@@ -47980,6 +48080,7 @@ var TSL = /*#__PURE__*/Object.freeze({
|
|
|
element: element,
|
|
|
emissive: emissive,
|
|
|
equal: equal,
|
|
|
+ equirectDirection: equirectDirection,
|
|
|
equirectUV: equirectUV,
|
|
|
exp: exp,
|
|
|
exp2: exp2,
|
|
|
@@ -48184,6 +48285,7 @@ var TSL = /*#__PURE__*/Object.freeze({
|
|
|
mx_worley_noise_vec2: mx_worley_noise_vec2,
|
|
|
mx_worley_noise_vec3: mx_worley_noise_vec3,
|
|
|
negate: negate,
|
|
|
+ negateOnBackSide: negateOnBackSide,
|
|
|
neutralToneMapping: neutralToneMapping,
|
|
|
nodeArray: nodeArray,
|
|
|
nodeImmutable: nodeImmutable,
|
|
|
@@ -48378,6 +48480,8 @@ var TSL = /*#__PURE__*/Object.freeze({
|
|
|
toonOutlinePass: toonOutlinePass,
|
|
|
transformDirection: transformDirection,
|
|
|
transformNormal: transformNormal,
|
|
|
+ transformNormalByInverseViewMatrix: transformNormalByInverseViewMatrix,
|
|
|
+ transformNormalByViewMatrix: transformNormalByViewMatrix,
|
|
|
transformNormalToView: transformNormalToView,
|
|
|
transformedClearcoatNormalView: transformedClearcoatNormalView,
|
|
|
transformedNormalView: transformedNormalView,
|
|
|
@@ -56334,6 +56438,14 @@ class Lighting {
|
|
|
*/
|
|
|
this.enabled = true;
|
|
|
|
|
|
+ /**
|
|
|
+ * A stack of light arrays saved per render via {@link Lighting#beginRender}.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @type {Array<Array<Light>>}
|
|
|
+ */
|
|
|
+ this._cache = [];
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -56349,10 +56461,9 @@ class Lighting {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns a lights node for the given scene and camera.
|
|
|
+ * Returns a lights node for the given scene.
|
|
|
*
|
|
|
* @param {Scene} scene - The scene.
|
|
|
- * @param {Camera} camera - The camera.
|
|
|
* @return {LightsNode} The lights node.
|
|
|
*/
|
|
|
getNode( scene ) {
|
|
|
@@ -56373,6 +56484,33 @@ class Lighting {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Saves the current lights of the scene's lights node so they can be restored
|
|
|
+ * in {@link Lighting#finishRender}. Must be paired with a `finishRender()` call
|
|
|
+ * to avoid memory leaks.
|
|
|
+ *
|
|
|
+ * Nested render calls might mutate the lights array so a save/restore is required
|
|
|
+ * for each render call.
|
|
|
+ *
|
|
|
+ * @param {Scene} scene - The scene.
|
|
|
+ */
|
|
|
+ beginRender( scene ) {
|
|
|
+
|
|
|
+ this._cache.push( this.getNode( scene ).getLights() );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Restores the lights saved by the matching {@link Lighting#beginRender} call.
|
|
|
+ *
|
|
|
+ * @param {Scene} scene - The scene.
|
|
|
+ */
|
|
|
+ finishRender( scene ) {
|
|
|
+
|
|
|
+ this.getNode( scene ).setLights( this._cache.pop() );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -60263,6 +60401,8 @@ class Renderer {
|
|
|
const previousRenderObjectFunction = this._currentRenderObjectFunction;
|
|
|
const previousHandleObjectFunction = this._handleObjectFunction;
|
|
|
|
|
|
+ this.lighting.beginRender( scene );
|
|
|
+
|
|
|
//
|
|
|
|
|
|
this._callDepth ++;
|
|
|
@@ -60489,6 +60629,8 @@ class Renderer {
|
|
|
this._currentRenderObjectFunction = previousRenderObjectFunction;
|
|
|
this._handleObjectFunction = previousHandleObjectFunction;
|
|
|
|
|
|
+ this.lighting.finishRender( scene );
|
|
|
+
|
|
|
//
|
|
|
|
|
|
this._callDepth --;
|
|
|
@@ -66124,17 +66266,29 @@ class Backend {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Whether the backend supports query timestamps or not.
|
|
|
+ *
|
|
|
+ * @type {boolean}
|
|
|
+ * @readonly
|
|
|
+ */
|
|
|
+ get hasTimestamp() {
|
|
|
+
|
|
|
+ return false;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Returns `true` if a timestamp for the given uid is available.
|
|
|
*
|
|
|
* @param {string} uid - The unique identifier.
|
|
|
* @return {boolean} Whether the timestamp is available or not.
|
|
|
*/
|
|
|
- hasTimestamp( uid ) {
|
|
|
+ hasTimestampQuery( uid ) {
|
|
|
|
|
|
const queryPool = this._getQueryPool( uid );
|
|
|
|
|
|
- return queryPool.hasTimestamp( uid );
|
|
|
+ return queryPool.hasTimestampQuery( uid );
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -69267,6 +69421,9 @@ class WebGLTextureUtils {
|
|
|
const srcFramebuffer = srcRenderContextData.framebuffers[ srcTextureData.cacheKey ];
|
|
|
const dstFramebuffer = dstRenderContextData.framebuffers[ dstTextureData.cacheKey ];
|
|
|
|
|
|
+ const prevReadFramebuffer = state.currentBoundFramebuffers[ gl.READ_FRAMEBUFFER ] ?? null;
|
|
|
+ const prevDrawFramebuffer = state.currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] ?? null;
|
|
|
+
|
|
|
state.bindFramebuffer( gl.READ_FRAMEBUFFER, srcFramebuffer );
|
|
|
state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, dstFramebuffer );
|
|
|
|
|
|
@@ -69284,8 +69441,8 @@ class WebGLTextureUtils {
|
|
|
|
|
|
}
|
|
|
|
|
|
- state.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
|
|
|
- state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
|
|
|
+ state.bindFramebuffer( gl.READ_FRAMEBUFFER, prevReadFramebuffer );
|
|
|
+ state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, prevDrawFramebuffer );
|
|
|
|
|
|
} else if ( srcLevel !== 0 || srcTexture.isRenderTargetTexture || backend.has( srcTexture ) ) {
|
|
|
|
|
|
@@ -69295,6 +69452,9 @@ class WebGLTextureUtils {
|
|
|
if ( this._srcFramebuffer === null ) this._srcFramebuffer = gl.createFramebuffer();
|
|
|
if ( this._dstFramebuffer === null ) this._dstFramebuffer = gl.createFramebuffer();
|
|
|
|
|
|
+ const prevReadFramebuffer = state.currentBoundFramebuffers[ gl.READ_FRAMEBUFFER ] ?? null;
|
|
|
+ const prevDrawFramebuffer = state.currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] ?? null;
|
|
|
+
|
|
|
// bind the frame buffer targets
|
|
|
state.bindFramebuffer( gl.READ_FRAMEBUFFER, this._srcFramebuffer );
|
|
|
state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, this._dstFramebuffer );
|
|
|
@@ -69339,9 +69499,9 @@ class WebGLTextureUtils {
|
|
|
|
|
|
}
|
|
|
|
|
|
- // unbind read, draw buffers
|
|
|
- state.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
|
|
|
- state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
|
|
|
+ // restore previous read, draw framebuffer bindings
|
|
|
+ state.bindFramebuffer( gl.READ_FRAMEBUFFER, prevReadFramebuffer );
|
|
|
+ state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, prevDrawFramebuffer );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
@@ -70118,7 +70278,7 @@ class TimestampQueryPool {
|
|
|
* @param {string} uid - A unique identifier for the render context.
|
|
|
* @return {boolean} True if a timestamp is available, false otherwise.
|
|
|
*/
|
|
|
- hasTimestamp( uid ) {
|
|
|
+ hasTimestampQuery( uid ) {
|
|
|
|
|
|
return this.timestamps.has( uid );
|
|
|
|
|
|
@@ -70836,6 +70996,18 @@ class WebGLBackend extends Backend {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Whether the backend supports query timestamps or not.
|
|
|
+ *
|
|
|
+ * @type {boolean}
|
|
|
+ * @readonly
|
|
|
+ */
|
|
|
+ get hasTimestamp() {
|
|
|
+
|
|
|
+ return this.disjoint !== null;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* This method performs a readback operation by moving buffer data from
|
|
|
* a storage buffer attribute from the GPU to the CPU. ReadbackBuffer can
|
|
|
@@ -77710,6 +77882,83 @@ const wgslPolyfill = {
|
|
|
repeatWrapping_float: new CodeNode( 'fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }' ),
|
|
|
mirrorWrapping_float: new CodeNode( 'fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }' ),
|
|
|
clampWrapping_float: new CodeNode( 'fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }' ),
|
|
|
+ inverse_mat2: new CodeNode( /* wgsl */`
|
|
|
+fn tsl_inverse_mat2( m : mat2x2<f32> ) -> mat2x2<f32> {
|
|
|
+
|
|
|
+ let det = m[ 0 ][ 0 ] * m[ 1 ][ 1 ] - m[ 0 ][ 1 ] * m[ 1 ][ 0 ];
|
|
|
+
|
|
|
+ return mat2x2<f32>(
|
|
|
+ m[ 1 ][ 1 ], - m[ 0 ][ 1 ],
|
|
|
+ - m[ 1 ][ 0 ], m[ 0 ][ 0 ]
|
|
|
+ ) * ( 1.0 / det );
|
|
|
+
|
|
|
+}
|
|
|
+` ),
|
|
|
+ inverse_mat3: new CodeNode( /* wgsl */`
|
|
|
+fn tsl_inverse_mat3( m : mat3x3<f32> ) -> mat3x3<f32> {
|
|
|
+
|
|
|
+ let a00 = m[ 0 ][ 0 ]; let a01 = m[ 0 ][ 1 ]; let a02 = m[ 0 ][ 2 ];
|
|
|
+ let a10 = m[ 1 ][ 0 ]; let a11 = m[ 1 ][ 1 ]; let a12 = m[ 1 ][ 2 ];
|
|
|
+ let a20 = m[ 2 ][ 0 ]; let a21 = m[ 2 ][ 1 ]; let a22 = m[ 2 ][ 2 ];
|
|
|
+
|
|
|
+ let b01 = a22 * a11 - a12 * a21;
|
|
|
+ let b11 = - a22 * a10 + a12 * a20;
|
|
|
+ let b21 = a21 * a10 - a11 * a20;
|
|
|
+
|
|
|
+ let det = a00 * b01 + a01 * b11 + a02 * b21;
|
|
|
+
|
|
|
+ return mat3x3<f32>(
|
|
|
+ b01, ( - a22 * a01 + a02 * a21 ), ( a12 * a01 - a02 * a11 ),
|
|
|
+ b11, ( a22 * a00 - a02 * a20 ), ( - a12 * a00 + a02 * a10 ),
|
|
|
+ b21, ( - a21 * a00 + a01 * a20 ), ( a11 * a00 - a01 * a10 )
|
|
|
+ ) * ( 1.0 / det );
|
|
|
+
|
|
|
+}
|
|
|
+` ),
|
|
|
+ inverse_mat4: new CodeNode( /* wgsl */`
|
|
|
+fn tsl_inverse_mat4( m : mat4x4<f32> ) -> mat4x4<f32> {
|
|
|
+
|
|
|
+ let a00 = m[ 0 ][ 0 ]; let a01 = m[ 0 ][ 1 ]; let a02 = m[ 0 ][ 2 ]; let a03 = m[ 0 ][ 3 ];
|
|
|
+ let a10 = m[ 1 ][ 0 ]; let a11 = m[ 1 ][ 1 ]; let a12 = m[ 1 ][ 2 ]; let a13 = m[ 1 ][ 3 ];
|
|
|
+ let a20 = m[ 2 ][ 0 ]; let a21 = m[ 2 ][ 1 ]; let a22 = m[ 2 ][ 2 ]; let a23 = m[ 2 ][ 3 ];
|
|
|
+ let a30 = m[ 3 ][ 0 ]; let a31 = m[ 3 ][ 1 ]; let a32 = m[ 3 ][ 2 ]; let a33 = m[ 3 ][ 3 ];
|
|
|
+
|
|
|
+ let b00 = a00 * a11 - a01 * a10;
|
|
|
+ let b01 = a00 * a12 - a02 * a10;
|
|
|
+ let b02 = a00 * a13 - a03 * a10;
|
|
|
+ let b03 = a01 * a12 - a02 * a11;
|
|
|
+ let b04 = a01 * a13 - a03 * a11;
|
|
|
+ let b05 = a02 * a13 - a03 * a12;
|
|
|
+ let b06 = a20 * a31 - a21 * a30;
|
|
|
+ let b07 = a20 * a32 - a22 * a30;
|
|
|
+ let b08 = a20 * a33 - a23 * a30;
|
|
|
+ let b09 = a21 * a32 - a22 * a31;
|
|
|
+ let b10 = a21 * a33 - a23 * a31;
|
|
|
+ let b11 = a22 * a33 - a23 * a32;
|
|
|
+
|
|
|
+ let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
|
+
|
|
|
+ return mat4x4<f32>(
|
|
|
+ a11 * b11 - a12 * b10 + a13 * b09,
|
|
|
+ a02 * b10 - a01 * b11 - a03 * b09,
|
|
|
+ a31 * b05 - a32 * b04 + a33 * b03,
|
|
|
+ a22 * b04 - a21 * b05 - a23 * b03,
|
|
|
+ a12 * b08 - a10 * b11 - a13 * b07,
|
|
|
+ a00 * b11 - a02 * b08 + a03 * b07,
|
|
|
+ a32 * b02 - a30 * b05 - a33 * b01,
|
|
|
+ a20 * b05 - a22 * b02 + a23 * b01,
|
|
|
+ a10 * b10 - a11 * b08 + a13 * b06,
|
|
|
+ a01 * b08 - a00 * b10 - a03 * b06,
|
|
|
+ a30 * b04 - a31 * b02 + a33 * b00,
|
|
|
+ a21 * b02 - a20 * b04 - a23 * b00,
|
|
|
+ a11 * b07 - a10 * b09 - a12 * b06,
|
|
|
+ a00 * b09 - a01 * b07 + a02 * b06,
|
|
|
+ a31 * b01 - a30 * b03 - a32 * b00,
|
|
|
+ a20 * b03 - a21 * b01 + a22 * b00
|
|
|
+ ) * ( 1.0 / det );
|
|
|
+
|
|
|
+}
|
|
|
+` ),
|
|
|
biquadraticTexture: new CodeNode( /* wgsl */`
|
|
|
fn tsl_biquadraticTexture( map : texture_2d<f32>, coord : vec2f, iRes : vec2u, level : u32 ) -> vec4f {
|
|
|
|
|
|
@@ -77769,6 +78018,9 @@ const wgslMethods = {
|
|
|
equals_bvec2: 'tsl_equals_bvec2',
|
|
|
equals_bvec3: 'tsl_equals_bvec3',
|
|
|
equals_bvec4: 'tsl_equals_bvec4',
|
|
|
+ inverse_mat2: 'tsl_inverse_mat2',
|
|
|
+ inverse_mat3: 'tsl_inverse_mat3',
|
|
|
+ inverse_mat4: 'tsl_inverse_mat4',
|
|
|
inversesqrt: 'inverseSqrt',
|
|
|
bitcast: 'bitcast<f32>',
|
|
|
floatpack_snorm_2x16: 'pack2x16snorm',
|
|
|
@@ -83316,6 +83568,18 @@ class WebGPUBackend extends Backend {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Whether the backend supports query timestamps or not.
|
|
|
+ *
|
|
|
+ * @type {boolean}
|
|
|
+ * @readonly
|
|
|
+ */
|
|
|
+ get hasTimestamp() {
|
|
|
+
|
|
|
+ return true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* This method performs a readback operation by moving buffer data from
|
|
|
* a storage buffer attribute from the GPU to the CPU. ReadbackBuffer can
|