framework2
408 строк · 17.2 Кб
1/*
2* DofPass.cpp
3*
4* Copyright (c) 2012, Neil Mendoza, http://www.neilmendoza.com
5* All rights reserved.
6*
7* Redistribution and use in source and binary forms, with or without
8* modification, are permitted provided that the following conditions are met:
9*
10* * Redistributions of source code must retain the above copyright notice,
11* this list of conditions and the following disclaimer.
12* * Redistributions in binary form must reproduce the above copyright
13* notice, this list of conditions and the following disclaimer in the
14* documentation and/or other materials provided with the distribution.
15* * Neither the name of Neil Mendoza nor the names of its contributors may be used
16* to endorse or promote products derived from this software without
17* specific prior written permission.
18*
19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29* POSSIBILITY OF SUCH DAMAGE.
30*
31*/
32#include "DofAltPass.h"
33
34namespace itg
35{
36DofAltPass::DofAltPass(const ofVec2f& aspect, bool arb, float focalDepth, float focalLength, float fStop, bool showFocus) :
37focalDepth(focalDepth), focalLength(focalLength), fStop(fStop), showFocus(showFocus), RenderPass(aspect, arb, "dofalt")
38{
39string fragShaderSrc = STRINGIFY(
40/*
41DoF with bokeh GLSL shader v2.4
42by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com)
43
44----------------------
45The shader is Blender Game Engine ready, but it should be quite simple to adapt for your engine.
46
47This work is licensed under a Creative Commons Attribution 3.0 Unported License.
48So you are free to share, modify and adapt it for your needs, and even use it for commercial use.
49I would also love to hear about a project you are using it.
50
51Have fun,
52Martins
53----------------------
54
55changelog:
56
572.4:
58- physically accurate DoF simulation calculated from "focalDepth" ,"focalLength", "f-stop" and "CoC" parameters.
59- option for artist controlled DoF simulation calculated only from "focalDepth" and individual controls for near and far blur
60- added "circe of confusion" (CoC) parameter in mm to accurately simulate DoF with different camera sensor or film sizes
61- cleaned up the code
62- some optimization
63
642.3:
65- new and physically little more accurate DoF
66- two extra input variables - focal length and aperture iris diameter
67- added a debug visualization of focus point and focal range
68
692.1:
70- added an option for pentagonal bokeh shape
71- minor fixes
72
732.0:
74- variable sample count to increase quality/performance
75- option to blur depth buffer to reduce hard edges
76- option to dither the samples with noise or pattern
77- bokeh chromatic aberration/fringing
78- bokeh bias to bring out bokeh edges
79- image thresholding to bring out highlights when image is out of focus
80
81*/
82
83uniform sampler2D bgl_RenderedTexture;
84uniform sampler2D bgl_DepthTexture;
85uniform float bgl_RenderedTextureWidth;
86uniform float bgl_RenderedTextureHeight;
87
88const float PI = 3.14159265;
89
90float width = bgl_RenderedTextureWidth; //texture width
91float height = bgl_RenderedTextureHeight; //texture height
92
93vec2 texel = vec2(1.0/width,1.0/height);
94
95//uniform variables from external script
96
97uniform float focalDepth; //focal distance value in meters, but you may use autofocus option below
98uniform float focalLength; //focal length in mm
99uniform float fstop; //f-stop value
100uniform bool showFocus; //show debug focus point and focal range (red = focal point, green = focal range)
101
102/*
103make sure that these two values are the same for your camera, otherwise distances will be wrong.
104*/
105
106float znear = 0.1; //camera clipping start
107float zfar = 100.0; //camera clipping end
108
109//------------------------------------------
110//user variables
111
112int samples = 3; //samples on the first ring
113int rings = 3; //ring count
114
115bool manualdof = false; //manual dof calculation
116float ndofstart = 1.0; //near dof blur start
117float ndofdist = 2.0; //near dof blur falloff distance
118float fdofstart = 1.0; //far dof blur start
119float fdofdist = 3.0; //far dof blur falloff distance
120
121float CoC = 0.03;//circle of confusion size in mm (35mm film = 0.03mm)
122
123bool vignetting = true; //use optical lens vignetting?
124float vignout = 1.3; //vignetting outer border
125float vignin = 0.0; //vignetting inner border
126float vignfade = 22.0; //f-stops till vignete fades
127
128bool autofocus = false; //use autofocus in shader? disable if you use external focalDepth value
129vec2 focus = vec2(0.5,0.5); // autofocus point on screen (0.0,0.0 - left lower corner, 1.0,1.0 - upper right)
130float maxblur = 1.0; //clamp value of max blur (0.0 = no blur,1.0 default)
131
132float threshold = 0.5; //highlight threshold;
133float gain = 2.0; //highlight gain;
134
135float bias = 0.5; //bokeh edge bias
136float fringe = 0.7; //bokeh chromatic aberration/fringing
137
138bool noise = true; //use noise instead of pattern for sample dithering
139float namount = 0.0001; //dither amount
140
141bool depthblur = false; //blur the depth buffer?
142float dbsize = 1.25; //depthblursize
143
144/*
145next part is experimental
146not looking good with small sample and ring count
147looks okay starting from samples = 4, rings = 4
148*/
149
150bool pentagon = false; //use pentagon as bokeh shape?
151float feather = 0.4; //pentagon shape feather
152
153//------------------------------------------
154
155float penta(vec2 coords) //pentagonal shape
156{
157float scale = float(rings) - 1.3;
158vec4 HS0 = vec4( 1.0, 0.0, 0.0, 1.0);
159vec4 HS1 = vec4( 0.309016994, 0.951056516, 0.0, 1.0);
160vec4 HS2 = vec4(-0.809016994, 0.587785252, 0.0, 1.0);
161vec4 HS3 = vec4(-0.809016994,-0.587785252, 0.0, 1.0);
162vec4 HS4 = vec4( 0.309016994,-0.951056516, 0.0, 1.0);
163vec4 HS5 = vec4( 0.0 ,0.0 , 1.0, 1.0);
164
165vec4 one = vec4( 1.0 );
166
167vec4 P = vec4((coords),vec2(scale, scale));
168
169vec4 dist = vec4(0.0);
170float inorout = -4.0;
171
172dist.x = dot( P, HS0 );
173dist.y = dot( P, HS1 );
174dist.z = dot( P, HS2 );
175dist.w = dot( P, HS3 );
176
177dist = smoothstep( -feather, feather, dist );
178
179inorout += dot( dist, one );
180
181dist.x = dot( P, HS4 );
182dist.y = HS5.w - abs( P.z );
183
184dist = smoothstep( -feather, feather, dist );
185inorout += dist.x;
186
187return clamp( inorout, 0.0, 1.0 );
188}
189
190float bdepth(vec2 coords) //blurring depth
191{
192float d = 0.0;
193float kernel[9];
194vec2 offset[9];
195
196vec2 wh = vec2(texel.x, texel.y) * dbsize;
197
198offset[0] = vec2(-wh.x,-wh.y);
199offset[1] = vec2( 0.0, -wh.y);
200offset[2] = vec2( wh.x -wh.y);
201
202offset[3] = vec2(-wh.x, 0.0);
203offset[4] = vec2( 0.0, 0.0);
204offset[5] = vec2( wh.x, 0.0);
205
206offset[6] = vec2(-wh.x, wh.y);
207offset[7] = vec2( 0.0, wh.y);
208offset[8] = vec2( wh.x, wh.y);
209
210kernel[0] = 1.0/16.0; kernel[1] = 2.0/16.0; kernel[2] = 1.0/16.0;
211kernel[3] = 2.0/16.0; kernel[4] = 4.0/16.0; kernel[5] = 2.0/16.0;
212kernel[6] = 1.0/16.0; kernel[7] = 2.0/16.0; kernel[8] = 1.0/16.0;
213
214
215for( int i=0; i<9; i++ )
216{
217float tmp = texture2D(bgl_DepthTexture, coords + offset[i]).r;
218d += tmp * kernel[i];
219}
220
221return d;
222}
223
224
225vec3 color(vec2 coords,float blur) //processing the sample
226{
227vec3 col = vec3(0.0);
228
229col.r = texture2D(bgl_RenderedTexture,coords + vec2(0.0,1.0)*texel*fringe*blur).r;
230col.g = texture2D(bgl_RenderedTexture,coords + vec2(-0.866,-0.5)*texel*fringe*blur).g;
231col.b = texture2D(bgl_RenderedTexture,coords + vec2(0.866,-0.5)*texel*fringe*blur).b;
232
233vec3 lumcoeff = vec3(0.299,0.587,0.114);
234float lum = dot(col.rgb, lumcoeff);
235float thresh = max((lum-threshold)*gain, 0.0);
236return col+mix(vec3(0.0),col,thresh*blur);
237}
238
239vec2 rand(vec2 coord) //generating noise/pattern texture for dithering
240{
241float noiseX = ((fract(1.0-coord.s*(width/2.0))*0.25)+(fract(coord.t*(height/2.0))*0.75))*2.0-1.0;
242float noiseY = ((fract(1.0-coord.s*(width/2.0))*0.75)+(fract(coord.t*(height/2.0))*0.25))*2.0-1.0;
243
244if (noise)
245{
246noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0;
247noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0;
248}
249return vec2(noiseX,noiseY);
250}
251
252vec3 debugFocus(vec3 col, float blur, float depth)
253{
254float edge = 0.002*depth; //distance based edge smoothing
255float m = clamp(smoothstep(0.0,edge,blur),0.0,1.0);
256float e = clamp(smoothstep(1.0-edge,1.0,blur),0.0,1.0);
257
258col = mix(col,vec3(1.0,0.5,0.0),(1.0-m)*0.6);
259col = mix(col,vec3(0.0,0.5,1.0),((1.0-e)-(1.0-m))*0.2);
260
261return col;
262}
263
264float linearize(float depth)
265{
266return -zfar * znear / (depth * (zfar - znear) - zfar);
267}
268
269float vignette()
270{
271float dist = distance(gl_TexCoord[3].xy, vec2(0.5,0.5));
272dist = smoothstep(vignout+(fstop/vignfade), vignin+(fstop/vignfade), dist);
273return clamp(dist,0.0,1.0);
274}
275
276void main()
277{
278//scene depth calculation
279
280float depth = linearize(texture2D(bgl_DepthTexture,gl_TexCoord[0].xy).x);
281
282if (depthblur)
283{
284depth = linearize(bdepth(gl_TexCoord[0].xy));
285}
286
287//focal plane calculation
288
289float fDepth = focalDepth;
290
291if (autofocus)
292{
293fDepth = linearize(texture2D(bgl_DepthTexture,focus).x);
294}
295
296//dof blur factor calculation
297
298float blur = 0.0;
299
300if (manualdof)
301{
302float a = depth-fDepth; //focal plane
303float b = (a-fdofstart)/fdofdist; //far DoF
304float c = (-a-ndofstart)/ndofdist; //near Dof
305blur = (a>0.0)?b:c;
306}
307
308else
309{
310float f = focalLength; //focal length in mm
311float d = fDepth*1000.0; //focal plane in mm
312float o = depth*1000.0; //depth in mm
313
314float a = (o*f)/(o-f);
315float b = (d*f)/(d-f);
316float c = (d-f)/(d*fstop*CoC);
317
318blur = abs(a-b)*c;
319}
320
321blur = clamp(blur,0.0,1.0);
322
323// calculation of pattern for ditering
324
325vec2 noise = rand(gl_TexCoord[0].xy)*namount*blur;
326
327// getting blur x and y step factor
328
329float w = (1.0/width)*blur*maxblur+noise.x;
330float h = (1.0/height)*blur*maxblur+noise.y;
331
332// calculation of final color
333
334vec3 col = vec3(0.0);
335
336if(blur < 0.05) //some optimization thingy
337{
338col = texture2D(bgl_RenderedTexture, gl_TexCoord[0].xy).rgb;
339}
340
341else
342{
343col = texture2D(bgl_RenderedTexture, gl_TexCoord[0].xy).rgb;
344float s = 1.0;
345int ringsamples;
346
347for (int i = 1; i <= rings; i += 1)
348{
349ringsamples = i * samples;
350
351for (int j = 0 ; j < ringsamples ; j += 1)
352{
353float step = PI*2.0 / float(ringsamples);
354float pw = (cos(float(j)*step)*float(i));
355float ph = (sin(float(j)*step)*float(i));
356float p = 1.0;
357if (pentagon)
358{
359p = penta(vec2(pw,ph));
360}
361col += color(gl_TexCoord[0].xy + vec2(pw*w,ph*h),blur)*mix(1.0,(float(i))/(float(rings)),bias)*p;
362s += 1.0*mix(1.0,(float(i))/(float(rings)),bias)*p;
363}
364}
365col /= s; //divide by sample count
366}
367
368if (showFocus)
369{
370col = debugFocus(col, blur, depth);
371}
372
373if (vignetting)
374{
375col *= vignette();
376}
377
378gl_FragColor.rgb = col;
379gl_FragColor.a = 1.0;
380}
381);
382
383shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragShaderSrc);
384shader.linkProgram();
385}
386
387void DofAltPass::render(ofFbo& readFbo, ofFbo& writeFbo, ofTexture& depth)
388{
389writeFbo.begin();
390
391shader.begin();
392
393shader.setUniformTexture("bgl_RenderedTexture", readFbo.getTexture(), 0);
394shader.setUniformTexture("bgl_DepthTexture", depth, 1);
395shader.setUniform1f("bgl_RenderedTextureWidth", aspect.x);
396shader.setUniform1f("bgl_RenderedTextureHeight", aspect.y);
397
398shader.setUniform1f("focalDepth", focalDepth); //focal distance value in meters, but you may use autofocus option below
399shader.setUniform1f("focalLength", focalLength); //focal length in mm
400shader.setUniform1f("fstop", fStop); //f-stop value
401shader.setUniform1f("showFocus", showFocus); //show debug focus point and focal range (red = focal point, green = focal range)
402
403texturedQuad(0, 0, writeFbo.getWidth(), writeFbo.getHeight());
404
405shader.end();
406writeFbo.end();
407}
408}