diff --git a/src/nodes/accessors/Texture3DNode.js b/src/nodes/accessors/Texture3DNode.js index cc1c0ce7eaad3f..785403035429fd 100644 --- a/src/nodes/accessors/Texture3DNode.js +++ b/src/nodes/accessors/Texture3DNode.js @@ -157,6 +157,19 @@ class Texture3DNode extends TextureNode { } + /** + * Generates the offset code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} offsetNode - The offset node to generate code for. + * @return {string} The generated code snippet. + */ + generateOffset( builder, offsetNode ) { + + return offsetNode.build( builder, 'ivec3' ); + + } + /** * TODO. * diff --git a/src/nodes/accessors/TextureNode.js b/src/nodes/accessors/TextureNode.js index 91fd6e0b03d816..fb1c6552e46223 100644 --- a/src/nodes/accessors/TextureNode.js +++ b/src/nodes/accessors/TextureNode.js @@ -95,6 +95,15 @@ class TextureNode extends UniformNode { */ this.gradNode = null; + /** + * Represents the optional texel offset applied to the unnormalized texture + * coordinate before sampling the texture. + * + * @type {?Node} + * @default null + */ + this.offsetNode = null; + /** * Whether texture values should be sampled or fetched. * @@ -364,6 +373,7 @@ class TextureNode extends UniformNode { properties.compareNode = this.compareNode; properties.gradNode = this.gradNode; properties.depthNode = this.depthNode; + properties.offsetNode = this.offsetNode; } @@ -380,6 +390,19 @@ class TextureNode extends UniformNode { } + /** + * Generates the offset code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} offsetNode - The offset node to generate code for. + * @return {string} The generated code snippet. + */ + generateOffset( builder, offsetNode ) { + + return offsetNode.build( builder, 'ivec2' ); + + } + /** * Generates the snippet for the texture sampling. * @@ -391,9 +414,10 @@ class TextureNode extends UniformNode { * @param {?string} depthSnippet - The depth snippet. * @param {?string} compareSnippet - The compare snippet. * @param {?Array} gradSnippet - The grad snippet. + * @param {?string} offsetSnippet - The offset snippet. * @return {string} The generated code snippet. */ - generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { + generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet ) { const texture = this.value; @@ -401,27 +425,27 @@ class TextureNode extends UniformNode { if ( levelSnippet ) { - snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ); + snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ); } else if ( biasSnippet ) { - snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet ); + snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet ); } else if ( gradSnippet ) { - snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet ); + snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, offsetSnippet ); } else if ( compareSnippet ) { - snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet ); + snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet ); } else if ( this.sampler === false ) { - snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet ); + snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ); } else { - snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet ); + snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ); } @@ -459,7 +483,7 @@ class TextureNode extends UniformNode { if ( propertyName === undefined ) { - const { uvNode, levelNode, biasNode, compareNode, depthNode, gradNode } = properties; + const { uvNode, levelNode, biasNode, compareNode, depthNode, gradNode, offsetNode } = properties; const uvSnippet = this.generateUV( builder, uvNode ); const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null; @@ -467,12 +491,13 @@ class TextureNode extends UniformNode { const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null; const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null; const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null; + const offsetSnippet = offsetNode ? this.generateOffset( builder, offsetNode ) : null; const nodeVar = builder.getVarFromNode( this ); propertyName = builder.getPropertyName( nodeVar ); - const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ); + const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet, offsetSnippet ); builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); @@ -695,6 +720,22 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by defining an offset node. + * + * @param {Node} offsetNode - The offset node. + * @return {TextureNode} A texture node representing the texture sample. + */ + offset( offsetNode ) { + + const textureNode = this.clone(); + textureNode.offsetNode = nodeObject( offsetNode ); + textureNode.referenceNode = this.getBase(); + + return nodeObject( textureNode ); + + } + // -- serialize( data ) { @@ -749,6 +790,7 @@ class TextureNode extends UniformNode { newNode.depthNode = this.depthNode; newNode.compareNode = this.compareNode; newNode.gradNode = this.gradNode; + newNode.offsetNode = this.offsetNode; return newNode; diff --git a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js index ec58b7232a1297..ba6b8ecc90dbc7 100644 --- a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +++ b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js @@ -350,7 +350,7 @@ ${ flowData.code } const channel = '.' + vectorComponents.join( '' ).slice( 0, itemSize ); const uvSnippet = `ivec2(${indexSnippet} % ${ propertySizeName }, ${indexSnippet} / ${ propertySizeName })`; - const snippet = this.generateTextureLoad( null, textureName, uvSnippet, null, '0' ); + const snippet = this.generateTextureLoad( null, textureName, uvSnippet, null, null, '0' ); // @@ -384,17 +384,30 @@ ${ flowData.code } * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling. * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [levelSnippet='0u'] - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. * @return {string} The GLSL snippet. */ - generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0' ) { + generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, offsetSnippet, levelSnippet = '0' ) { if ( depthSnippet ) { + if ( offsetSnippet ) { + + return `texelFetchOffset( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet }, ${ offsetSnippet } )`; + + } + return `texelFetch( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet } )`; } else { + if ( offsetSnippet ) { + + return `texelFetchOffset( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`; + + } + return `texelFetch( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet } )`; } @@ -408,20 +421,33 @@ ${ flowData.code } * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @return {string} The GLSL snippet. */ - generateTexture( texture, textureProperty, uvSnippet, depthSnippet ) { + generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ) { if ( texture.isDepthTexture ) { if ( depthSnippet ) uvSnippet = `vec4( ${ uvSnippet }, ${ depthSnippet } )`; + if ( offsetSnippet ) { + + return `textureOffset( ${ textureProperty }, ${ uvSnippet }, ${ offsetSnippet } ).x`; + + } + return `texture( ${ textureProperty }, ${ uvSnippet } ).x`; } else { if ( depthSnippet ) uvSnippet = `vec3( ${ uvSnippet }, ${ depthSnippet } )`; + if ( offsetSnippet ) { + + return `textureOffset( ${ textureProperty }, ${ uvSnippet }, ${ offsetSnippet } )`; + + } + return `texture( ${ textureProperty }, ${ uvSnippet } )`; } @@ -435,9 +461,16 @@ ${ flowData.code } * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. * @param {string} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @return {string} The GLSL snippet. */ - generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet ) { + generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, offsetSnippet ) { + + if ( offsetSnippet ) { + + return `textureLodOffset( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`; + + } return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`; @@ -450,9 +483,16 @@ ${ flowData.code } * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. * @param {string} biasSnippet - A GLSL snippet that represents the bias to apply to the mip level before sampling. + * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @return {string} The GLSL snippet. */ - generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet ) { + generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, offsetSnippet ) { + + if ( offsetSnippet ) { + + return `textureOffset( ${ textureProperty }, ${ uvSnippet }, ${ offsetSnippet }, ${ biasSnippet } )`; + + } return `texture( ${ textureProperty }, ${ uvSnippet }, ${ biasSnippet } )`; @@ -465,9 +505,16 @@ ${ flowData.code } * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. * @param {Array} gradSnippet - An array holding both gradient GLSL snippets. + * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @return {string} The GLSL snippet. */ - generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet ) { + generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, offsetSnippet ) { + + if ( offsetSnippet ) { + + return `textureGradOffset( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] }, ${ offsetSnippet } )`; + + } return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; @@ -482,19 +529,32 @@ ${ flowData.code } * @param {string} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. * @param {string} compareSnippet - A GLSL snippet that represents the reference value. * @param {?string} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The GLSL snippet. */ - generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { + generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { if ( depthSnippet ) { + if ( offsetSnippet ) { + + return `textureOffset( ${ textureProperty }, vec4( ${ uvSnippet }, ${ depthSnippet }, ${ compareSnippet } ), ${ offsetSnippet } )`; + + } + return `texture( ${ textureProperty }, vec4( ${ uvSnippet }, ${ depthSnippet }, ${ compareSnippet } ) )`; } + if ( offsetSnippet ) { + + return `textureOffset( ${ textureProperty }, vec3( ${ uvSnippet }, ${ compareSnippet } ), ${ offsetSnippet } )`; + + } + return `texture( ${ textureProperty }, vec3( ${ uvSnippet }, ${ compareSnippet } ) )`; } else { diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index 76d056368189c5..5f80685dc17dd5 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -219,19 +219,32 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The WGSL snippet. */ - _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { + _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { if ( depthSnippet ) { + if ( offsetSnippet ) { + + return `textureSample( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ depthSnippet }, ${ offsetSnippet } )`; + + } + return `textureSample( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ depthSnippet } )`; } else { + if ( offsetSnippet ) { + + return `textureSample( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ offsetSnippet } )`; + + } + return `textureSample( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet } )`; } @@ -253,21 +266,28 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. * @param {string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @return {string} The WGSL snippet. */ - generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ) { + generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ) { if ( this.isUnfilterable( texture ) === false ) { + if ( offsetSnippet ) { + + return `textureSampleLevel( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`; + + } + return `textureSampleLevel( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ levelSnippet } )`; } else if ( this.isFilteredTexture( texture ) ) { - return this.generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet ); + return this.generateFilteredTexture( texture, textureProperty, uvSnippet, offsetSnippet, levelSnippet ); } else { - return this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet ); + return this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet ); } @@ -445,16 +465,23 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {Texture} texture - The texture. * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. - * @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. + * @param {string} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. * @return {string} The WGSL snippet. */ - generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0u' ) { + generateFilteredTexture( texture, textureProperty, uvSnippet, offsetSnippet, levelSnippet = '0u' ) { this._include( 'biquadraticTexture' ); const wrapFunction = this.generateWrapFunction( texture ); const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet ); + if ( offsetSnippet ) { + + uvSnippet = `${ uvSnippet } + vec2(${ offsetSnippet }) / ${ textureDimension }`; + + } + return `tsl_biquadraticTexture( ${ textureProperty }, ${ wrapFunction }( ${ uvSnippet } ), ${ textureDimension }, u32( ${ levelSnippet } ) )`; } @@ -467,18 +494,26 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. * @return {string} The WGSL snippet. */ - generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet = '0u' ) { + generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet = '0u' ) { const wrapFunction = this.generateWrapFunction( texture ); const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet ); const vecType = texture.isData3DTexture ? 'vec3' : 'vec2'; + + if ( offsetSnippet ) { + + uvSnippet = `${ uvSnippet } + ${ vecType }(${ offsetSnippet }) / ${ vecType }( ${ textureDimension } )`; + + } + const coordSnippet = `${ vecType }( ${ wrapFunction }( ${ uvSnippet } ) * ${ vecType }( ${ textureDimension } ) )`; - return this.generateTextureLoad( texture, textureProperty, coordSnippet, depthSnippet, levelSnippet ); + return this.generateTextureLoad( texture, textureProperty, coordSnippet, depthSnippet, null, levelSnippet ); } @@ -489,13 +524,20 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. * @return {string} The WGSL snippet. */ - generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u' ) { + generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, offsetSnippet, levelSnippet = '0u' ) { let snippet; + if ( offsetSnippet ) { + + uvIndexSnippet = `${ uvIndexSnippet } + ${ offsetSnippet }`; + + } + if ( depthSnippet ) { snippet = `textureLoad( ${ textureProperty }, ${ uvIndexSnippet }, ${ depthSnippet }, u32( ${ levelSnippet } ) )`; @@ -578,20 +620,21 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} textureProperty - The name of the texture uniform in the shader. * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The WGSL snippet. */ - generateTexture( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { + generateTexture( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) { let snippet = null; if ( this.isUnfilterable( texture ) ) { - snippet = this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, '0', shaderStage ); + snippet = this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, '0', shaderStage ); } else { - snippet = this._generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage ); + snippet = this._generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, shaderStage ); } @@ -607,14 +650,21 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {Array} gradSnippet - An array holding both gradient WGSL snippets. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The WGSL snippet. */ - generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, shaderStage = this.shaderStage ) { + generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { // TODO handle i32 or u32 --> uvSnippet, array_index: A, ddx, ddy + if ( offsetSnippet ) { + + return `textureSampleGrad( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] }, ${ offsetSnippet } )`; + + } + return `textureSampleGrad( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; } else { @@ -634,19 +684,32 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {string} compareSnippet - A WGSL snippet that represents the reference value. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The WGSL snippet. */ - generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { + generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { if ( texture.isDepthTexture === true && texture.isArrayTexture === true ) { + if ( offsetSnippet ) { + + return `textureSampleCompare( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ depthSnippet }, ${ compareSnippet }, ${ offsetSnippet } )`; + + } + return `textureSampleCompare( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ depthSnippet }, ${ compareSnippet } )`; } + if ( offsetSnippet ) { + + return `textureSampleCompare( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ compareSnippet }, ${ offsetSnippet } )`; + + } + return `textureSampleCompare( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ compareSnippet } )`; } else { @@ -665,22 +728,29 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The WGSL snippet. */ - generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet ) { + generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ) { if ( this.isUnfilterable( texture ) === false ) { + if ( offsetSnippet ) { + + return `textureSampleLevel( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`; + + } + return `textureSampleLevel( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ levelSnippet } )`; } else if ( this.isFilteredTexture( texture ) ) { - return this.generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet ); + return this.generateFilteredTexture( texture, textureProperty, uvSnippet, offsetSnippet, levelSnippet ); } else { - return this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet ); + return this.generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet, levelSnippet ); } @@ -694,13 +764,20 @@ class WGSLNodeBuilder extends NodeBuilder { * @param {string} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. * @param {string} biasSnippet - A WGSL snippet that represents the bias to apply to the mip level before sampling. * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. * @param {string} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. * @return {string} The WGSL snippet. */ - generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, shaderStage = this.shaderStage ) { + generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { + if ( offsetSnippet ) { + + return `textureSampleBias( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ biasSnippet }, ${ offsetSnippet } )`; + + } + return `textureSampleBias( ${ textureProperty }, ${ textureProperty }_sampler, ${ uvSnippet }, ${ biasSnippet } )`; } else {