UNPKG

6.7 kBJavaScriptView Raw
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
8THREE.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
38THREE.CinematicCamera.prototype = Object.create( THREE.PerspectiveCamera.prototype );
39THREE.CinematicCamera.prototype.constructor = THREE.CinematicCamera;
40
41
42// providing fnumber and coc(Circle of Confusion) as extra arguments
43THREE.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
66THREE.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
74THREE.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
81THREE.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
88THREE.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
117THREE.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
176THREE.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, this );
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, this );
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};