LearnOpenGL 入门篇 纹理
发布网友
发布时间:2024-10-22 11:55
我来回答
共1个回答
热心网友
时间:2024-10-24 14:10
在 LearnOpenGL 教程中,使用 stb_image.h 加载图片时,通常会将其包含在 main.cpp 的顶部。但教程对此描述不够清晰。实际上,通常只需在 main.cpp 中包含这两行命令,而不必将其放入单独的 .cpp 文件中,随后像 glad.c 那样将此文件添加至项目工程中。具体原因尚不明确,为何将其置于 main.cpp 中会导致错误,而创建一个空白的 .cpp 文件则可以正常工作。关键在于,stb_image.h 只需包含一次,因为 stb.cpp 文件中已经包含了它,所以不必在 main.cpp 中重复包含。
引入头文件后,使用以下命令加载图片:
unsigned char* data = stbi_load("E:/VSFile/LearnOpenGL/tex/container.jpg", &width, &height, &nrChannels, 0);
在尝试加载图片时,可能会遇到一些小问题。这可能源于代码与教程的不完全同步,导致内存溢出错误。最初,作者以为是图片读取失败,或未正确包含 stb_image.h。但在尝试在空白的 .cpp 文件中单独加载图片后,发现图片被正确读取,从而确认了 stb_image.h 的正确性及其使用方法。
研究后发现,问题可能出在教程中使用了索引缓冲对象 EBO,而未注意到这一点,导致使用了错误的绘制命令,如 glDrawArrays(GL_TRIANGLES, 0, 6),四个顶点绘制六个顶点,从而引发了内存错误。将绘制方法更改为使用索引绘制(如 glDrawElements)即可解决问题。
总结而言,遇到大段代码时,先创建一个空白的 .cpp 文件来测试新函数或工具,以确保其功能无误。同时,仔细阅读代码是避免错误的关键。
在学习 OpenGL 时,需要处理纹理。生成纹理对象的方式类似于创建顶点数组对象(VAO)和顶点缓冲对象(VBO)。首先,创建一个无符号整数变量,如 basecolor,并将其绑定到一个纹理对象上,如下所示:
unsigned int basecolor;
glGenTextures(1, &basecolor);
glBindTexture(GL_TEXTURE_2D, basecolor);
接下来,使用 stbi_load() 函数加载图片,并将数据通过 glTexImage2D() 函数传递给 GPU 的内存中。同时,生成 mipmaps 以提高纹理质量。此过程确保纹理存在于 GPU 的内存中。
为了在片段着色器中使用纹理,需要创建一个采样器(Sampler)类型的统一变量。使用此采样器从 GPU 的纹理内存中获取数据。然而,创建采样器变量并不需要设置其值,因为 OpenGL 知道从哪个纹理内存中获取数据。每个采样器通过激活对应的纹理单元来识别不同的纹理。例如,激活纹理单元 0 并绑定纹理 basecolor,然后激活纹理单元 1 并绑定另一个纹理,如 specularity map。这样,片段着色器可以访问多个纹理。
片段着色器通过采样器访问纹理,如下所示:
uniform sampler2D basecolor;
uniform sampler2D specularMap;
然后,使用以下代码设置采样器位置:
glUniform1i(glGetUniformLocation(ourShader.ID, "basecolor"), 0);
glUniform1i(glGetUniformLocation(ourShader.ID, "specularMap"), 1);
最后,片段着色器可以轻松地访问和处理这些纹理数据。在实际应用中,纹理单元的数量(最多 16 个)通常由图形 API 和硬件*决定。
以上内容详细介绍了如何在 OpenGL 中加载和使用纹理,从加载图片到在着色器中使用纹理,涵盖了从基础到高级的各个阶段。