Skip to content
66 changes: 59 additions & 7 deletions src/nodes/pmrem/PMREMUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const textureCubeUV = /*@__PURE__*/ Fn( ( [ envMap, sampleDir_immutable,

} );

const bilinearCubeUV = /*@__PURE__*/ Fn( ( [ envMap, direction_immutable, mipInt_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => {
export const bilinearCubeUV = /*@__PURE__*/ Fn( ( [ envMap, direction_immutable, mipInt_immutable, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ] ) => {
Comment thread
elalish marked this conversation as resolved.

const mipInt = float( mipInt_immutable ).toVar();
const direction = vec3( direction_immutable );
Expand All @@ -241,7 +241,7 @@ const bilinearCubeUV = /*@__PURE__*/ Fn( ( [ envMap, direction_immutable, mipInt

} );

const getSample = /*@__PURE__*/ Fn( ( { envMap, mipInt, outputDirection, theta, axis, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => {
const getSample = /*@__PURE__*/ Fn( ( { envMap, outputDirection, theta, axis, sampler } ) => {

const cosTheta = cos( theta );

Expand All @@ -250,11 +250,11 @@ const getSample = /*@__PURE__*/ Fn( ( { envMap, mipInt, outputDirection, theta,
.add( axis.cross( outputDirection ).mul( sin( theta ) ) )
.add( axis.mul( axis.dot( outputDirection ).mul( cosTheta.oneMinus() ) ) );

return bilinearCubeUV( envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP );
return sampler( envMap, sampleDirection );

} );

export const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, weights, samples, dTheta, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => {
export const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, weights, samples, dTheta, envMap, sampler } ) => {

const axis = vec3( select( latitudinal, poleAxis, cross( poleAxis, outputDirection ) ) ).toVar();

Expand All @@ -267,7 +267,7 @@ export const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirect
axis.assign( normalize( axis ) );

const gl_FragColor = vec3().toVar();
gl_FragColor.addAssign( weights.element( int( 0 ) ).mul( getSample( { theta: 0.0, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) );
gl_FragColor.addAssign( weights.element( int( 0 ) ).mul( getSample( { theta: 0.0, axis, outputDirection, envMap, sampler } ) ) );

Loop( { start: int( 1 ), end: n }, ( { i } ) => {

Expand All @@ -278,11 +278,63 @@ export const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirect
} );

const theta = float( dTheta.mul( float( i ) ) ).toVar();
gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta: theta.mul( - 1.0 ), axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) );
gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta, axis, outputDirection, mipInt, envMap, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) ) );
gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta: theta.mul( - 1.0 ), axis, outputDirection, envMap, sampler } ) ) );
gl_FragColor.addAssign( weights.element( i ).mul( getSample( { theta, axis, outputDirection, envMap, sampler } ) ) );

} );

return vec4( gl_FragColor, 1 );

} );

export const getBlurParams=(sigmaRadians, cubeRes, maxSamples)=>{
// Number of standard deviations at which to cut off the discrete approximation.
const STANDARD_DEVIATIONS = 3;

const radiansPerPixel = Math.PI / ( 2 * cubeRes );
const sigmaPixels = sigmaRadians / radiansPerPixel;
const samples =1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels );

if ( samples > maxSamples ) {

console.warn( `sigmaRadians, ${
sigmaRadians}, is too large and will clip, as it requested ${
samples} samples when the maximum is set to ${maxSamples}` );

}

const weights = [];
let sum = 0;

for ( let i = 0; i < maxSamples; ++ i ) {

if(i>=samples){
weights.push(0);
continue;
}

const x = i / sigmaPixels;
const weight = Math.exp( - x * x / 2 );
weights.push( weight );

if ( i === 0 ) {

sum += weight;

} else {

sum += 2 * weight;

}

}

for ( let i = 0; i < weights.length; i ++ ) {

weights[ i ] = weights[ i ] / sum;

}

return {radiansPerPixel, samples, weights};

};
29 changes: 29 additions & 0 deletions src/renderers/common/CubeRenderTarget.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CubeCamera } from '../../cameras/CubeCamera.js';
import { BoxGeometry } from '../../geometries/BoxGeometry.js';
import { Mesh } from '../../objects/Mesh.js';
import { BackSide, NoBlending, LinearFilter, LinearMipmapLinearFilter } from '../../constants.js';
import {cubeTexture as TSL_CubeTexture} from '../../nodes/accessors/CubeTextureNode.js';

// @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget

Expand Down Expand Up @@ -72,6 +73,34 @@ class CubeRenderTarget extends WebGLCubeRenderTarget {

}

fromBlur(renderer, cubeMap, sigma){
const blurTarget1=new CubeRenderTarget(this.width);

const geometry = new BoxGeometry( 5, 5, 5 );

const blurMaterial = new NodeMaterial();
blurMaterial.colorNode = TSL_CubeTexture(cubeMap, positionWorldDirection, 0);
blurMaterial.side = BackSide;
blurMaterial.depthTest = false;
blurMaterial.depthWrite = false;
blurMaterial.blending = NoBlending;

const mesh = new Mesh( geometry, blurMaterial );

const scene = new Scene();
scene.add( mesh );

const camera = new CubeCamera( 1, 10, blurTarget1 );

camera.update( renderer, scene );

camera.renderTarget=this;

camera.update( renderer, scene );

blurTarget1.dispose();
}

}

export default CubeRenderTarget;
14 changes: 7 additions & 7 deletions src/renderers/common/extras/PMREMGenerator.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import NodeMaterial from '../../../materials/nodes/NodeMaterial.js';
import { getDirection, blur } from '../../../nodes/pmrem/PMREMUtils.js';
import { getDirection, blur, bilinearCubeUV } from '../../../nodes/pmrem/PMREMUtils.js';
import { equirectUV } from '../../../nodes/utils/EquirectUVNode.js';
import { uniform } from '../../../nodes/core/UniformNode.js';
import { uniformArray } from '../../../nodes/accessors/UniformArrayNode.js';
import { texture } from '../../../nodes/accessors/TextureNode.js';
import { cubeTexture } from '../../../nodes/accessors/CubeTextureNode.js';
import { float, vec3 } from '../../../nodes/tsl/TSLBase.js';
import { float, vec3, Fn } from '../../../nodes/tsl/TSLBase.js';
import { uv } from '../../../nodes/accessors/UV.js';
import { attribute } from '../../../nodes/core/AttributeNode.js';

Expand Down Expand Up @@ -833,15 +833,15 @@ function _getBlurShader( lodMax, width, height ) {
dTheta,
samples,
envMap,
mipInt,
CUBEUV_TEXEL_WIDTH,
CUBEUV_TEXEL_HEIGHT,
CUBEUV_MAX_MIP
mipInt
};

const material = _getMaterial( 'blur' );
material.uniforms = materialUniforms; // TODO: Move to outside of the material
material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ) } );
const cubeUVsampler=Fn((envMap, sampleDirection)=>{
return bilinearCubeUV( envMap, sampleDirection, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP );
});
material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ), sampler: cubeUVsampler } );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the heart of the refactor I'm attempting - make the sampling function something that can be passed in so I can use different ones for a CubeUV texture vs an actual CubeTexture.


return material;

Expand Down