返回

OpenGL渲染技巧-光照效果下的甜甜圈

IOS

光照效果概述

光照效果是计算机图形学中非常重要的一部分,它可以使渲染出的物体更加逼真,更接近真实世界中的物体。光照效果可以通过模拟真实世界中的光线来实现,包括光线的方向、颜色和强度。

实现光照效果

在OpenGL中,可以使用光照着色器来实现光照效果。光照着色器是一种特殊的着色器,它可以根据光源的位置、方向、颜色和强度来计算出物体表面的颜色。

甜甜圈模型渲染

为了演示光照效果,我们将使用OpenGL实现一个甜甜圈模型的渲染。甜甜圈模型是由OpenGL提供实现的,我们可以通过调用相应的OpenGL函数来绘制甜甜圈模型。

代码示例

// 顶点着色器代码
const char *vertexShaderSource =
    "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "layout (location = 1) in vec3 aNormal;\n"
    "uniform mat4 model;\n"
    "uniform mat4 view;\n"
    "uniform mat4 projection;\n"
    "out vec3 fragPos;\n"
    "out vec3 Normal;\n"
    "void main()\n"
    "{\n"
    "    fragPos = vec3(model * vec4(aPos, 1.0));\n"
    "    Normal = mat3(transpose(inverse(model))) * aNormal;\n"
    "    gl_Position = projection * view * model * vec4(aPos, 1.0);\n"
    "}\n";

// 片段着色器代码
const char *fragmentShaderSource =
    "#version 330 core\n"
    "in vec3 fragPos;\n"
    "in vec3 Normal;\n"
    "uniform vec3 lightPos;\n"
    "uniform vec3 lightColor;\n"
    "uniform vec3 objectColor;\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "    // 计算光线方向
    "    vec3 lightDir = normalize(lightPos - fragPos);\n"
    "    // 计算表面法线方向
    "    vec3 normal = normalize(Normal);\n"
    "    // 计算漫反射光照强度
    "    float diffuse = max(dot(lightDir, normal), 0.0);\n"
    "    // 计算最终颜色
    "    FragColor = vec4(diffuse * objectColor, 1.0);\n"
    "}\n";

// 主函数
int main()
{
    // 初始化GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 创建窗口
    GLFWwindow *window = glfwCreateWindow(800, 600, "甜甜圈渲染", NULL, NULL);
    if (window == NULL)
    {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // 加载并编译着色器
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    // 创建着色器程序
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    // 设置光源位置和颜色
    glm::vec3 lightPos = glm::vec3(1.0f, 1.0f, 1.0f);
    glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f);

    // 设置物体颜色
    glm::vec3 objectColor = glm::vec3(1.0f, 0.0f, 0.0f);

    // 获取着色器中的uniform变量的位置
    GLint modelLoc = glGetUniformLocation(shaderProgram, "model");
    GLint viewLoc = glGetUniformLocation(shaderProgram, "view");
    GLint projectionLoc = glGetUniformLocation(shaderProgram, "projection");
    GLint lightPosLoc = glGetUniformLocation(shaderProgram, "lightPos");
    GLint lightColorLoc = glGetUniformLocation(shaderProgram, "lightColor");
    GLint objectColorLoc = glGetUniformLocation(shaderProgram, "objectColor");

    // 创建甜甜圈模型
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // 创建顶点缓冲对象
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // 填充顶点数据
    // ...

    // 启用顶点属性
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));

    // 创建索引缓冲对象
    GLuint ibo;
    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

    // 填充索引数据
    // ...

    // 设置模型、视图和投影矩阵
    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view = 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 projection = glm::perspective(45.0f, 800.0f / 600.0f, 0.1f, 100.0f);

    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
        // 清空颜色缓冲和深度缓冲
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // 使用着色器程序
        glUseProgram(shaderProgram);

        // 设置uniform变量
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
        glUniform3fv(lightPosLoc, 1, glm::value_ptr(lightPos));
        glUniform3fv(lightColorLoc, 1, glm::value_ptr(lightColor));
        glUniform3fv(objectColorLoc, 1, glm::value_ptr(objectColor));

        // 绘制甜甜圈模型
        glBindVertexArray(vao);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        // 交换缓冲
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 释放资源
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ibo);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

运行效果

运行代码后,您将看到一个甜甜圈模型,模型上应用了光照效果,看起来更加逼真。您还可以通过修改光源的位置、方向、颜色和强度来改变甜甜圈模型的渲染效果。