1

在我使用 GLSL 程序的纹理中,只有一个纹理绑定到纹理单元 0。如下所示:

.......................
        glActiveTexture(GL_TEXTURE0);
        GLuint tid;
        glGenTextures(1, &tid);
        glBindTexture(GL_TEXTURE_2D, tid);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width, img.height, 0,
                     img.format, GL_UNSIGNED_BYTE, img.data);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

然后通过一个统一变量通知frag shader(就像setUniform一样),这里的名字是“texture0”,对应于我的frag shader:

void CShader::setUniform( const char *name, int val )
    {
        int loc = getUniformLocation(name);
        glAssert();  //note!,my own assertion wrapping around glGetError.
              if( loc >= 0 )
        {
            glUniform1i(loc, val);

        } else {
            printf("Uniform: %s not found.\n",name);
        }
              glAssert();   //note!,my own assertion wrapping around glGetError.

    }

出乎我的意料,它在最后glAssert()一行断言失败,并给我。出了什么GL_INVALID_OPERATION问题,我的显卡不支持这个操作吗?,不可能,我的OpenGL版本是 3.x。经过几个小时的挣扎,尝试评论了最后一个glAssert(),但另一个断言在我的 gldrawelements 调用中失败了。显然,我绝对认为原因gldrawelements失败是glUniform1i失败的。有人可以给我建议。

编辑:

来自 datenwolf 的建议,这里是 glAssert 的代码,非常简单,只需调用 glGetError 一次。

void _glAssert(const char * info, int line){
 char const* sz_GL_INVALID_ENUM="GL_INVALID_ENUM";
 char const* sz_GL_INVALID_VALUE="GL_INVALID_VALUE";
 char const* sz_GL_INVALID_OPERATION="GL_INVALID_OPERATION";
 char const* sz_GL_OUT_OF_MEMORY ="GL_OUT_OF_MEMORY";
GLenum result;
    if((result=glGetError()) != GL_NO_ERROR )
    {
        const char *  sz_result=NULL;
        switch(result)
        {
        case GL_INVALID_ENUM:
            sz_result = sz_GL_INVALID_ENUM;
        break;
        case GL_INVALID_VALUE:
            sz_result = sz_GL_INVALID_VALUE;
        break;
        case GL_INVALID_OPERATION:
            sz_result = sz_GL_INVALID_OPERATION;
        break;
        case GL_OUT_OF_MEMORY:
            sz_result = sz_GL_OUT_OF_MEMORY;
        break;
        }

        _assert(sz_result,info,line);
    }
}

#define glAssert() \
    _glAssert(__FILE__, __LINE__);

顺便说一句,在我使用 glUniform1i 调用之前,我的着色器一切正常

attribute vec3 VertexPosition;
varying vec3 Color;
void main()
{
Color = vec3(0.5,0,0);
gl_TexCoord[0]  = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * vec4( VertexPosition, 1.0 );
}


uniform sampler2D texture0;

varying vec3 Color;
void main() {

 vec4 texColor = texture2D( texture0, gl_TexCoord[0].st);
gl_FragColor= vec4(Color, 1.0)*texColor;
}

我已经在着色器中删除了许多代码以简化问题。

对不起,我没有详细描述这一点。实际上,我对 opengl 的包装非常简单,没有复杂的东西,没有多线程。

这是用于将纹理和着色器脚本分别加载到GPU,内存中的构造函数,然后调用“compileandlink”方法编译着色器脚本,并立即调用setUniform。

IEntity(const char * szvs,const char * szfs): m_shader(new CShader(szvs,szfs)){
         ...........................
}

CCube::CCube():IEntity("v_simple.glsl","f_simple.glsl") {
    ...................

        IMAGE img;
        img.Load("texture.bmp");
        img.ExpandPalette();

        glActiveTexture(GL_TEXTURE0);
        GLuint tid;
        glGenTextures(1, &tid);
        glBindTexture(GL_TEXTURE_2D, tid);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width, img.height, 0,
                     img.format, GL_UNSIGNED_BYTE, img.data);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        m_shader->compileandlink();
        m_shader->setUniform("texture0", 0);
}

CShader::compileandlink 方法

bool CShader::compileandlink(){
            if(m_vsscript == NULL || m_fsscript == NULL)
                return false;

            if(strlen(m_vsscript) <= 0  || strlen(m_fsscript) <= 0)
                return false;

            glShaderSource(m_vs, 1, (const GLchar **) &m_vsscript, NULL);
            glCompileShader(m_vs);

            glShaderSource(m_fs, 1, (const GLchar **) &m_fsscript, NULL);
            glCompileShader(m_fs);

            glAttachShader(m_program, m_vs);
            glAttachShader(m_program, m_fs);
            //glBindFragDataLocation(m_program, 0, "FragColor");
            glLinkProgram(m_program);
            glAssert();


            GLint status;
            glGetProgramiv( m_program, GL_LINK_STATUS, &status );
            if( GL_FALSE == status ) {
            fprintf( stderr, "Failed to link shader program!\n" );
            GLint logLen;
            glGetProgramiv(m_program, GL_INFO_LOG_LENGTH,
            &logLen);

            if( logLen > 0 )
                {
                char * log = (char *)malloc(logLen);
                GLsizei written;
                glGetProgramInfoLog(m_program, logLen,
                    &written, log);
                printf("Program log: \n%s", log);
                free(log);
                }
            }


            return true;

    }

CShader::setUniform 方法,正如我之前所说,在 glGetUniformiv 在此方法中返回后,它具有“glGetError”的 GL_INVALID_OPERATION 结果。

void CShader::setUniform( const char *name, int val )
    {
        int loc = getUniformLocation(name);
        glAssert();
        if( loc >= 0 )
        {
            GLint outval=-1;

            glUniform1i(loc, val);
            /*int tmploc =glGetUniformLocation(m_program, name);
            glGetUniformiv(m_program,
                            tmploc,
                           &outval);
            printf("Value is %d\n", outval);*/

        } else {
            printf("Uniform: %s not found.\n",name);
        }
        glAssert();
    }
4

1 回答 1

7
m_shader->compileandlink();
m_shader->setUniform("texture0", 0);

这是行不通的,因为只有在有活动的程序对象时才能设置制服。即,您需要glUseProgram(m_program)在尝试设置统一值之前。这就是函数没有program参数的原因glUniform

我不明白:int loc = getUniformLocation(name),因为它确实需要链接程序的名称。评论:glGetUniformLocation(m_program, name)实际上是正确的。

于 2013-04-07T14:25:22.400 回答