framework2
255 строк · 9.7 Кб
1/*
2* SSAOPass.h
3*
4* Copyright (c) 2013, satcy, http://satcy.net
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 "SSAOPass.h"
33#include "ofMain.h"
34
35namespace itg
36{
37SSAOPass::SSAOPass(const ofVec2f& aspect, bool arb, const char * customVertexShader, const char * customFragmentShader, float cameraNear, float cameraFar, float fogNear, float fogFar, bool fogEnabled, bool onlyAO, float aoClamp, float lumInfluence) :
38cameraNear(cameraNear), cameraFar(cameraFar), fogNear(fogNear), fogFar(fogFar), fogEnabled(fogEnabled), onlyAO(onlyAO), aoClamp(aoClamp), lumInfluence(lumInfluence), RenderPass(aspect, arb, "SSAO")
39{
40string fragShaderSrc = "";
41
42if (customFragmentShader == NULL) {
43fragShaderSrc = STRINGIFY(
44uniform float cameraNear;
45uniform float cameraFar;
46
47uniform float fogNear;
48uniform float fogFar;
49
50uniform bool fogEnabled; // attenuate AO with linear fog
51uniform bool onlyAO; // use only ambient occlusion pass?
52
53uniform vec2 size; // texture width, height
54uniform float aoClamp; // depth clamp - reduces haloing at screen edges
55
56uniform float lumInfluence; // how much luminance affects occlusion
57
58uniform sampler2D tDiffuse;
59uniform sampler2D tDepth;
60
61//const float PI = 3.14159265;
62const float DL = 2.399963229728653; // PI * ( 3.0 - sqrt( 5.0 ) )
63const float EULER = 2.718281828459045;
64
65// helpers
66
67float width = size.x; // texture width
68float height = size.y; // texture height
69
70float cameraFarPlusNear = cameraFar + cameraNear;
71float cameraFarMinusNear = cameraFar - cameraNear;
72float cameraCoef = 2.0 * cameraNear;
73
74// user variables
75
76const int samples = 8; // ao sample count
77const float radius = 5.0; // ao radius
78
79const bool useNoise = true; // use noise instead of pattern for sample dithering
80const float noiseAmount = 0.0003; // dithering amount
81
82const float diffArea = 0.4; // self-shadowing reduction
83const float gDisplace = 0.4; // gauss bell center
84
85const vec3 onlyAOColor = vec3( 1.0, 0.7, 0.5 );
86//const vec3 onlyAOColor = vec3( 1.0, 1.0, 1.0 );,
87
88
89// RGBA depth
90
91float unpackDepth( const in vec4 rgba_depth ) {
92const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );
93float depth = dot( rgba_depth, bit_shift );
94return depth;
95}
96
97// generating noise / pattern texture for dithering
98
99vec2 rand( const vec2 coord ) {
100
101vec2 noise;
102
103if ( useNoise ) {
104
105float nx = dot ( coord, vec2( 12.9898, 78.233 ) );
106float ny = dot ( coord, vec2( 12.9898, 78.233 ) * 2.0 );
107
108noise = clamp( fract ( 43758.5453 * sin( vec2( nx, ny ) ) ), 0.0, 1.0 );
109
110} else {
111
112float ff = fract( 1.0 - coord.s * ( width / 2.0 ) );
113float gg = fract( coord.t * ( height / 2.0 ) );
114
115noise = vec2( 0.25, 0.75 ) * vec2( ff ) + vec2( 0.75, 0.25 ) * gg;
116
117}
118
119return ( noise * 2.0 - 1.0 ) * noiseAmount;
120
121}
122
123float doFog() {
124vec2 vUv = gl_TexCoord[0].st;
125float zdepth = unpackDepth( texture2D( tDepth, vUv ) );
126float depth = -cameraFar * cameraNear / ( zdepth * cameraFarMinusNear - cameraFar );
127
128return smoothstep( fogNear, fogFar, depth );
129
130}
131
132float readDepth( const in vec2 coord ) {
133
134//return ( 2.0 * cameraNear ) / ( cameraFar + cameraNear - unpackDepth( texture2D( tDepth, coord ) ) * ( cameraFar - cameraNear ) );,
135return cameraCoef / ( cameraFarPlusNear - unpackDepth( texture2D( tDepth, coord ) ) * cameraFarMinusNear );
136
137
138}
139
140float compareDepths( const in float depth1, const in float depth2, inout int far ) {
141
142float garea = 2.0; // gauss bell width
143float diff = ( depth1 - depth2 ) * 100.0; // depth difference (0-100)
144
145// reduce left bell width to avoid self-shadowing
146
147if ( diff < gDisplace ) {
148
149garea = diffArea;
150
151} else {
152
153far = 1;
154
155}
156
157float dd = diff - gDisplace;
158float gauss = pow( EULER, -2.0 * dd * dd / ( garea * garea ) );
159return gauss;
160
161}
162
163float calcAO( float depth, float dw, float dh ) {
164vec2 vUv = gl_TexCoord[0].st;
165float dd = radius - depth * radius;
166vec2 vv = vec2( dw, dh );
167vec2 coord1 = vUv + dd * vv;
168vec2 coord2 = vUv - dd * vv;
169
170float temp1 = 0.0;
171float temp2 = 0.0;
172int far = 0;
173temp1 = compareDepths( depth, readDepth( coord1 ), far );
174
175// DEPTH EXTRAPOLATION
176
177if ( far > 0 ) {
178temp2 = compareDepths( readDepth( coord2 ), depth, far );
179temp1 += ( 1.0 - temp1 ) * temp2;
180}
181return temp1;
182}
183void main() {
184vec2 vUv = gl_TexCoord[0].st;
185vec2 noise = rand( vUv );
186float depth = readDepth( vUv );
187float tt = clamp( depth, aoClamp, 1.0 );
188float w = ( 1.0 / width ) / tt + ( noise.x * ( 1.0 - noise.x ) );
189float h = ( 1.0 / height ) / tt + ( noise.y * ( 1.0 - noise.y ) );
190float pw;
191float ph;
192float ao;
193float dz = 1.0 / float( samples );
194float z = 1.0 - dz / 2.0;
195float l = 0.0;
196for ( int i = 0; i <= samples; i ++ ) {
197float r = sqrt( 1.0 - z );
198pw = cos( l ) * r;
199ph = sin( l ) * r;
200ao += calcAO( depth, pw * w, ph * h );
201z = z - dz;
202l = l + DL;
203}
204ao /= float( samples );
205ao = 1.0 - ao;
206if ( fogEnabled ) {
207ao = mix( ao, 1.0, doFog() );
208}
209vec3 color = texture2D( tDiffuse, vUv ).rgb;
210vec3 lumcoeff = vec3( 0.299, 0.587, 0.114 );
211float lum = dot( color.rgb, lumcoeff );
212vec3 luminance = vec3( lum );
213vec3 final = vec3( color * mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );
214if ( onlyAO ) {
215final = onlyAOColor * vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );
216}
217gl_FragColor = vec4( final, 1.0 );
218}
219);
220} else {
221fragShaderSrc = customFragmentShader;
222}
223
224
225shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragShaderSrc);
226shader.linkProgram();
227
228}
229
230
231void SSAOPass::render(ofFbo& readFbo, ofFbo& writeFbo, ofTexture& depthTex)
232{
233writeFbo.begin();
234
235
236shader.begin();
237
238shader.setUniformTexture("tDiffuse", readFbo.getTexture(), 0);
239shader.setUniformTexture("tDepth", depthTex, 1);
240shader.setUniform2f("size", writeFbo.getWidth(), writeFbo.getHeight());
241shader.setUniform1f("cameraNear", cameraNear);
242shader.setUniform1f("cameraFar", cameraFar);
243shader.setUniform1f("fogNear", fogNear);
244shader.setUniform1f("fogFar", fogFar);
245shader.setUniform1i("fogEnabled", fogEnabled ? 1 : 0 );
246shader.setUniform1i("onlyAO", onlyAO ? 1 : 0);
247shader.setUniform1f("aoClamp", aoClamp);
248shader.setUniform1f("lumInfluence", lumInfluence);
249
250texturedQuad(0, 0, writeFbo.getWidth(), writeFbo.getHeight());
251
252shader.end();
253writeFbo.end();
254}
255}