计算机图形学(5):OpenGL光照

news/2024/11/29 10:49:10/

参考

介绍
现实世界中的光照是极其复杂,难以计算的,因此OpenGL的光照使用的是简化的模型,其中一个模型被称为冯氏光照模型(Phong Lighting Model)。

冯氏光照模型的主要结构由三个分量组成:

环境(Ambient)光照
漫反射(Diffuse)光照
镜面(Specular)光照

环境光照

光的一大特点是,它可以向很多方向发散并反弹,所以现实环境周围通常总会有些光亮,对应的物体通常都会反射些微弱的光。
计算:

用一个很小的分量乘以光的颜色,最后乘以物体的颜色

漫反射光照

漫反射光照使物体与光线方向越接近的片段能充光源处获得更多的亮度。

image.png

如果光线垂直于物体表面,这束光对物体的影响会最大化(译注:更亮)。

可以大致理解为

片段的漫反射光照 = (光源坐标到片段坐标的向量与片段法向量的夹角) * 光源颜色

注意两个向量都要先归一化
为了计算漫反射光照我们需要知道这几个值:

片段所在面的法向量
光源的世界坐标
片段的世界坐标
最后目前片段的颜色为: (环境光照值+漫反射光照值) * 片段自身颜色

镜面光照

镜面光照决定于表面的反射特性。如果我们把物体表面设想为一面镜子,那么镜面光照最强的地方就是我们看到表面上反射光的地方。如下图:

image.png

为此我们还需要一个观察者坐标(即摄像机)。光的反射向量与观察方向之间夹角越小,镜面光照效果越强。

最终效果:
在这里插入图片描述
在这里插入图片描述
主要代码:

std::vector<float> sphereVertices;std::vector<int> sphereIndices;// 生成球的顶点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);}}// 生成球的Indicesfor (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);}}float cube[] = {-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,-0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,-0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,-0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,-0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,-0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,-0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f};//sphere---lightglBindVertexArray(VAO[2]);glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[2]);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);//cubeglBindVertexArray(VAO[3]);glBindBuffer(GL_ARRAY_BUFFER, VBO[3]);glBufferData(GL_ARRAY_BUFFER, sizeof(cube), cube, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));glEnableVertexAttribArray(1);

每次渲染时都绑定信息:

//让光源绕原点旋转float distance = 2.0f;float lightY = sin(glfwGetTime()) * distance;float lightZ = -(cos(glfwGetTime()) * distance);float lightX = sin(glfwGetTime()) * distance;//lightPos.x = lightX; lightPos.y = 1; lightPos.z = 1.2;						//直线移动lightPos.x = lightX; lightPos.y = lightY; lightPos.z = lightZ;			//环绕移动shader.use();model = glm::mat4(1.0f);shader.setMat4("model", model);shader.setMat4("projection", projection);shader.setMat4("view", view);shader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);shader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);shader.setVec3("lightPos", lightPos);shader.setVec3("viewPos", camera.position);glBindVertexArray(VAO[3]);glDrawArrays(GL_TRIANGLES, 0, 36);glBindVertexArray(0);light_shader.use();model = glm::mat4(1.0f);model = glm::translate(model, lightPos);model = glm::scale(model, glm::vec3(0.1f));light_shader.setMat4("model", model);light_shader.setMat4("projection", projection);light_shader.setMat4("view", view);glBindVertexArray(VAO[2]);glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);//glDrawArrays(GL_TRIANGLES, 0, 36);glBindVertexArray(0);

顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;out vec3 FragPos;
out vec3 Normal;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{FragPos = vec3(model * vec4(aPos, 1.0));mat3 normalMatrix = mat3(transpose(inverse(model)));Normal = normalMatrix * aNormal; // 计算法向量经过模型变换后值gl_Position = projection * view * vec4(FragPos, 1.0);
}

片段着色器:

#version 330 core
out vec4 FragColor;in vec3 Normal;  
in vec3 FragPos;  uniform vec3 lightPos; 
uniform vec3 lightColor;
uniform vec3 objectColor;
uniform vec3 viewPos; void main()
{// ambientfloat ambientStrength = 0.1;vec3 ambient = ambientStrength * lightColor;// diffuse vec3 norm = normalize(Normal);vec3 lightDir = normalize(lightPos - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = diff * lightColor;// specularfloat specularStrength = 0.5;vec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);  float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);vec3 specular = specularStrength * spec * lightColor; //距离影响光照强度,暂时是我自己想的float enableDistance = 4.0f;	//有效光照距离vec3 light2fragVec = lightPos - vec3(FragPos);float distan = min(sqrt(light2fragVec.x * light2fragVec.x + light2fragVec.y * light2fragVec.y + light2fragVec.z * light2fragVec.z), enableDistance);float strength = 1 - distan / enableDistance;//光照远近先不影响环境光照了vec3 result = ambient*objectColor+(diffuse + specular) * objectColor*strength;FragColor = vec4(result, 1.0);
} 

光源的顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);
}

光源的片段着色器:

#version 330 core
out vec4 FragColor;void main()
{FragColor = vec4(1.0); // set all 4 vector values to 1.0
}

http://www.ppmy.cn/news/48715.html

相关文章

【C/C++】结构体对齐详解

文章目录 结构体内存对齐原则结构体对齐方法结构体对齐意义 结构体内存对齐原则 结构体内存对齐是由编译器自动完成的&#xff0c;编译器会按照一定的规则将结构体成员按照一定的字节对齐方式排列在内存中。不同的编译器可能会有不同的对齐规则&#xff0c;但通常都遵循以下几…

第三章 作业(7BF)【计算机系统结构】

第三章 作业&#xff08;7BF&#xff09;【计算机系统结构】 前言推荐第三章 作业&#xff08;7BF&#xff09;71115鲲鹏流水线调研华为鲲鹏处理器ARM体系的总体思想ARM的流水线结构 最后 前言 2023-4-10 18:49:41 以下内容源自《【计算机系统结构】》 仅供学习交流使用 推荐…

瀚高股份吕新杰:创新开源双驱动 躬耕国产数据库

近年来&#xff0c;国际形势不断变幻&#xff0c;也给人们带来巨大警示&#xff1a;关键核心技术是买不来、讨不来的&#xff0c;中国科技企业需寻找研发自强之路。 瀚高基础软件股份有限公司&#xff08;简称瀚高股份&#xff09;专注数据库十八年&#xff0c;始终以“振兴民…

003+limou+C语言链表之“无头单向非循环链表”的实现

0、前要&#xff1a;顺序表的缺陷 在倍数增容的时候&#xff0c;存储空间存在一定的空间浪费增容需要申请空间、拷贝数据、释放旧空间&#xff0c;有不小的消耗头部或者中部的插入、删除效率低下&#xff0c;时间复杂度是O(N)查找搜索缓慢&#xff0c;但是这个其实是可以靠树来…

Unity --- UGUI(Unity Graphical user interface)--- Canvas画布

1.UI --- User Interface --- 使用者与机器之间的交互界面 1.所谓的自适应系统指的是分辨率的适应&#xff1a; 比如在一个分辨率下做的UI放到另一个分辨率下显示时&#xff0c;如果没有自适应系统的话就会导致UI过大&#xff0c;过小&#xff0c;被辟成一半等等情况&#xff…

Excel函数培训目录

Excel快捷键★查找删除重复项★★数据透视表★★VLOOKUP 与 INDEX(MATCH())★★★多条件查找选择性粘贴 | 转置 与 运算 ★数据格式验证 ★ 函数 文本函数 文本函数ValueTRIM()去空TEXT()转换文本格式MID()中取LEFT()左取RIGHT()右取LEN()字符数量LENB()字节长度 查找函数 …

python批量下载怀俄明大学探空数据Wyoming soundings并处理

下载怀俄明大学的探空数据&#xff0c;之前用的是气象家园写的maltab脚本&#xff0c;但总是链接不上&#xff0c;而且有的站点需要用新网址&#xff0c;有的有需要用老网址&#xff0c;很麻烦&#xff0c;痛定思痛用决定终于用python了&#xff0c;主要有两种方式&#xff0c;…

傅里叶级数FS,连续时间傅里叶变换CTFT,离散时间傅里叶变换DTFT,离散傅里叶变换DFT,推导与联系(一)

本文主要从傅里叶级数 FS&#xff0c;连续时间傅里叶变换 CTFT&#xff0c;离散时间傅里叶变换 DTFT&#xff0c;以及离散傅里叶变换 DFT 之间的区别与联系进行了比较详细的讨论&#xff0c;主要注重于公式形式上的推导&#xff0c;略去了相关的图像示例&#xff0c;对于傅里叶…