diff --git a/examples/jsm/utils/RoughnessMipmapper.js b/examples/jsm/utils/RoughnessMipmapper.js index d30cee51f964120dbcfbb67bf001ac4bf17904f3..e38da6d9a2402190c05846162f537099ba39cc56 100644 --- a/examples/jsm/utils/RoughnessMipmapper.js +++ b/examples/jsm/utils/RoughnessMipmapper.js @@ -19,15 +19,19 @@ import { } from "../../../build/three.module.js"; var _mipmapMaterial = _getMipmapMaterial(); + var _mesh = new Mesh( new PlaneBufferGeometry( 2, 2 ), _mipmapMaterial ); var _flatCamera = new OrthographicCamera( 0, 1, 0, 1, 0, 1 ); + var _tempTarget = null; + var _renderer = null; function RoughnessMipmapper( renderer ) { _renderer = renderer; + _renderer.compile( _mesh, _flatCamera ); } @@ -39,62 +43,79 @@ RoughnessMipmapper.prototype = { generateMipmaps: function ( material ) { var { roughnessMap, normalMap } = material; - if ( roughnessMap == null || normalMap == null || ! roughnessMap.generateMipmaps || - material.userData.roughnessUpdated ) return; + + if ( roughnessMap === null || normalMap === null || ! roughnessMap.generateMipmaps || material.userData.roughnessUpdated ) return; material.userData.roughnessUpdated = true; var width = Math.max( roughnessMap.image.width, normalMap.image.width ); + var height = Math.max( roughnessMap.image.height, normalMap.image.height ); + if ( ! MathUtils.isPowerOfTwo( width ) || ! MathUtils.isPowerOfTwo( height ) ) return; var oldTarget = _renderer.getRenderTarget(); + var autoClear = _renderer.autoClear; + _renderer.autoClear = false; - if ( _tempTarget == null || _tempTarget.width !== width || _tempTarget.height !== height ) { + if ( _tempTarget === null || _tempTarget.width !== width || _tempTarget.height !== height ) { - if ( _tempTarget != null ) _tempTarget.dispose(); + if ( _tempTarget !== null ) _tempTarget.dispose(); _tempTarget = new WebGLRenderTarget( width, height, { depthBuffer: false } ); + _tempTarget.scissorTest = true; } if ( width !== roughnessMap.image.width || height !== roughnessMap.image.height ) { - var newRoughnessTarget = new WebGLRenderTarget( width, height, { - minFilter: LinearMipMapLinearFilter, - depthBuffer: false - } ); + var newRoughnessTarget = new WebGLRenderTarget( width, height, { minFilter: LinearMipMapLinearFilter, depthBuffer: false } ); + newRoughnessTarget.texture.generateMipmaps = true; + // Setting the render target causes the memory to be allocated. + _renderer.setRenderTarget( newRoughnessTarget ); + material.roughnessMap = newRoughnessTarget.texture; + if ( material.metalnessMap == roughnessMap ) material.metalnessMap = material.roughnessMap; + if ( material.aoMap == roughnessMap ) material.aoMap = material.roughnessMap; } _mipmapMaterial.uniforms.roughnessMap.value = roughnessMap; + _mipmapMaterial.uniforms.normalMap.value = normalMap; var position = new Vector2( 0, 0 ); + var texelSize = _mipmapMaterial.uniforms.texelSize.value; - for ( var mip = 0; width >= 1 && height >= 1; - ++ mip, width /= 2, height /= 2 ) { + + for ( var mip = 0; width >= 1 && height >= 1; ++ mip, width /= 2, height /= 2 ) { // Rendering to a mip level is not allowed in webGL1. Instead we must set // up a secondary texture to write the result to, then copy it back to the // proper mipmap level. + texelSize.set( 1.0 / width, 1.0 / height ); + if ( mip == 0 ) texelSize.set( 0.0, 0.0 ); _tempTarget.viewport.set( position.x, position.y, width, height ); + _tempTarget.scissor.set( position.x, position.y, width, height ); + _renderer.setRenderTarget( _tempTarget ); + _renderer.render( _mesh, _flatCamera ); + _renderer.copyFramebufferToTexture( position, material.roughnessMap, mip ); + _mipmapMaterial.uniforms.roughnessMap.value = material.roughnessMap; } @@ -102,6 +123,7 @@ RoughnessMipmapper.prototype = { if ( roughnessMap !== material.roughnessMap ) roughnessMap.dispose(); _renderer.setRenderTarget( oldTarget ); + _renderer.autoClear = autoClear; }, @@ -109,7 +131,9 @@ RoughnessMipmapper.prototype = { dispose: function () { _mipmapMaterial.dispose(); + _mesh.geometry.dispose(); + if ( _tempTarget != null ) _tempTarget.dispose(); } @@ -129,69 +153,119 @@ function _getMipmapMaterial() { vertexShader: /* glsl */` precision mediump float; precision mediump int; + attribute vec3 position; attribute vec2 uv; + varying vec2 vUv; + void main() { + vUv = uv; + gl_Position = vec4( position, 1.0 ); + } `, fragmentShader: /* glsl */` precision mediump float; precision mediump int; + varying vec2 vUv; + uniform sampler2D roughnessMap; uniform sampler2D normalMap; uniform vec2 texelSize; #define ENVMAP_TYPE_CUBE_UV - vec4 envMapTexelToLinear(vec4 a){return a;} + + vec4 envMapTexelToLinear( vec4 a ) { return a; } + #include - float roughnessToVariance(float roughness) { + float roughnessToVariance( float roughness ) { + float variance = 0.0; - if (roughness >= r1) { - variance = (r0 - roughness) * (v1 - v0) / (r0 - r1) + v0; - } else if (roughness >= r4) { - variance = (r1 - roughness) * (v4 - v1) / (r1 - r4) + v1; - } else if (roughness >= r5) { - variance = (r4 - roughness) * (v5 - v4) / (r4 - r5) + v4; + + if ( roughness >= r1 ) { + + variance = ( r0 - roughness ) * ( v1 - v0 ) / ( r0 - r1 ) + v0; + + } else if ( roughness >= r4 ) { + + variance = ( r1 - roughness ) * ( v4 - v1 ) / ( r1 - r4 ) + v1; + + } else if ( roughness >= r5 ) { + + variance = ( r4 - roughness ) * ( v5 - v4 ) / ( r4 - r5 ) + v4; + } else { + float roughness2 = roughness * roughness; + variance = 1.79 * roughness2 * roughness2; + } + return variance; + } - float varianceToRoughness(float variance) { + + float varianceToRoughness( float variance ) { + float roughness = 0.0; - if (variance >= v1) { - roughness = (v0 - variance) * (r1 - r0) / (v0 - v1) + r0; - } else if (variance >= v4) { - roughness = (v1 - variance) * (r4 - r1) / (v1 - v4) + r1; - } else if (variance >= v5) { - roughness = (v4 - variance) * (r5 - r4) / (v4 - v5) + r4; + + if ( variance >= v1 ) { + + roughness = ( v0 - variance ) * ( r1 - r0 ) / ( v0 - v1 ) + r0; + + } else if ( variance >= v4 ) { + + roughness = ( v1 - variance ) * ( r4 - r1 ) / ( v1 - v4 ) + r1; + + } else if ( variance >= v5 ) { + + roughness = ( v4 - variance ) * ( r5 - r4 ) / ( v4 - v5 ) + r4; + } else { - roughness = pow(0.559 * variance, 0.25);// 0.559 = 1.0 / 1.79 + + roughness = pow( 0.559 * variance, 0.25 ); // 0.559 = 1.0 / 1.79 + } + return roughness; + } void main() { - gl_FragColor = texture2D(roughnessMap, vUv, -1.0); - if (texelSize.x == 0.0) return; + + gl_FragColor = texture2D( roughnessMap, vUv, - 1.0 ); + + if ( texelSize.x == 0.0 ) return; + float roughness = gl_FragColor.g; - float variance = roughnessToVariance(roughness); + + float variance = roughnessToVariance( roughness ); + vec3 avgNormal; - for (float x = -1.0; x < 2.0; x += 2.0) { - for (float y = -1.0; y < 2.0; y += 2.0) { - vec2 uv = vUv + vec2(x, y) * 0.25 * texelSize; - avgNormal += normalize(texture2D(normalMap, uv, -1.0).xyz - 0.5); + + for ( float x = - 1.0; x < 2.0; x += 2.0 ) { + + for ( float y = - 1.0; y < 2.0; y += 2.0 ) { + + vec2 uv = vUv + vec2( x, y ) * 0.25 * texelSize; + + avgNormal += normalize( texture2D( normalMap, uv, - 1.0 ).xyz - 0.5 ); + } + } - variance += 1.0 - 0.25 * length(avgNormal); - gl_FragColor.g = varianceToRoughness(variance); + + variance += 1.0 - 0.25 * length( avgNormal ); + + gl_FragColor.g = varianceToRoughness( variance ); + } `,