framework2
155 строк · 5.7 Кб
1/*
2* ConvolutionPass.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 "ConvolutionPass.h"
33#include "ofMain.h"
34
35namespace itg
36{
37ConvolutionPass::ConvolutionPass(const ofVec2f& aspect, bool arb, const ofVec2f& imageIncrement, float sigma, unsigned kernelSize) :
38imageIncrement(imageIncrement), RenderPass(aspect, arb, "convolution")
39{
40string vertShaderSrc = STRINGIFY(
41uniform vec2 imageIncrement;
42uniform vec2 resolution;
43
44varying vec2 vUv;
45varying vec2 scaledImageIncrement;
46
47void main()
48{
49gl_TexCoord[0] = gl_MultiTexCoord0;
50scaledImageIncrement = imageIncrement * resolution;
51vUv = gl_TexCoord[0].st - ( ( KERNEL_SIZE - 1.0 ) / 2.0 ) * scaledImageIncrement;
52gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
53}
54);
55
56string fragShaderSrc = STRINGIFY(
57uniform float kernel[KERNEL_SIZE];
58uniform SAMPLER_TYPE readTex;
59uniform vec2 imageIncrement;
60
61varying vec2 vUv;
62varying vec2 scaledImageIncrement;
63
64void main()
65{
66
67vec2 imageCoord = vUv;
68vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 );
69
70for( int i = 0; i < KERNEL_SIZE; i++ )
71{
72sum += TEXTURE_FN( readTex, imageCoord ) * kernel[ i ];
73imageCoord += scaledImageIncrement;
74}
75
76gl_FragColor = sum;
77}
78);
79
80ostringstream oss;
81oss << "#version 120\n#define KERNEL_SIZE " << kernelSize << ".0" << endl << vertShaderSrc;
82shader.setupShaderFromSource(GL_VERTEX_SHADER, oss.str());
83
84oss.str("");
85oss << "#version 120\n#define KERNEL_SIZE " << kernelSize << endl;
86if (arb)
87{
88oss << "#define SAMPLER_TYPE sampler2DRect" << endl;
89oss << "#define TEXTURE_FN texture2DRect" << endl;
90}
91else
92{
93oss << "#define SAMPLER_TYPE sampler2D" << endl;
94oss << "#define TEXTURE_FN texture2D" << endl;
95}
96oss << fragShaderSrc;
97shader.setupShaderFromSource(GL_FRAGMENT_SHADER, oss.str());
98shader.linkProgram();
99
100// build kernel
101buildKernel(sigma);
102}
103
104// We lop off the sqrt(2 * pi) * sigma term, since we're going to normalize anyway.
105float ConvolutionPass::gauss(float x, float sigma)
106{
107return expf( -( x * x ) / ( 2.0 * sigma * sigma ) );
108}
109
110void ConvolutionPass::render(ofFbo& readFbo, ofFbo& writeFbo)
111{
112writeFbo.begin();
113
114ofClear(0, 0, 0, 255);
115
116shader.begin();
117
118shader.setUniformTexture("readTex", readFbo, 0);
119shader.setUniform2f("imageIncrement", imageIncrement.x, imageIncrement.y);
120shader.setUniform1fv("kernel", kernel.data(), kernel.size());
121if (arb) shader.setUniform2f("resolution", readFbo.getWidth(), readFbo.getHeight());
122else shader.setUniform2f("resolution", 1.f, 1.f);
123
124if (arb) texturedQuad(0, 0, writeFbo.getWidth(), writeFbo.getHeight(), readFbo.getWidth(), readFbo.getHeight());
125else texturedQuad(0, 0, writeFbo.getWidth(), writeFbo.getHeight());
126
127shader.end();
128writeFbo.end();
129}
130
131void ConvolutionPass::buildKernel(float sigma)
132{
133unsigned kernelSize = 2 * ceil( sigma * 3.0 ) + 1;
134
135if (kernelSize > MAX_KERNEL_SIZE) kernelSize = MAX_KERNEL_SIZE;
136
137kernel.clear();
138kernel.reserve(kernelSize);
139
140float halfWidth = ( kernelSize - 1 ) * 0.5;
141
142float sum = 0.0;
143for (unsigned i = 0; i < kernelSize; ++i )
144{
145kernel.push_back(gauss(i - halfWidth, sigma));
146sum += kernel.back();
147}
148
149// normalize the kernel
150for (unsigned i = 0; i < kernelSize; ++i )
151{
152kernel[ i ] /= sum;
153}
154}
155}