openGL GLFW 学习笔记 m8w1

颜色 - LearnOpenGL CN 这部分是OpenGL光照部分的学习笔记,内容比较杂乱

绘制出光源模型

LearnOpenGL中给的是正方形的光源模型,这里修改成了球形的光源,更符合一些。

【生成球形顶点坐标】之前提到过,用两个欧拉角可以生成一个方向向量,这里一个欧拉角从0到2π被等分成N份,另一个欧拉角从0到π被等分成N份。如下图,可以看到这两个欧拉角正好可以全覆盖整个球形的表面。

然后用和上一篇笔记一样的方法,把欧拉角转换为3D空间的坐标,并取每4个相邻的顶点构成的矩形创建两个三角形的顶点索引。

// 创造球型光源顶点
    // 生成球的顶点
    int Y_SEGMENTS = 50;
    int X_SEGMENTS = 50;
    vector<float> sphereVertices;
    vector<int> sphereIndices;
    float PI = 3.1415926535;

    for (int y = 0;y <= Y_SEGMENTS;y++)
    {
        for (int x = 0;x <= X_SEGMENTS;x++)
        {
            float xSegment = (float)x / (float)X_SEGMENTS;
            float ySegment = (float)y / (float)Y_SEGMENTS;
            float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
            float yPos = std::cos(ySegment * PI);
            float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
            sphereVertices.push_back(xPos);
            sphereVertices.push_back(yPos);
            sphereVertices.push_back(zPos);
        }
    }

    // 生成球的Indices
    for (int i = 0;i < Y_SEGMENTS;i++)
    {
        for (int j = 0;j < X_SEGMENTS;j++)
        {
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j + 1);
        }
    }

    unsigned int lightVBO, lightVAO, lightEBO;
    glGenBuffers(1, &lightVBO);
    glGenVertexArrays(1, &lightVAO);
    glGenBuffers(1, &lightEBO);

    glBindVertexArray(lightVAO);
    glBindBuffer(GL_ARRAY_BUFFER, lightVBO);
    glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lightEBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

但是这么看来还是不像一个光源,没有向周围发射光线的视觉效果,那么就来加一个泛光。在LearnOpenGL中,泛光在高级光照章节中,实现方法和之前一篇文章记录的Unity shader入门精要笔记中的思路基本差不多,不过实现上区别有点大(TODO)。

想做一个按键显示/不显示鼠标的功能

逻辑很简单,实现出来后发现按一次键会触发这个功能好几次,最后鼠标是消失还是出现全看运气。实现按键检测的方法是按LearnOpenGL自己在main中用loop实现的,glfwGetKey只有三个状态,GLFW_RELEASE(是否处于未按下状态),GLFW_PRESS(是否处于按下状态),GLFW_REPEAT。GLFW_REPEAT只在key_callback回调时会返回。这部分unity就很人性化,有按下,抬起,长按三个状态。所以想要按一次只触发一次功能,得自己写一个状态检测函数,检测是否某个键的状态从0变成了1。

GLFW_REPEAT官方文档解释:

#define GLFW_REPEAT   2:The key was held down until it repeated.

法线变换

我这里是直接用原来的旋转立方体场景,所以同时需要对法线进行变换,不然立方体的光照效果就是静态的。一种简单的方法就是用法线添加一个w维度,值为0,然后和模型变换矩阵(model)相乘,这样只应用了旋转,而没有使用平移(法线变换只需要旋转,无法处理等比缩放的情况);

实现后光照在模型上是动态的了,但是光照方向不对o.O,发现是光线位置的uniform没能正确传入。

glUniform3fv(glGetUniformLocation(ObjShader.ID, "lightPos"), 1, glm::value_ptr(glm::vec3(0.0f, 10.0f, 0.0f)));

第二个参数一开始写错为3了,第二个参数是变量的数量,因为这里lightPos是一个vec3所以这里是1,如果lightPos是vec3数组,第二个参数就填数组中vec3的数量。

posted @ 2024-09-02 18:09  PAddingoi  阅读(6)  评论(0编辑  收藏  举报  来源