qt opengl着色器纹理坐标

时间:2015-10-13 06:17:56

标签: qt opengl shader

我使用OpenGL着色器将中值滤镜应用于图像。输入图像我复制到in_fbo缓冲区。一切正常。

QGLFramebufferObject *in_fbo, *out_fbo;
painter.begin(in_fbo); //Copy QImage to  QGLFramebufferObject
painter.drawImage(0,0,image_in,0,0,width,height);
painter.end();

out_fbo->bind();
glViewport( 0, 0, nWidth, nHeight );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();

glOrtho( 0.0, nWidth, 0.0, nHeight, -1.0, 1.0 );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );

glEnable( GL_TEXTURE_2D );

out_fbo->drawTexture( QPointF(0.0,0.0), in_fbo->texture( ), GL_TEXTURE_2D );

但是在着色器代码中我需要按照图像的宽度和高度划分顶点的位置,因为纹理坐标被归一化到0到1之间的范围。

如何正确计算纹理坐标?

//vertex shader
varying vec2 pos;
void main( void )
{
    pos = gl_Vertex.xy;
    gl_Position = ftransform( );
}
//fragment shader
#extension GL_ARB_texture_rectangle : enable

uniform sampler2D texture0;
uniform int imgWidth;
uniform int imgHeight;
uniform int len;
varying vec2 pos;

#define MAX_LEN (100)

void main(){
    float v[ MAX_LEN ];

    for (int i = 0; i < len; i++) {
         vec2 posi = pos + float(i);
         posi.x = posi.x / float( imgWidth );
         posi.y = posi.y / float( imgHeight );
         v[i] = texture2D(texture0, posi).r;
    }
    //
    //.... Calculating new value
    //

    gl_FragColor = vec4( m, m, m, 1.0 );
}

之前我在OpenFrameworks中做过。但OF中纹理的着色器对Qt中的纹理不起作用。我想因为OF使用textureTarget = GL_TEXTURE_RECTANGLE_ARB创建纹理。现在应用上面的着色器的结果是不正确的。它与旧着色器的结果不同(有少量像素具有不同的颜色)。我不知道如何修改上面的着色器:(。

旧着色器:

//vertex
#version 120
#extension GL_ARB_texture_rectangle : enable

void main() {
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_FrontColor = gl_Color;
}


//fragment
#version 120
#extension GL_ARB_texture_rectangle : enable

uniform sampler2D texture0;
uniform int len; 

void main(){
    vec2 pos = gl_TexCoord[0].xy;

    pos.x = int( pos.x );       
    pos.y = int( pos.y );

    float v[ MAX_LEN ];

    for (int i=0; i<len; i++) {
        vec2 posi = pos +  i;       
        posi.x = int( posi.x + 0.5 ) + 0.5;
        posi.y = int( posi.y + 0.5 ) + 0.5;
        v[i] = texture2D(texture0, posi).r;
    }
    //
    //.... Calculating new value
    //       
    gl_FragColor = vec4( m, m, m, 1.0 );
}

OpenFrameworks lib中的OpenGL代码

texData.width = w;
texData.height = h;

texData.tex_w = w;
texData.tex_h = h;
texData.textureTarget = GL_TEXTURE_RECTANGLE_ARB;

texData.bFlipTexture = true;
texData.glType = GL_RGBA;

// create & setup FBO
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

// Create the render buffer for depth
glGenRenderbuffersEXT(1, &depthBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, texData.tex_w, texData.tex_h);

// create & setup texture
glGenTextures(1, (GLuint *)(&texData.textureID));   // could be more then one, but for now, just one
glBindTexture(texData.textureTarget, (GLuint)(texData.textureID));
glTexParameterf(texData.textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(texData.textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(texData.textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(texData.textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(texData.textureTarget, 0, texData.glType, texData.tex_w, texData.tex_h, 0, texData.glType, GL_UNSIGNED_BYTE, 0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

// attach it to the FBO so we can render to it
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texData.textureTarget, (GLuint)texData.textureID, 0);

1 个答案:

答案 0 :(得分:0)

我认为你真的不想使用纹理的尺寸来做到这一点。根据事物的声音,这是一个简单的全屏图像滤镜,你真的只想将片段坐标映射到范围[ 0.0 1.0 ]。如果是这种情况,那么gl_FragCoord.xy / viewport.xy,其中视口是2D制服,它定义视口的宽度和高度应该适用于纹理坐标(在片段着色器中)。

vec2 texCoord = vec2 (transformed_pos.x, transformed_pos.y) / transformed_pos.w * vec2 (0.5, 0.5) + vec2 (1.0, 1.0)也可以使用相同的原理 - 剪辑空间坐标转换为NDC,然后映射到纹理空间。这种方法无法正确考虑纹素中心((0.5, 0.5)而不是(0.0, 0.0)),但在启用纹理过滤且包裹模式不是GL_CLAMP_TO_EDGE时会出现问题。