OpenGL学习笔记九——光照3实现三种光照类型:平行光,点光源,聚光灯

  • 前言
  • 平行光
    • 代码表示
  • 点光
    • 衰减
    • 代码实现
  • 聚光
    • 实现代码
    • 带有渐变边缘

前言

在上一次介绍光照时曾大概介绍了三种光照

图片选自LearnOpenGL

平行光

最简单来说,平行光可以理解为太阳光,光有固定的颜色和统一的方向,且衰减值可以忽略,即光照强度和距离没有关系。如图:

代码表示

#version 330 core
out vec4 FragColor;struct Material {sampler2D diffuse;sampler2D specular;    float shininess;
}; struct Light {//vec3 position;vec3 direction;vec3 ambient;vec3 diffuse;vec3 specular;
};in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;uniform vec3 viewPos;
uniform Material material;
uniform Light light;void main()
{// ambientvec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;// diffuse vec3 norm = normalize(Normal);// vec3 lightDir = normalize(light.position - FragPos);vec3 lightDir = normalize(-light.direction);  float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;  // specularvec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);  float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;  vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);
}

点光

点光源可以简单理解为点灯,光由一点发出,并且随着距离越来越远,光照强度也越来越弱

衰减

随着光线传播距离的增长逐渐削减光的强度通常叫做衰减。线性衰减实现容易,但是效果不真实,现实中的衰减效果如图,并非呈现线性衰减:

下面这个公式根据片段距光源的距离计算了衰减值,之后我们会将它乘以光的强度向量:


在这里d代表了片段距光源的距离。接下来为了计算衰减值,我们定义3个(可配置的)项:常数项Kc、一次项Kl和二次项Kq。

  1. 常数项通常保持为1.0,它的主要作用是保证分母永远不会比1小,否则的话在某些距离上它反而会增加强度,这肯定不是我们想要的效果。
  2. 一次项会与距离值相乘,以线性的方式减少强度。
  3. 二次项会与距离的平方相乘,让光源以二次递减的方式减少强度。二次项在距离比较小的时候影响会比一次项小很多,但当距离值比较大的时候它就会比一次项更大了。

代码实现

#version 330 core
out vec4 FragColor;struct Material {sampler2D diffuse;sampler2D specular;    float shininess;
}; struct Light {vec3 position;  vec3 ambient;vec3 diffuse;vec3 specular;float constant;float linear;float quadratic;
};in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;uniform vec3 viewPos;
uniform Material material;
uniform Light light;void main()
{// ambientvec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;// diffuse vec3 norm = normalize(Normal);vec3 lightDir = normalize(light.position - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;  // specularvec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);  float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;  // attenuationfloat distance    = length(light.position - FragPos);float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    ambient  *= attenuation;  diffuse   *= attenuation;specular *= attenuation;   vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);
}

聚光

聚光可以理解为手电筒,光源形状呈圆形,并向四周有衰减

  • LightDir:从片段指向光源的向量。
  • SpotDir:聚光所指向的方向。
  • Phiϕ:指定了聚光半径的切光角。落在这个角度之外的物体都不会被这个聚光所照亮。
  • Thetaθ:LightDir向量和SpotDir向量之间的夹角。在聚光内部的话θ值应该比ϕ值小。

实现代码

#version 330 core
out vec4 FragColor;struct Material {sampler2D diffuse;sampler2D specular;    float shininess;
}; struct Light {vec3 position;  vec3 direction;float cutOff;float outerCutOff;vec3 ambient;vec3 diffuse;vec3 specular;float constant;float linear;float quadratic;
};in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;uniform vec3 viewPos;
uniform Material material;
uniform Light light;void main()
{vec3 lightDir = normalize(light.position - FragPos);// check if lighting is inside the spotlight conefloat theta = dot(lightDir, normalize(-light.direction)); if(theta > light.cutOff) // remember that we're working with angles as cosines instead of degrees so a '>' is used.{    // ambientvec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;// diffuse vec3 norm = normalize(Normal);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;  // specularvec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);  float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;  // attenuationfloat distance    = length(light.position - FragPos);float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    // ambient  *= attenuation; // remove attenuation from ambient, as otherwise at large distances the light would be darker inside than outside the spotlight due the ambient term in the else branchediffuse   *= attenuation;specular *= attenuation;   vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);}else {// else, use ambient light so scene isn't completely dark outside the spotlight.FragColor = vec4(light.ambient * texture(material.diffuse, TexCoords).rgb, 1.0);}
}

带有渐变边缘

#version 330 core
out vec4 FragColor;struct Material {sampler2D diffuse;sampler2D specular;    float shininess;
}; struct Light {vec3 position;  vec3 direction;float cutOff;float outerCutOff;vec3 ambient;vec3 diffuse;vec3 specular;float constant;float linear;float quadratic;
};in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;uniform vec3 viewPos;
uniform Material material;
uniform Light light;void main()
{// ambientvec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;// diffuse vec3 norm = normalize(Normal);vec3 lightDir = normalize(light.position - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;  // specularvec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);  float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;  // spotlight (soft edges)float theta = dot(lightDir, normalize(-light.direction)); float epsilon = (light.cutOff - light.outerCutOff);float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);diffuse  *= intensity;specular *= intensity;// attenuationfloat distance    = length(light.position - FragPos);float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));    ambient  *= attenuation; diffuse   *= attenuation;specular *= attenuation;   vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);
}

OpenGL学习笔记九——光照3(实现三种光照类型:平行光,点光源,聚光灯)相关推荐

  1. mongo学习笔记四:Mongodb的三种集群(Replica Set)

    Replica Set    中文翻译叫做副本集,不过我并不喜欢把英文翻译成中文,总是感觉怪怪的.其实简单来说就是集群当中包含了多份数据,保证主节点挂掉了,备节点能继续提供数据服务,提供的前提就是数据 ...

  2. 计算机视觉与图像处理学习笔记之人脸识别的三种方法

    人脸检测是指在图像中完成人脸定位的过程,而人脸识别是在人脸检测的基础上进一步判断人的身份,OpenCV提供了三种人脸识别的方法:EigenFaces(特征脸).FisherFaces(人鱼脸).Loc ...

  3. Silverlight学习笔记(九)-----RenderTransform特效【五种基本变换】及【矩阵变换MatrixTransform】...

    RenderTransform特效: 变形(RenderTransform)类是为了达到直接去改变某个Silverlight对象的形状(比如缩放.旋转一个元素)的目的而设计的,RenderTransf ...

  4. opengl对三种光源(方向光,点光源,聚光灯)进行特写并分屏渲染

    分屏特写渲染效果图 实现原理 1,创建3个fbo 2,分别将方向光,点光源,聚光灯的照射效果渲染到fbo 3,在将渲染好的三个fbo作为纹理贴到要绘制的三个四边形上. 渲染入口 #include &l ...

  5. 【OpenGL学习笔记⑧】——键盘控制正方体+光源【冯氏光照模型 光照原理 环境光照+漫反射光照+镜面光照】

    ✅ 重点参考了 LearnOpenGL CN 的内容,但大部分知识内容,小编已作改写,以方便读者理解. 文章目录 零. 成果预览图 一. 光照原理与投光物的配置 1.1 光照原理 1.2 投光物 二. ...

  6. Python之OpenGL笔记(38):三种光照通道的合成

    一.目的 1.实现镜面光照射下的棋盘球体: 2.环境光.散射光.镜面光三种光照通道的合成 二.程序运行结果 三.镜面光    现实世界中,当光滑表面被照射时会有方向很集中的反射光.这就是镜面光(Spe ...

  7. 吴恩达《机器学习》学习笔记九——神经网络相关(1)

    吴恩达<机器学习>学习笔记九--神经网络相关(1) 一. 非线性假设的问题 二. 神经网络相关知识 1.神经网络的大致历史 2.神经网络的表示 3.前向传播:向量化表示 三. 例子与直觉理 ...

  8. ROS学习笔记九:用C++编写ROS发布与订阅

    ROS学习笔记九:用C++编写ROS发布与订阅 本节主要介绍如何用C++编写一个简单的ROS发布与订阅. 编写发布节点 在之前创建的例子beginner_tutorials软件包中,在其目录下的src ...

  9. at24c16如何划分出多个读写区_AVR学习笔记九、基于AT24C16的数据存储实验

    Ema{@AVR 学习笔记九.基于 AT24C16 的数据存储实验 ------- 基于 LT_Mini_M16 9.1 用 I/O 口模拟 I2C 总线实现 AT24C16 的读写 9.1.1 .实 ...

  10. OpenGL学习笔记:矩阵变换

    文章目录 缩放 glm矩阵表示 glm缩放矩阵实现 位移 齐次坐标 glm位移矩阵实现 旋转 沿x轴旋转 沿y轴旋转 沿z轴旋转 沿任意轴旋转 glm旋转矩阵实现 矩阵的组合 glm矩阵组合使用 接上 ...

最新文章

  1. R语言使用ggplot2包的快速可视化函数qplot绘制散点图(分类变量分组配色、连续值程度配色)实战
  2. 最基本的Socket编程 C#版
  3. python中change的用法_vue中select的使用、默认选择、onchange/change事件等操作实例
  4. Tomcat——设置管理员的用户名和密码
  5. hash算法_数据库中间件分片算法之hash
  6. DataTable转成List集合
  7. 身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」
  8. HBuilder 模拟器
  9. eclipse目录发布到tomcat对应的目录
  10. oracle jdk下载镜像
  11. 全球免费开放的电子图书馆
  12. Timesten安装
  13. 让手机成为电脑的摄像头,Droidcam(linux) 的安装及使用
  14. 外汇交易的主服务器中心,常见外汇交易商服务器ip地址汇总【转载】
  15. scala安装与配置(详细步骤)
  16. Win11系统Windows.old能删除吗?Windows.old怎么删?
  17. web前端学习135-144(盒子模型---网页布局,盒子模型组成,边框,表格细线边框,盒子实际大小,内边距)
  18. C语言程序设计学习笔记:P3-判断
  19. 读取raw格式数据,OpenCV显示
  20. thinkpad E430 电源连接未充电的问题解决方法

热门文章

  1. java“的注脚_百度得到的数据如何写脚注
  2. R语言ggplot2可视化(细节优化)
  3. 高校医科能转专业去计算机工科,转专业详细(2017最新版)想
  4. 如何设计出骚气的秒杀系统?
  5. 远程计算机如果关机咋办,远程界面不小心关机
  6. 考研面试php,考研复试 | 盘点:这些院校已公布2019考研复试内容
  7. 2019-05-22 Domain注入工具;旁注工具;ASP木马;
  8. 如何才能做好短线交易?这三点你要知道!
  9. cf英文名字格式好看的_格式好看的cf英语名字【三篇】
  10. 浙大玉泉校区-武林门民航售票处-萧山机场