OpenGL 和 GLSL 在顶点着色器中动态调整裁剪平面参数的简单代码示例
以下是一个使用 OpenGL 和 GLSL 在顶点着色器中动态调整裁剪平面参数的简单代码示例:
// OpenGL 初始化代码
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
GLFWwindow* window;
// 初始化 GLFW
void initGLFW() {
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(800, 600, "Dynamic Clip Plane Example", nullptr, nullptr);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
}
// 初始化 GLEW
void initGLEW() {
glewExperimental = GL_TRUE;
if (glewInit()!= GLEW_OK) {
std::cerr << "Failed to initialize GLEW" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
}
// 顶点着色器代码
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 clipPlane; // 裁剪平面参数
out vec3 fragPosition;
void main() {
fragPosition = vec3(model * vec4(position, 1.0));
// 计算顶点到裁剪平面的距离
float distance = dot(vec4(fragPosition, 1.0), clipPlane);
// 如果顶点在裁剪平面背面,则将其位置设置为一个无效值(这里简单设置为很大的负值)
if (distance < 0.0) {
gl_Position = vec4(-10000.0, -10000.0, -10000.0, 1.0);
} else {
gl_Position = projection * view * model * vec4(position, 1.0);
}
}
// 片段着色器代码
#version 330 core
in vec3 fragPosition;
out vec4 color;
void main() {
color = vec4(fragPosition, 1.0);
}
// 渲染循环函数
void renderLoop() {
while (!glfwWindowShouldClose(window)) {
// 处理输入
glfwPollEvents();
// 动态更新裁剪平面参数(这里只是简单的示例,你可以根据实际需求更新)
float clipPlaneParameters[4] = {0.5, 0.5, -0.5, -0.5};
glUniform4fv(glGetUniformLocation(yourShaderProgram, "clipPlane"), 1, clipPlaneParameters);
// 清除颜色和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 使用你的着色器程序进行渲染
glUseProgram(yourShaderProgram);
// 绘制物体(这里假设你已经有了一个简单的物体绘制代码)
// 例如:绘制一个三角形
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO);
// 交换前后缓冲区
glfwSwapBuffers(window);
}
}
// 主函数
int main() {
initGLFW();
initGLEW();
// 编译和链接着色器程序
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 clipPlane;
out vec3 fragPosition;
void main() {
fragPosition = vec3(model * vec4(position, 1.0));
float distance = dot(vec4(fragPosition, 1.0), clipPlane);
if (distance < 0.0) {
gl_Position = vec4(-10000.0, -10000.0, -10000.0, 1.0);
} else {
gl_Position = projection * view * model * vec4(position, 1.0);
}
}
)";
const char* fragmentShaderSource = R"(
#version 330 core
in vec3 fragPosition;
out vec4 color;
void main() {
color = vec4(fragPosition, 1.0);
}
)";
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
glCompileShader(vertexShader);
// 检查顶点着色器编译错误
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cerr << "Vertex Shader Compilation Failed: " << infoLog << std::endl;
glfwTerminate();
return -1;
}
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
glCompileShader(fragmentShader);
// 检查片段着色器编译错误
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
std::cerr << "Fragment Shader Compilation Failed: " << infoLog << std::endl;
glfwTerminate();
return -1;
}
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// 检查着色器程序链接错误
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
std::cerr << "Shader Program Linking Failed: " << infoLog << std::endl;
glfwTerminate();
return -1;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 设置你的着色器程序
glUseProgram(shaderProgram);
// 获取 uniform 变量的位置
GLint modelLoc = glGetUniformLocation(shaderProgram, "model");
GLint viewLoc = glGetUniformLocation(shaderProgram, "view");
GLint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
// 设置模型、视图和投影矩阵(这里只是简单的示例矩阵,你需要根据实际情况设置)
glm::mat4 modelMatrix = glm::mat4(1.0f);
glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 projectionMatrix = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
// 进入渲染循环
renderLoop();
// 清理资源
glfwTerminate();
return 0;
}
在上述代码中:
- 首先初始化
GLFW
和GLEW
,创建一个 OpenGL 窗口。 - 在顶点着色器中,定义了一个
uniform
变量clipPlane
来接收裁剪平面的参数。在main
函数中,计算每个顶点到裁剪平面的距离,如果顶点在裁剪平面背面,则将其位置设置为一个无效值,使其在渲染时被裁剪掉。 - 在片段着色器中,简单地将顶点位置作为颜色输出,以便在屏幕上显示。
- 在
renderLoop
函数中,动态更新裁剪平面参数,并进行渲染操作。
请注意,上述代码只是一个简单的示例,实际应用中你需要根据具体需求进一步完善和扩展代码,例如处理更多的输入、加载模型数据等。并且确保你的 OpenGL 环境已经正确配置,并且支持 GLSL
的相关特性。