OpenGL 编程/高级/阴影
外观
在 OpenGL 中绘制阴影可能是一项具有挑战性的任务,但有几种技术可以用来实现令人信服的效果。以下是在 OpenGL 中绘制阴影的一些常见技术
- 阴影贴图:阴影贴图是一种在实时 3D 图形中渲染阴影的常用技术。它涉及从光源的角度渲染场景并将深度值存储在纹理中。然后使用该纹理来确定在从相机的角度渲染场景时,像素是否在阴影中。
- 阴影体积:阴影体积是另一种渲染阴影的技术,它通过创建一个包围物体并与场景中的其他物体相交的体积来工作。然后使用该体积来确定像素是否在阴影中。
- 阴影蒙版:阴影蒙版是用于在 OpenGL 中渲染软阴影的技术。它们的工作原理是渲染一个代表阴影形状的黑白蒙版,然后使用该蒙版来调制场景中物体的亮度。
- 投影纹理:投影纹理可以用于通过将代表阴影的纹理投影到场景中的物体上来模拟阴影的外观。这种技术可以用来创建软阴影或模拟由场景中不存在的物体投射的阴影的外观。
每种技术都有其自身的优缺点,最佳方法将取决于项目的具体要求。通过尝试这些技术并将它们调整到您的需要,您可以在 OpenGL 应用程序中创建令人信服且视觉上吸引人的阴影。
以下是如何使用着色器和帧缓冲区在 OpenGL 中实现阴影贴图的示例
首先,设置帧缓冲区和深度纹理
GLuint fbo, depthTex;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &depthTex);
glBindTexture(GL_TEXTURE_2D, depthTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
接下来,创建阴影贴图着色器程序
GLuint shadowProgram = createShaderProgram("shadow.vert", "shadow.frag");
GLint shadowViewLoc = glGetUniformLocation(shadowProgram, "view");
GLint shadowProjLoc = glGetUniformLocation(shadowProgram, "proj");
GLint shadowModelLoc = glGetUniformLocation(shadowProgram, "model");
然后,从光的角度渲染场景到深度纹理
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, width, height);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(shadowProgram);
glUniformMatrix4fv(shadowViewLoc, 1, GL_FALSE, glm::value_ptr(lightView));
glUniformMatrix4fv(shadowProjLoc, 1, GL_FALSE, glm::value_ptr(lightProj));
for (auto& object : objects) {
glUniformMatrix4fv(shadowModelLoc, 1, GL_FALSE, glm::value_ptr(object.model));
object.mesh->render();
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
最后,从相机的角度渲染场景,使用深度纹理来确定像素是否在阴影中
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
glUniformMatrix4fv(lightViewLoc, 1, GL_FALSE, glm::value_ptr(lightView));
glUniformMatrix4fv(lightProjLoc, 1, GL_FALSE, glm::value_ptr(lightProj));
glUniform1i(shadowMapLoc, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTex);
for (auto& object : objects) {
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(object.model));
object.mesh->render();
}
这只是一个基本的示例,有许多方法可以优化和改进此代码。但是,它应该让您了解如何在 OpenGL 中使用着色器和帧缓冲区实现阴影贴图。