我使用Apple的OpenGL Shader Builder(类似于Nvidia的fx作曲家的工具,但更简单)跟踪this tutorial。
我可以轻松应用过滤器,但我不明白它们是否正常工作(如果是这样,我怎样才能改进输出)。例如,模糊滤镜:OpenGL本身对纹理进行一些图像处理,因此如果它们以比原始图像更高的分辨率显示,则它们已经被OpenGL模糊。其次,模糊部分比没有处理的部分更亮,我认为这没有意义,因为它只是从直接邻域获取像素。这是由
定义的float step_w = (1.0/width);
我不太明白:使用浮点值对像素进行索引
Blurred Image http://img218.imageshack.us/img218/6468/blurzt.png
编辑:我忘记附上我使用的确切代码:
片段着色器
// Originally taken from: http://www.ozone3d.net/tutorials/image_filtering_p2.php#part_2
#define KERNEL_SIZE 9
float kernel[KERNEL_SIZE];
uniform sampler2D colorMap;
uniform float width;
uniform float height;
float step_w = (1.0/width);
float step_h = (1.0/height);
// float step_w = 20.0;
// float step_h = 20.0;
vec2 offset[KERNEL_SIZE];
void main(void)
{
int i = 0;
vec4 sum = vec4(0.0);
offset[0] = vec2(-step_w, -step_h); // south west
offset[1] = vec2(0.0, -step_h); // south
offset[2] = vec2(step_w, -step_h); // south east
offset[3] = vec2(-step_w, 0.0); // west
offset[4] = vec2(0.0, 0.0); // center
offset[5] = vec2(step_w, 0.0); // east
offset[6] = vec2(-step_w, step_h); // north west
offset[7] = vec2(0.0, step_h); // north
offset[8] = vec2(step_w, step_h); // north east
// Gaussian kernel
// 1 2 1
// 2 4 2
// 1 2 1
kernel[0] = 1.0; kernel[1] = 2.0; kernel[2] = 1.0;
kernel[3] = 2.0; kernel[4] = 4.0; kernel[5] = 2.0;
kernel[6] = 1.0; kernel[7] = 2.0; kernel[8] = 1.0;
// TODO make grayscale first
// Laplacian Filter
// 0 1 0
// 1 -4 1
// 0 1 0
/*
kernel[0] = 0.0; kernel[1] = 1.0; kernel[2] = 0.0;
kernel[3] = 1.0; kernel[4] = -4.0; kernel[5] = 1.0;
kernel[6] = 0.0; kernel[7] = 2.0; kernel[8] = 0.0;
*/
// Mean Filter
// 1 1 1
// 1 1 1
// 1 1 1
/*
kernel[0] = 1.0; kernel[1] = 1.0; kernel[2] = 1.0;
kernel[3] = 1.0; kernel[4] = 1.0; kernel[5] = 1.0;
kernel[6] = 1.0; kernel[7] = 1.0; kernel[8] = 1.0;
*/
if(gl_TexCoord[0].s<0.5)
{
// For every pixel sample the neighbor pixels and sum up
for( i=0; i<KERNEL_SIZE; i++ )
{
// select the pixel with the concerning offset
vec4 tmp = texture2D(colorMap, gl_TexCoord[0].st + offset[i]);
sum += tmp * kernel[i];
}
sum /= 16.0;
}
else if( gl_TexCoord[0].s>0.51 )
{
sum = texture2D(colorMap, gl_TexCoord[0].xy);
}
else // Draw a red line
{
sum = vec4(1.0, 0.0, 0.0, 1.0);
}
gl_FragColor = sum;
}
顶点着色器
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
}
答案 0 :(得分:4)
纹理坐标通常从(0,0)
(左下角)到(1,1)
(右上角),所以实际上它们是浮点数。
因此,如果您有texturecoordinates (u,v)
,则“原始”坐标由(u*textureWidth, v*textureHeight)
计算。
如果结果值不是整数,则可能有不同的方法来处理:
floor
或ceil
即可使数字成为积分但是我认为每种着色语言都有一种方法可以通过它们的“原始”来访问纹理,即整数索引。
答案 1 :(得分:0)
@Nils,感谢您发布此代码。我一直试图找出一种在GPU上进行卷积一段时间的简单方法。 我尝试了你的代码并自己遇到了同样的调光问题。这是我解决它的方式。
这是一个没有调光问题的解决方案,并且还绕过了对3x3内核的偏移数组的需求。
我已经包含了8个对我有用的内核而没有变暗。
uniform sampler2D colorMap;
uniform float width;
uniform float height;
const mat3 SobelVert= mat3( 1.0, 2.0, 1.0, 0.0, 0.0, 0.0, -1.0, -2.0, -1.0 );
const mat3 SobelHorz= mat3( 1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0 );
const mat3 SimpleBlur= (1.0/9.0)*mat3( 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 );
const mat3 Sharpen= mat3( 0.0, -1.0, 0.0, -1.0, 5.0, -1.0, 0.0, -1.0, 0.0 );
const mat3 GaussianBlur= (1.0/16.0)*mat3( 1.0, 2.0, 1.0, 2.0, 4.0, 2.0, 1.0, 2.0, 1.0 );
const mat3 SimpleHorzEdge= mat3( 0.0, 0.0, 0.0, -3.0, 3.0, 0.0, 0.0, 0.0, 0.0 );
const mat3 SimpleVertEdge= mat3( 0.0, -3.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0 );
const mat3 ClearNone= mat3( 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 );
void main(void)
{
vec4 sum = vec4(0.0);
if(gl_TexCoord[0].x <0.5)
{
mat3 I, R, G, B;
vec3 sample;
// fetch the 3x3 neighbourhood and use the RGB vector's length as intensity value
for (int i=0; i<3; i++){
for (int j=0; j<3; j++) {
sample = texture2D(colorMap, gl_TexCoord[0].xy + vec2(i-1,j-1)/vec2(width, height)).rgb;
I[i][j] = length(sample); //intensity (or illumination)
R[i][j] = sample.r;
G[i][j] = sample.g;
B[i][j] = sample.b;
}
}
//apply the kernel convolution
mat3 convolvedMatR = matrixCompMult( SimpleBlur, R);
mat3 convolvedMatG = matrixCompMult( SimpleBlur, G);
mat3 convolvedMatB = matrixCompMult( SimpleBlur, B);
float convR = 0.0;
float convG = 0.0;
float convB = 0.0;
//sum the result
for (int i=0; i<3; i++){
for (int j=0; j<3; j++) {
convR += convolvedMatR[i][j];
convG += convolvedMatG[i][j];
convB += convolvedMatB[i][j];
}
}
sum = vec4(vec3(convR, convG, convB), 1.0);
}
else if( gl_TexCoord[0].x >0.51 )
{
sum = texture2D(colorMap, gl_TexCoord[0].xy );
}
else // Draw a red line
{
sum = vec4(1.0, 0.0, 0.0, 1.0);
}
gl_FragColor = sum;
}