当前位置: 首页 > ds >正文

WebGL入门:光照原理

一、计算物体的颜色

在日常生活中,我们见到的大多数物体都是基于漫反射光源的光线,从而被人眼看到的,就比如下面这张图

漫反射

反射光的颜色即跟光源的颜色有关,也跟物体本身的颜色有关,颜色的强弱跟入射角也有关系,入射的光线角度不同时,单位面积所接受的能量是不一样的,越垂直照射越亮,基本符合余弦公式,所以得出如下的一个公式

 漫反射颜色 = 入射光颜色 * 表面基地色 * cosθ 

从WebGL数学手记:向量基础-CSDN博客 中可以知道

向量点乘公式:a\bulletb = |a|\bullet|b|\bulletcosθ 

如果向量 a和向量b都是单位向量的话,那么他们点乘的结果就是cosθ 

假设一个物体的颜色是红色,rgb值是(1.0,0.0,0.0),而光源的颜色是白色(1.0,1.0,1.0),那么它俩计算出的颜色就是

表面基地颜色[1.0,0.0,0.0]  * 入射光颜色[1.0,1.0,1.0] = [1.0,0.0,0.0] 

考虑入射角的话就需要乘 cosθ ,假设角度是60度,cosθ=0.5,

表面基地颜色[1.0,0.0,0.0]  * 入射光颜色[1.0,1.0,1.0] * cosθ  = [0.5,0.0,0.0] 

 最终的颜色就是比较弱的红光

二、计算点光源下物体的颜色

从事上面的描述中,我们基本可以知道,要想知道物体的颜色,需要知道原物体的颜色,物体顶点位置的法线与光照方向的角度,所以在webgl中要提供顶点的法向量信息

  // 创建立方体顶点const vertices = new Float32Array([// 前面1.0, 1.0, 1.0,  -1.0, 1.0, 1.0,  -1.0,-1.0, 1.0,   1.0,-1.0, 1.0,// 后面1.0, 1.0,-1.0,  -1.0, 1.0,-1.0,  -1.0,-1.0,-1.0,   1.0,-1.0,-1.0,// 顶面1.0, 1.0, 1.0,   1.0, 1.0,-1.0,  -1.0, 1.0,-1.0,  -1.0, 1.0, 1.0,// 底面1.0,-1.0, 1.0,   1.0,-1.0,-1.0,  -1.0,-1.0,-1.0,  -1.0,-1.0, 1.0,// 右面1.0, 1.0, 1.0,   1.0,-1.0, 1.0,   1.0,-1.0,-1.0,   1.0, 1.0,-1.0,// 左面-1.0, 1.0, 1.0,  -1.0,-1.0, 1.0,  -1.0,-1.0,-1.0,  -1.0, 1.0,-1.0])// 立方体顶点的法线信息const normals = new Float32Array([// 前面0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,// 后面0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0,// 顶面0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,// 底面0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,// 右面1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,// 左面-1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0])

 经过一系列的 gl.bindBuffer 和 gl.bufferData 后 进入顶点着色器

1.顶点着色器

const VSHADER_SOURCE = `attribute vec4 a_Position;attribute vec4 a_Normal;//模型矩阵、视图矩阵、投影矩阵uniform mat4 u_MvpMatrix;uniform mat4 u_ModelMatrix;//法线的逆转置矩阵(用于计算仿射变换后的物体法向量)uniform mat4 u_NormalMatrix;//世界坐标系下的法向量varying vec3 v_Normal;//世界坐标系下的坐标varying vec3 v_Position;void main() {gl_Position = u_MvpMatrix * a_Position;v_Position = vec3(u_ModelMatrix * a_Position);v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));}
`

这个顶点着色器中的关键信息有好多

1.1逆转置矩阵

仿射变换后的法向量 = 原法向量 * 模型矩阵的逆转置矩阵

1.2.Mvp矩阵 

Mvp矩阵 = 模型矩阵 * 视图矩阵 * 投影矩阵

1.3.内插法向量 

其实最简单的做法是在顶点着色器中根据顶点位置直接结算每个顶点对应的颜色值,然后由varying修饰符传递给片元着色器做内插,但是实际上这样的效果不是太逼真,所以一般的做法是在顶点着色器中计算顶点坐标的世界坐标系和世界坐标系下的法向量,然后用varying修饰符传递给片元着色器做内插,从片元着色器中计算光照方向更准确,也更逼真

2.片元着色器

const FSHADER_SOURCE = `precision mediump float;uniform vec3 u_LightPosition;uniform vec3 u_AmbientLight;uniform vec3 u_LightColor;varying vec3 v_Normal;varying vec3 v_Position;void main() {vec3 normal = normalize(v_Normal);vec3 lightDirection = normalize(u_LightPosition - v_Position);float nDotL = max(dot(lightDirection, normal), 0.0);vec3 diffuse = u_LightColor * nDotL;vec3 ambient = u_AmbientLight;vec3 baseColor = vec3(0.8, 0.0, 0.0);gl_FragColor = vec4((diffuse + ambient) * baseColor, 1.0);}
`

 片元着色器中的关键信息点如下

2.1 normalize 归一化

webgl提供的归一化方法,用于把向量转换成单位向量

2.2 lightDirection 光照方向

vec3 lightDirection = normalize(u_LightPosition - v_Position);

光照方向 = 光源向量 - 物体顶点位置 

2.3 diffuse 漫反射光

漫反射颜色 = 入射光颜色 * 表面基地色 * cosθ 

在不考虑表面基底色的情况下,由公式可以得到

float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = u_LightColor * nDotL;

2.4 环境光 

 实际生活中环境光是普遍存在的,比如太阳光,月光,星光等等,在大环境的范围内影响看到的物体,所以为了更贴近生活,一般在考虑实际光源的情况下,还要把环境中的光也考虑进去,所以最终的颜色是漫反射光加环境光

diffuse + ambient

最终的颜色是

vec3 baseColor = vec3(0.8, 0.0, 0.0);
gl_FragColor = vec4((diffuse + ambient) * baseColor, 1.0);

三、源码

传送门

 

http://www.xdnf.cn/news/6048.html

相关文章:

  • binlog日志以及MySQL的数据同步
  • 项目三 - 任务5:清洗网址中垃圾字符
  • 电池自动点焊机:多领域电池制造的核心设备
  • UE5中制作动态数字Decal
  • ES6 语法
  • Rust 环境变量管理秘籍:从菜鸟到老鸟都爱的 dotenv 教程
  • Visual studio 打包方法
  • 计算机系统----软考中级软件设计师(自用学习笔记)
  • Biba安全模型详解:守护信息系统完整性的基石
  • 加速度策略思路
  • SwarmUI 基于.NET开发的开源AI图像生成WEB用户界面系统
  • git-gui界面汉化
  • 【3-2】HDLC
  • 详解注意力机制
  • Linux文件编程——读写结构体、链表等其他类型的数据
  • 9.9 Ollama私有化部署Mistral 7B全指南:命令行交互到API集成全流程解析
  • 格雷希尔G10和G15系列自动化快速密封连接器,适用于哪些管件的密封,以及它们相关的特性有哪些?
  • 参考UTD的上市公司供应链信息数据库(2017-2022)
  • 深度学习模型在目标检测任务中的前向传播(forward)和反向传播(backward)过程
  • 基于STM32、HAL库的TLV320AIC3101IRHBR音频接口芯片驱动程序设计
  • NovaMSS v1.40音乐源分离工具,一键提取伴奏人声贝斯鼓点分离音轨等
  • 交流充电桩IEC 61851-1和IEC 61851-21-2标准测试项目
  • Deno、Bun、Node.js 性能对比与选型指南
  • C++23 ranges::range_adaptor_closure:程序定义的范围适配器闭包的辅助类
  • flutter Stream 有哪两种订阅模式。
  • 从新手到高手:全面解析 AI 时代的「魔法咒语」——Prompt
  • Hue面试内容整理-后端框架
  • C++11异步编程 --- async
  • 多目应用:三目相机在汽车智能驾驶领域的应用与技术创新
  • Generative Diffusion Prior for Unified Image Restoration and Enhancement论文阅读