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;
}

在上述代码中:

  1. 首先初始化 GLFWGLEW,创建一个 OpenGL 窗口。
  2. 在顶点着色器中,定义了一个 uniform 变量 clipPlane 来接收裁剪平面的参数。在 main 函数中,计算每个顶点到裁剪平面的距离,如果顶点在裁剪平面背面,则将其位置设置为一个无效值,使其在渲染时被裁剪掉。
  3. 在片段着色器中,简单地将顶点位置作为颜色输出,以便在屏幕上显示。
  4. renderLoop 函数中,动态更新裁剪平面参数,并进行渲染操作。

请注意,上述代码只是一个简单的示例,实际应用中你需要根据具体需求进一步完善和扩展代码,例如处理更多的输入、加载模型数据等。并且确保你的 OpenGL 环境已经正确配置,并且支持 GLSL 的相关特性。

posted @ 2024-11-10 16:27  MarsCactus  阅读(22)  评论(0编辑  收藏  举报