diff --git a/examples/files.json b/examples/files.json index 39a4fc3528bac3cc9f8ab96e220f330c32e594ad..cf8be90ba78d1527361ce249c6230e8b6e80440b 100644 --- a/examples/files.json +++ b/examples/files.json @@ -268,7 +268,6 @@ "webgl_postprocessing_rgb_halftone", "webgl_postprocessing_masking", "webgl_postprocessing_ssaa", - "webgl_postprocessing_ssaa_unbiased", "webgl_postprocessing_outline", "webgl_postprocessing_pixel", "webgl_postprocessing_procedural", diff --git a/examples/screenshots/webgl_postprocessing_ssaa.jpg b/examples/screenshots/webgl_postprocessing_ssaa.jpg index 5de296cb2eb2e0c33833690f813c25a606f17d5a..13e9c8ce5c27a1fccb3cadbcb64270191b59410e 100644 Binary files a/examples/screenshots/webgl_postprocessing_ssaa.jpg and b/examples/screenshots/webgl_postprocessing_ssaa.jpg differ diff --git a/examples/screenshots/webgl_postprocessing_ssaa_unbiased.jpg b/examples/screenshots/webgl_postprocessing_ssaa_unbiased.jpg deleted file mode 100644 index 13e9c8ce5c27a1fccb3cadbcb64270191b59410e..0000000000000000000000000000000000000000 Binary files a/examples/screenshots/webgl_postprocessing_ssaa_unbiased.jpg and /dev/null differ diff --git a/examples/webgl_postprocessing_ssaa.html b/examples/webgl_postprocessing_ssaa.html index 3a076515e4c064b6542df383da276871c8e83478..b5e9d1d55558279fd0d06bcb1154036c5501ee67 100644 --- a/examples/webgl_postprocessing_ssaa.html +++ b/examples/webgl_postprocessing_ssaa.html @@ -1,16 +1,16 @@ - three.js webgl - postprocessing ssaa + three.js webgl - postprocessing manual ssaa
- three.js - Manual Supersampling Anti-Aliasing (SSAA) pass by Ben Houston

- This manual approach to SSAA re-renders the scene once for each sample with camera jitter and accumulates the results.

- Texture interpolation, mipmapping and anistropic sampling is disabled to emphasize
the effect SSAA levels have one the resulting render quality. + three.js - Unbiased Manual Supersamling Anti-Aliasing (SSAA) pass by Ben Houston

+ This example shows how to unbias the rounding errors accumulated using high number of SSAA samples on a 8-bit per channel buffer.

+ Turn off the "unbiased" feature to see the banding that results from accumulated rounding errors.
@@ -27,11 +27,20 @@ import { SSAARenderPass } from './jsm/postprocessing/SSAARenderPass.js'; import { CopyShader } from './jsm/shaders/CopyShader.js'; - let camera, scene, renderer, composer, copyPass, ssaaRenderPass; + let scene, renderer, composer, copyPass; + let cameraP, ssaaRenderPassP; + let cameraO, ssaaRenderPassO; let gui, stats; - const param = { - sampleLevel: 2 + const params = { + sampleLevel: 4, + renderToScreen: false, + unbiased: true, + camera: 'perspective', + clearColor: 'black', + clearAlpha: 1.0, + autoRotate: true + }; init(); @@ -45,7 +54,9 @@ gui = new GUI(); - gui.add( param, 'sampleLevel', { + gui.add( params, "unbiased" ); + gui.add( params, "renderToScreen" ); + gui.add( params, 'sampleLevel', { 'Level 0: 1 Sample': 0, 'Level 1: 2 Samples': 1, 'Level 2: 4 Samples': 2, @@ -53,6 +64,10 @@ 'Level 4: 16 Samples': 4, 'Level 5: 32 Samples': 5 } ); + gui.add( params, 'camera', [ 'perspective', 'orthographic' ] ); + gui.add( params, "clearColor", [ 'black', 'white', 'blue', 'green', 'red' ] ); + gui.add( params, "clearAlpha", 0, 1 ); + gui.add( params, "autoRotate" ); gui.open(); @@ -62,46 +77,87 @@ const container = document.getElementById( "container" ); + const width = window.innerWidth || 1; + const height = window.innerHeight || 1; + const aspect = width / height; + const devicePixelRatio = window.devicePixelRatio || 1; + renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio( window.devicePixelRatio ); - renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setPixelRatio( devicePixelRatio ); + renderer.setSize( width, height ); document.body.appendChild( renderer.domElement ); stats = new Stats(); container.appendChild( stats.dom ); - camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); - camera.position.z = 300; + cameraP = new THREE.PerspectiveCamera( 65, aspect, 3, 10 ); + cameraP.position.z = 7; + + cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 3, 10 ); + cameraO.position.z = 7; + + const fov = THREE.MathUtils.degToRad( cameraP.fov ); + const hyperfocus = ( cameraP.near + cameraP.far ) / 2; + const _height = 2 * Math.tan( fov / 2 ) * hyperfocus; + cameraO.zoom = height / _height; + scene = new THREE.Scene(); - const geometry = new THREE.BoxBufferGeometry( 120, 120, 120 ); - const material1 = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } ); + const group = new THREE.Group(); + scene.add( group ); - const mesh1 = new THREE.Mesh( geometry, material1 ); - mesh1.position.x = - 100; - scene.add( mesh1 ); + const light = new THREE.PointLight( 0xddffdd, 1.0 ); + light.position.z = 70; + light.position.y = - 70; + light.position.x = - 70; + scene.add( light ); - const texture = new THREE.TextureLoader().load( "textures/brick_diffuse.jpg" ); - texture.minFilter = THREE.NearestFilter; - texture.magFilter = THREE.NearestFilter; - texture.anisotropy = 1; - texture.generateMipmaps = false; + const light2 = new THREE.PointLight( 0xffdddd, 1.0 ); + light2.position.z = 70; + light2.position.x = - 70; + light2.position.y = 70; + scene.add( light2 ); - const material2 = new THREE.MeshBasicMaterial( { map: texture } ); + const light3 = new THREE.PointLight( 0xddddff, 1.0 ); + light3.position.z = 70; + light3.position.x = 70; + light3.position.y = - 70; + scene.add( light3 ); - const mesh2 = new THREE.Mesh( geometry, material2 ); - mesh2.position.x = 100; - scene.add( mesh2 ); + const light4 = new THREE.AmbientLight( 0xffffff, 0.05 ); + scene.add( light4 ); - // postprocessing + const geometry = new THREE.SphereBufferGeometry( 3, 48, 24 ); - composer = new EffectComposer( renderer ); + for ( let i = 0; i < 120; i ++ ) { + + const material = new THREE.MeshStandardMaterial(); + material.roughness = 0.5 * Math.random() + 0.25; + material.metalness = 0; + material.color.setHSL( Math.random(), 1.0, 0.3 ); + + const mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = Math.random() * 4 - 2; + mesh.position.y = Math.random() * 4 - 2; + mesh.position.z = Math.random() * 4 - 2; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.rotation.z = Math.random(); + + mesh.scale.setScalar( Math.random() * 0.2 + 0.05 ); + group.add( mesh ); - ssaaRenderPass = new SSAARenderPass( scene, camera ); - ssaaRenderPass.unbiased = false; - composer.addPass( ssaaRenderPass ); + } + + // postprocessing + composer = new EffectComposer( renderer ); + composer.setPixelRatio( 1 ); // ensure pixel ratio is always 1 for performance reasons + ssaaRenderPassP = new SSAARenderPass( scene, cameraP ); + composer.addPass( ssaaRenderPassP ); + ssaaRenderPassO = new SSAARenderPass( scene, cameraO ); + composer.addPass( ssaaRenderPassO ); copyPass = new ShaderPass( CopyShader ); composer.addPass( copyPass ); @@ -113,9 +169,16 @@ const width = window.innerWidth; const height = window.innerHeight; + const aspect = width / height; + + cameraP.aspect = aspect; + cameraO.updateProjectionMatrix(); - camera.aspect = width / height; - camera.updateProjectionMatrix(); + cameraO.left = - height * aspect; + cameraO.right = height * aspect; + cameraO.top = height; + cameraO.bottom = - height; + cameraO.updateProjectionMatrix(); renderer.setSize( width, height ); composer.setSize( width, height ); @@ -128,18 +191,44 @@ stats.begin(); - for ( let i = 0; i < scene.children.length; i ++ ) { + if ( params.autoRotate ) { + + for ( let i = 0; i < scene.children.length; i ++ ) { + + const child = scene.children[ i ]; - const child = scene.children[ i ]; + child.rotation.x += 0.005; + child.rotation.y += 0.01; - child.rotation.x += 0.005; - child.rotation.y += 0.01; + } } - ssaaRenderPass.sampleLevel = param.sampleLevel; + let newColor = ssaaRenderPassP.clearColor; + + switch ( params.clearColor ) { + + case 'blue': newColor = 0x0000ff; break; + case 'red': newColor = 0xff0000; break; + case 'green': newColor = 0x00ff00; break; + case 'white': newColor = 0xffffff; break; + case 'black': newColor = 0x000000; break; + + } + + ssaaRenderPassP.clearColor = ssaaRenderPassO.clearColor = newColor; + ssaaRenderPassP.clearAlpha = ssaaRenderPassO.clearAlpha = params.clearAlpha; + + ssaaRenderPassP.sampleLevel = ssaaRenderPassO.sampleLevel = params.sampleLevel; + ssaaRenderPassP.unbiased = ssaaRenderPassO.unbiased = params.unbiased; + + ssaaRenderPassP.enabled = ( params.camera === 'perspective' ); + ssaaRenderPassO.enabled = ( params.camera === 'orthographic' ); + + copyPass.enabled = ! params.renderToScreen; composer.render(); + stats.end(); } diff --git a/examples/webgl_postprocessing_ssaa_unbiased.html b/examples/webgl_postprocessing_ssaa_unbiased.html deleted file mode 100644 index b5e9d1d55558279fd0d06bcb1154036c5501ee67..0000000000000000000000000000000000000000 --- a/examples/webgl_postprocessing_ssaa_unbiased.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - three.js webgl - postprocessing manual ssaa - - - - - -
- three.js - Unbiased Manual Supersamling Anti-Aliasing (SSAA) pass by Ben Houston

- This example shows how to unbias the rounding errors accumulated using high number of SSAA samples on a 8-bit per channel buffer.

- Turn off the "unbiased" feature to see the banding that results from accumulated rounding errors. -
- -
- - - -