具有多个着色器程序的 OpenGL 多纹理
Posted
技术标签:
【中文标题】具有多个着色器程序的 OpenGL 多纹理【英文标题】:OpenGL multiple texture with multiple shader programs 【发布时间】:2015-08-09 04:00:39 【问题描述】:我正在尝试在 OpenGL 中制作一个场景来模拟来自太空的地球。我现在有两个球体,一个用于地球,另一个用于云。地球和云球对象有自己的着色器程序来保持简单。地球着色器程序需要 4 个纹理(白天、夜晚、光谱贴图和法线贴图),而云着色器程序需要 2 个纹理(云图和法线贴图)。我有一个具有渲染函数的对象类,在该函数中我使用以下逻辑:
//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个纹理单元开始,将N个纹理绑定到从GL_TEXTURE0开始的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】:据我所知,您将所有纹理绑定为单独的纹理单元
错了 如果您有 100 个对象,每个对象有 4 个纹理... 我强烈怀疑你有 400 个纹理单元可供使用 纹理 ID(名称)不是纹理单元...我这样渲染空间体:
First pass renders the astro body geometry
我有用于特定任务的特定纹理单元
// 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
查看该链接中的着色器(它也是为太阳系可视化而编写的)...
在每次渲染之前,您只绑定单个主体的纹理 (绑定着色器后) 不要更改纹理单元的含义(如果您这样做,着色器将如何知道哪个纹理是什么?)Second render pass adds atmospheres
未使用纹理 它只是一个覆盖整个屏幕的透明四边形here some insights to your tasks
[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);
【讨论】:
您能否展示如何使用 glActiveTexture 和 glBindTexture 调用将纹理绑定到 C++ 端的着色器? @pslayer89 添加示例 谢谢,今天晚些时候我会试试看结果。 我仍在努力,我一直在努力,我意识到了一些我不确定的事情。从文件中读取纹理的顺序是否重要?据我了解,不应该。只是希望有人确认... @pslayer89 没关系,唯一的区别是,如果您按顺序添加纹理,那么不同的顺序有时在 OpenGL 中意味着不同的TextureID
,但这与渲染本身无关,除非您不传递@ 987654327@ 而是一些索引(但那是代码中的错误......)以上是关于具有多个着色器程序的 OpenGL 多纹理的主要内容,如果未能解决你的问题,请参考以下文章