颜色 - 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的数量。