当前位置: 首页 > 知识库问答 >
问题:

带有多个着色器程序的OpenGL多重纹理

百里金林
2023-03-14

我试图在OpenGL中制作一个场景,从太空模拟地球。我现在有两个球体,一个用于地球,另一个稍大一些用于云层。地球和云球体对象都有自己的着色器程序来保持简单。地球着色器程序采用4种纹理(白天、夜晚、specmap和normalmap),而云着色器程序采用2种纹理(cloudmap和normalmap)。我有一个对象类,它有一个渲染函数,在该函数中我使用以下逻辑:

//bind the current object's texture
for (GLuint i = 0; i < texIDs.size(); i++){
    glActiveTexture(GL_TEXTURE0 + i);
    if (cubemap)
        glBindTexture(GL_TEXTURE_CUBE_MAP, texIDs[i]);
    else
        glBindTexture(GL_TEXTURE_2D, texIDs[i]);
}
    if (samplers.size()){
    for (GLuint i = 0; i < samplers.size(); i++){
        glUniform1i(glGetUniformLocation(program, samplers[i]), i);
    }
}

它从第0个纹理单元开始,从GL_TEXTURE0开始绑定N个纹理单元到N个纹理单元。然后它绑定着色器程序中从0到N开始的采样器。采样器由我在加载纹理时提供:

void Object::loadTexture(const char* filename, const GLchar* sampler){
    int texID;
    texID = SOIL_load_OGL_texture(filename, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS);
    if(texID == 0){
        cerr << "SOIL error: " << SOIL_last_result();
    }
    cout << filename << " Tex ID: " << texID << endl;
    texIDs.push_back(texID);
    samplers.push_back(sampler);
    //glBindTexture(GL_TEXTURE_2D, texID);
}

当我这样做时,第一个球体(地球)中的所有纹理都被成功加载,但在第二个球体中,我没有得到任何纹理,只得到一个黑色球体。我的问题是,如果我对每个对象使用不同的着色器程序,我应该如何管理多个纹理和采样器?

共有1个答案

解浩渺
2023-03-14

从我看到的情况来看,你将所有纹理绑定为单独的纹理单元

  • 那是错误的
  • 如果你有100个对象,每个对象有4个纹理...
  • 我强烈怀疑你有400个纹理单位可以支配
  • 纹理ID(名称)不是纹理单元...

我渲染的空间实体如下:

>

>

  • 我有特定任务的特定纹理单元

    // texture units:            
    // 0 - texture0 map 2D rgba (surface)
    // 1 - texture1 map 2D rgba (clouds blend)
    // 2 - normal map 2D xyz (normal/bump mapping)
    // 3 - specular map 2D i (reflection shininess)
    // 4 - light map 2D rgb rgb (night lights)
    // 5 - enviroment/skybox cube map 3D rgb
    

    查看链接中的着色器(它也是为太阳系可视化编写的)...

    第二个渲染过程将添加大气

    • 未使用纹理
    • 它只是覆盖整个屏幕的单个透明四边形

    以下是对你的任务的一些见解

    [edit1]多重文本的示例

    // init shader once per render all geometries
    GLint prog_id;      // shader program ID;
    GLint txrskybox;    // global skybox environment cube map
    GLint id;
    glUseProgram(prog_id);
    id=glGetUniformLocation(prog_id,"txr_texture0"); glUniform1i(id,0); //uniform sampler2D   txr_texture0;
    id=glGetUniformLocation(prog_id,"txr_texture1"); glUniform1i(id,1); //uniform sampler2D   txr_texture1;
    id=glGetUniformLocation(prog_id,"txr_normal");   glUniform1i(id,2); //uniform sampler2D   txr_normal;
    id=glGetUniformLocation(prog_id,"txr_specular"); glUniform1i(id,3); //uniform sampler2D   txr_specular;
    id=glGetUniformLocation(prog_id,"txr_light");    glUniform1i(id,4); //uniform sampler2D   txr_light;
    id=glGetUniformLocation(prog_id,"txr_skybox");   glUniform1i(id,5); //uniform samplerCube txr_skybox;
    
    // add here all uniforms you need ...
    glActiveTexture(GL_TEXTURE0+5); glEnable(GL_TEXTURE_CUBE_MAP); glBindTexture(GL_TEXTURE_CUBE_MAP,txrskybox);
    
    for (i=0;i<all_objects;i++)
        {
        // add here all uniforms you need ...
    
        // pass textures once per any object render
        // obj::(GLint) txr0,txr1,txrnor,txrspec,txrlight; // object local textures
        glActiveTexture(GL_TEXTURE0+0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txr0);
        glActiveTexture(GL_TEXTURE0+1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txr1);
        glActiveTexture(GL_TEXTURE0+2); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txrnor);
        glActiveTexture(GL_TEXTURE0+3); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txrspec);
        glActiveTexture(GL_TEXTURE0+4); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,obj[i].txrlight);
        // here render the geometry of obj[i]
        }
    
    // unbind textures and shaders
    glActiveTexture(GL_TEXTURE0+5); glBindTexture(GL_TEXTURE_CUBE_MAP,0); glDisable(GL_TEXTURE_CUBE_MAP);
    glActiveTexture(GL_TEXTURE0+4); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+3); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+2); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+1); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0+0); glBindTexture(GL_TEXTURE_2D,0); glDisable(GL_TEXTURE_2D); // unit0 at last so it stays active ...
    glUseProgram(0);
    

  •  类似资料:
    • 目前,我有问题与传递多个纹理到一个glsl着色器在iOS。 在渲染中,想要的纹理被绑定到制服上 我在这里一直使用GL_TEXTURE0和GL_TEXTURE1,因为当纹理(实际上是来自iPhone摄像头的luma和Chroma纹理,最终用于计算相应的rgb值)被创建时,这些textureLots被使用。 我使用的fragmentshader非常简单,它只是用给定的纹理对一个简单的屏幕填充四方进行纹

    • 我是OpenGL的新手,在整理如何将纹理和着色器绑定到VBOs时遇到了困难。 我正在使用Cinder的纹理和着色器类。以下是我绘制方法的一部分: 在上面的代码中,如果我注释掉对mShader的调用。bind(),我的球体VBO将显示纹理(myImage)。我的着色器适用于普通(无纹理)形状,但当我在绘制任何带有包裹纹理的形状之前绑定着色器时,它会阻止纹理显示。 这是我使用的着色器的问题,还是我不理

    • 我跟着教程上了课https://learnopengl.com/Lighting/Lighting-maps当使用多个纹理(一个用于镜面反射,一个用于漫反射照明)时,会出现一些奇怪的错误。当只使用一种纹理时,一切正常,但在使用两种纹理后,立方体只渲染黑色或只应用镜面反射纹理。 我在stackoverflow上搜索了所有类似的问题,并阅读了OpenGL文档,但仍然无法找出第二种纹理不起作用的原因。

    • 他们没有提到的是如何首先将两个纹理传递给着色器。 以前我 所以现在我 如何将大小不同的纹理数组传递给GLSL? 将多个纹理从OpenGL传递到GLSL着色器 GLSL中的多个纹理-只有一个有效 (这是家庭作业,所以请用最少的代码片段回答(如果有的话)。谢谢!) 如果做不到这一点,有人有茶具吗?

    • 我正在尝试实现现代OpenGL,但问题是:大多数教程都是基于3.3的,说到GLSL330,我只有GLSL130。因此,许多事情显然是不同的,因为我的VBO不起作用。 你能给我一个一般的提示或教程,解释如何使用GLSL 130与VBO的?在我的例子中,我加载了vbo,但是当我使用我的着色程序时,只有用glVertex调用的顶点被渲染,就像vbo被忽略(没有输入)。这个怎么解决? 你能在没有着色器的情

    • 我希望能够在GLSL片段着色器中组合两种纹理。我目前正在使用PyOpenGL,到目前为止我使用着色器所做的一切都很好。 当我尝试从片段着色器访问多个纹理时遇到困难,例如,以下着色器显示正确的纹理减去蓝色像素: 但是 导致空白屏幕。 我有一种感觉,问题可能在于我如何将纹理制服传递给着色器,但我一辈子都无法弄清楚为什么第一个纹理有效,而第二个纹理无效。下面是完整的程序。