|
| 1 | +/** |
| 2 | + * @author mrdoob / http://mrdoob.com/ |
| 3 | + * @author greggman / http://games.greggman.com/ |
| 4 | + * @author zz85 / http://www.lab4games.net/zz85/blog |
| 5 | + * @author kaypiKun |
| 6 | + */ |
| 7 | + |
| 8 | +THREE.CinematicCamera = function ( fov, aspect, near, far ) { |
| 9 | + |
| 10 | + THREE.PerspectiveCamera.call( this, fov, aspect, near, far ); |
| 11 | + |
| 12 | + this.type = 'CinematicCamera'; |
| 13 | + |
| 14 | + this.postprocessing = { enabled: true }; |
| 15 | + this.shaderSettings = { |
| 16 | + rings: 3, |
| 17 | + samples: 4 |
| 18 | + }; |
| 19 | + |
| 20 | + var depthShader = THREE.BokehDepthShader; |
| 21 | + |
| 22 | + this.materialDepth = new THREE.ShaderMaterial( { |
| 23 | + uniforms: depthShader.uniforms, |
| 24 | + vertexShader: depthShader.vertexShader, |
| 25 | + fragmentShader: depthShader.fragmentShader |
| 26 | + } ); |
| 27 | + |
| 28 | + this.materialDepth.uniforms[ 'mNear' ].value = near; |
| 29 | + this.materialDepth.uniforms[ 'mFar' ].value = far; |
| 30 | + |
| 31 | + // In case of cinematicCamera, having a default lens set is important |
| 32 | + this.setLens(); |
| 33 | + |
| 34 | + this.initPostProcessing(); |
| 35 | + |
| 36 | +}; |
| 37 | + |
| 38 | +THREE.CinematicCamera.prototype = Object.create( THREE.PerspectiveCamera.prototype ); |
| 39 | +THREE.CinematicCamera.prototype.constructor = THREE.CinematicCamera; |
| 40 | + |
| 41 | + |
| 42 | +// providing fnumber and coc(Circle of Confusion) as extra arguments |
| 43 | +THREE.CinematicCamera.prototype.setLens = function ( focalLength, filmGauge, fNumber, coc ) { |
| 44 | + |
| 45 | + // In case of cinematicCamera, having a default lens set is important |
| 46 | + if ( focalLength === undefined ) focalLength = 35; |
| 47 | + if ( filmGauge !== undefined ) this.filmGauge = filmGauge; |
| 48 | + |
| 49 | + this.setFocalLength( focalLength ); |
| 50 | + |
| 51 | + // if fnumber and coc are not provided, cinematicCamera tries to act as a basic PerspectiveCamera |
| 52 | + if ( fNumber === undefined ) fNumber = 8; |
| 53 | + if ( coc === undefined ) coc = 0.019; |
| 54 | + |
| 55 | + this.fNumber = fNumber; |
| 56 | + this.coc = coc; |
| 57 | + |
| 58 | + // fNumber is focalLength by aperture |
| 59 | + this.aperture = focalLength / this.fNumber; |
| 60 | + |
| 61 | + // hyperFocal is required to calculate depthOfField when a lens tries to focus at a distance with given fNumber and focalLength |
| 62 | + this.hyperFocal = ( focalLength * focalLength ) / ( this.aperture * this.coc ); |
| 63 | + |
| 64 | +}; |
| 65 | + |
| 66 | +THREE.CinematicCamera.prototype.linearize = function ( depth ) { |
| 67 | + |
| 68 | + var zfar = this.far; |
| 69 | + var znear = this.near; |
| 70 | + return - zfar * znear / ( depth * ( zfar - znear ) - zfar ); |
| 71 | + |
| 72 | +}; |
| 73 | + |
| 74 | +THREE.CinematicCamera.prototype.smoothstep = function ( near, far, depth ) { |
| 75 | + |
| 76 | + var x = this.saturate( ( depth - near ) / ( far - near ) ); |
| 77 | + return x * x * ( 3 - 2 * x ); |
| 78 | + |
| 79 | +}; |
| 80 | + |
| 81 | +THREE.CinematicCamera.prototype.saturate = function ( x ) { |
| 82 | + |
| 83 | + return Math.max( 0, Math.min( 1, x ) ); |
| 84 | + |
| 85 | +}; |
| 86 | + |
| 87 | +// function for focusing at a distance from the camera |
| 88 | +THREE.CinematicCamera.prototype.focusAt = function ( focusDistance ) { |
| 89 | + |
| 90 | + if ( focusDistance === undefined ) focusDistance = 20; |
| 91 | + |
| 92 | + var focalLength = this.getFocalLength(); |
| 93 | + |
| 94 | + // distance from the camera (normal to frustrum) to focus on |
| 95 | + this.focus = focusDistance; |
| 96 | + |
| 97 | + // the nearest point from the camera which is in focus (unused) |
| 98 | + this.nearPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal + ( this.focus - focalLength ) ); |
| 99 | + |
| 100 | + // the farthest point from the camera which is in focus (unused) |
| 101 | + this.farPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal - ( this.focus - focalLength ) ); |
| 102 | + |
| 103 | + // the gap or width of the space in which is everything is in focus (unused) |
| 104 | + this.depthOfField = this.farPoint - this.nearPoint; |
| 105 | + |
| 106 | + // Considering minimum distance of focus for a standard lens (unused) |
| 107 | + if ( this.depthOfField < 0 ) this.depthOfField = 0; |
| 108 | + |
| 109 | + this.sdistance = this.smoothstep( this.near, this.far, this.focus ); |
| 110 | + |
| 111 | + this.ldistance = this.linearize( 1 - this.sdistance ); |
| 112 | + |
| 113 | + this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance; |
| 114 | + |
| 115 | +}; |
| 116 | + |
| 117 | +THREE.CinematicCamera.prototype.initPostProcessing = function () { |
| 118 | + |
| 119 | + if ( this.postprocessing.enabled ) { |
| 120 | + |
| 121 | + this.postprocessing.scene = new THREE.Scene(); |
| 122 | + |
| 123 | + this.postprocessing.camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 ); |
| 124 | + |
| 125 | + this.postprocessing.scene.add( this.postprocessing.camera ); |
| 126 | + |
| 127 | + var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat }; |
| 128 | + this.postprocessing.rtTextureDepth = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars ); |
| 129 | + this.postprocessing.rtTextureColor = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars ); |
| 130 | + |
| 131 | + var bokeh_shader = THREE.BokehShader; |
| 132 | + |
| 133 | + this.postprocessing.bokeh_uniforms = THREE.UniformsUtils.clone( bokeh_shader.uniforms ); |
| 134 | + |
| 135 | + this.postprocessing.bokeh_uniforms[ "tColor" ].value = this.postprocessing.rtTextureColor.texture; |
| 136 | + this.postprocessing.bokeh_uniforms[ "tDepth" ].value = this.postprocessing.rtTextureDepth.texture; |
| 137 | + |
| 138 | + this.postprocessing.bokeh_uniforms[ "manualdof" ].value = 0; |
| 139 | + this.postprocessing.bokeh_uniforms[ "shaderFocus" ].value = 0; |
| 140 | + |
| 141 | + this.postprocessing.bokeh_uniforms[ "fstop" ].value = 2.8; |
| 142 | + |
| 143 | + this.postprocessing.bokeh_uniforms[ "showFocus" ].value = 1; |
| 144 | + |
| 145 | + this.postprocessing.bokeh_uniforms[ "focalDepth" ].value = 0.1; |
| 146 | + |
| 147 | + //console.log( this.postprocessing.bokeh_uniforms[ "focalDepth" ].value ); |
| 148 | + |
| 149 | + this.postprocessing.bokeh_uniforms[ "znear" ].value = this.near; |
| 150 | + this.postprocessing.bokeh_uniforms[ "zfar" ].value = this.near; |
| 151 | + |
| 152 | + |
| 153 | + this.postprocessing.bokeh_uniforms[ "textureWidth" ].value = window.innerWidth; |
| 154 | + |
| 155 | + this.postprocessing.bokeh_uniforms[ "textureHeight" ].value = window.innerHeight; |
| 156 | + |
| 157 | + this.postprocessing.materialBokeh = new THREE.ShaderMaterial( { |
| 158 | + uniforms: this.postprocessing.bokeh_uniforms, |
| 159 | + vertexShader: bokeh_shader.vertexShader, |
| 160 | + fragmentShader: bokeh_shader.fragmentShader, |
| 161 | + defines: { |
| 162 | + RINGS: this.shaderSettings.rings, |
| 163 | + SAMPLES: this.shaderSettings.samples, |
| 164 | + DEPTH_PACKING: 1 |
| 165 | + } |
| 166 | + } ); |
| 167 | + |
| 168 | + this.postprocessing.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( window.innerWidth, window.innerHeight ), this.postprocessing.materialBokeh ); |
| 169 | + this.postprocessing.quad.position.z = - 500; |
| 170 | + this.postprocessing.scene.add( this.postprocessing.quad ); |
| 171 | + |
| 172 | + } |
| 173 | + |
| 174 | +}; |
| 175 | + |
| 176 | +THREE.CinematicCamera.prototype.renderCinematic = function ( scene, renderer ) { |
| 177 | + |
| 178 | + if ( this.postprocessing.enabled ) { |
| 179 | + |
| 180 | + var currentRenderTarget = renderer.getRenderTarget(); |
| 181 | + |
| 182 | + renderer.clear(); |
| 183 | + |
| 184 | + // Render scene into texture |
| 185 | + |
| 186 | + scene.overrideMaterial = null; |
| 187 | + renderer.setRenderTarget( this.postprocessing.rtTextureColor ); |
| 188 | + renderer.clear(); |
| 189 | + renderer.render( scene, camera ); |
| 190 | + |
| 191 | + // Render depth into texture |
| 192 | + |
| 193 | + scene.overrideMaterial = this.materialDepth; |
| 194 | + renderer.setRenderTarget( this.postprocessing.rtTextureDepth ); |
| 195 | + renderer.clear(); |
| 196 | + renderer.render( scene, camera ); |
| 197 | + |
| 198 | + // Render bokeh composite |
| 199 | + |
| 200 | + renderer.setRenderTarget( null ); |
| 201 | + renderer.render( this.postprocessing.scene, this.postprocessing.camera ); |
| 202 | + |
| 203 | + renderer.setRenderTarget( currentRenderTarget ); |
| 204 | + |
| 205 | + } |
| 206 | + |
| 207 | +}; |
0 commit comments