1.demo效果


如上,添加了漫反射光照射效果的立方体,最前面的面亮一些,顶上和右侧的面暗一些

2.光照原理

现实中,物体被光线照射,会有一部分光在物体表面反射,当反射光线进入你的眼睛时,你就看到了物体的形状与颜色,现实生活中你会发现,有光照照射物体时会在地面上投下影子,物体表面会出现明暗程度不一样的效果,正是因为存在影子(阴影)和明暗差异使得我们看到物体具有立体感。

2.1光源类型

真实世界中存在两种类型的光:平行光和点光源光,平行光类似于太阳光,点光源类似于灯泡、手电筒的光;在WebGL中,光源主要分为三类:平行光、点光源、环境光
平行光的光线相互平行,具有方向,可以看做是无限远处的光源发出的光,列如太阳照射在地球上的光。
点光源是从一个点向周围的所有方向发出的光,例如灯泡和火焰发出的光
环境光也叫做间接光,指光源发出的光被墙壁或物体多次反射后照射的物体表面的光,比如夜间打开冰箱周围都会有微亮的光,环境光不用指定位置和方向,只需要指定颜色即可

2.2反射类型

物体表面反射光线的方式有两种:漫反射和环境反射,漫反射是针对平行光和点光源,环境反射是针对环境光的。

2.3漫反射计算模型

漫反射的决定因素有两个

  • 入射光 入射光的信息包括入射光的方向和颜色
  • 物体表面类型 物体表面信息包括固有颜色(也称基地色 也就是几何体本身的颜色)和反射特性
    <漫反射光颜色> = <入射光颜色> x <表面基底色> x cosθ
    θ表示入射角,即入射光与物体表面法线的夹角
    在创建三维模型的时候我们无法预先确定光线照射到物体表面的入射角,但是我们可以确定物体每个表面的法向量,同时可以指定光源的方向,有了物体表面的法向量和光源信息就可以计算出入射角了。
    我们可以通过计算两个向量的点积来计算这两个向量夹角的余弦值:
    cosθ = <入射光线方向> ● <法线方向>
    将该等式带入漫反射计算模型中得到
    <漫反射光颜色> = <入射光颜色> x <表面基底色> x ( <入射光线方向> ● <法线方向>)
    光线方向矢量和表面法线矢量长度必须为1,也就是使用前必须进行归一化处理,否则反射光的颜色会过暗或过亮

3.demo代码

const VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal; //法向量
uniform vec3 u_LightColor; //光线颜色
uniform vec3 u_LightDirection; //光线方向(归一化)
uniform vec3 u_AmbientLight;uniform mat4 u_MvpMatrix;
varying vec4 v_Color;void main() {gl_Position = u_MvpMatrix*a_Position;//法线向量归一化vec3 normal = normalize(vec3(a_Normal));//求夹角  法向与入射光线夹角的余弦值float nDotL = max(dot(u_LightDirection,normal),0.0);//计算漫反射光的颜色vec3 diffuse = u_LightColor*vec3(a_Color)*nDotL;//计算环境光产生的反射光颜色vec3 ambient = u_AmbientLight*a_Color.rgb;v_Color=vec4(diffuse+ambient,1.0);
}
`;const FSHADER_SOURCE = `
precision mediump float;
varying vec4 v_Color;
void main() {gl_FragColor = v_Color;
}
`;const main = () => {const canvas = document.getElementById("webgl");const gl = canvas.getContext("webgl");if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.error("failed to init shaders");}//视点,视线,上方向const viewMat = new Matrix4().setLookAt(3,3,7,0.0,0.0,0.0,0.0,1.0,0.0);const modelMat = new Matrix4().setRotate(0, 0, 0);const projMat = new Matrix4();projMat.setPerspective(30, canvas.width / canvas.clientHeight, 1.0, 100);const mvpMat = new Matrix4().setIdentity().multiply(projMat).multiply(viewMat).multiply(modelMat);const u_MvpMatrix = gl.getUniformLocation(gl.program, "u_MvpMatrix");const u_LightColor = gl.getUniformLocation(gl.program, "u_LightColor");const u_LightDirection = gl.getUniformLocation(gl.program,"u_LightDirection");const u_AmbientLight= gl.getUniformLocation(gl.program,'u_AmbientLight');gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);//设置光的颜色 白色gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);//设置光线方向(世界坐标系下的)const lightDirection = new Vector3([0.5, 3.0, 4.0]);lightDirection.normalize();gl.uniform3fv(u_LightDirection, lightDirection.elements);gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMat.elements);const vertexData = 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, //front面 v0-41.0,1.0,1.0,1.0,-1.0,1.0,1.0,-1.0,-1.0,1.0,1.0,-1.0, //right v03451.0,1.0,1.0,1.0,1.0,-1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0, //up v0561-1.0,1.0,1.0,-1.0,-1.0,1.0,-1.0,-1.0,-1.0,-1.0,1.0,-1.0, //left-1.0,-1.0,1.0,1.0,-1.0,1.0,1.0,-1.0,-1.0,-1.0,-1.0,-1.0, //down1.0,-1.0,-1.0,1.0,1.0,-1.0,-1.0,1.0,-1.0,-1.0,-1.0,-1.0, //back]);//   const colorData = new Float32Array([//     0.4,0.4,1.0,//     0.4,0.4,1.0,//     0.4,0.4,1.0,//     0.4,0.4,1.0, //front//     0.4,1.0,0.4,//     0.4,1.0,0.4,//     0.4,1.0,0.4,//     0.4,1.0,0.4, //right//     1.0,0.4,0.4,//     1.0,0.4,0.4,//     1.0,0.4,0.4,//     1.0,0.4,0.4, //up//     1.0,1.0,0.4,//     1.0,1.0,0.4,//     1.0,1.0,0.4,//     1.0,1.0,0.4, //left//     1.0,0.4,1.0,//     1.0,0.4,1.0,//     1.0,0.4,1.0,//     1.0,0.4,1.0, //btm//     0.4,1.0,1.0,//     0.4,1.0,1.0,//     0.4,1.0,1.0,//     0.4,1.0,1.0, //back//   ]);const colorData = 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, //front1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, //right1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, //up1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, //left1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, //btm1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, //back]);const indicesData = new Uint8Array([0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14,15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23,]);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, 1.0, 0.0, 0.0,1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.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, 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, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0,]);const initArrayBuffer = (gl, data, name, num, type) => {//创建缓冲区const vertexBuffer = gl.createBuffer();//绑定taggl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);//像缓冲区传入数据gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);const vertexLocation = gl.getAttribLocation(gl.program, name);//分配缓冲区gl.vertexAttribPointer(vertexLocation, num, type, false, 0, 0);//启用缓冲区gl.enableVertexAttribArray(vertexLocation);return true;};const initIndexBuffer = (gl, indexData) => {const indicesBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW);};initArrayBuffer(gl, vertexData, "a_Position", 3, gl.FLOAT);initArrayBuffer(gl, colorData, "a_Color", 3, gl.FLOAT);initArrayBuffer(gl, normals, "a_Normal", 3, gl.FLOAT);initIndexBuffer(gl, indicesData);const n = indicesData.length;gl.enable(gl.DEPTH_TEST);gl.clearColor(0.0, 0.0, 0.0, 1.0);gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);let CURRENT_TIMESTAMP = Date.now();const tick = (speed) => {const now = Date.now();const interval = now - CURRENT_TIMESTAMP;CURRENT_TIMESTAMP = now;const angle = (interval * speed) / 1000;modelMat.setRotate(angle, 0, -1, 0);const rotateMatrix = gl.getUniformLocation(gl.program,'u_RotateMatrix');gl.uniformMatrix4fv(rotateMatrix,false,modelMat.elements);gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);  requestAnimationFrame(tick);console.log('执行了')return modelMat;};
//   tick()
};main();

WebGL编程指南-23 光照原理、漫反射光计算、漫反射光照射下的立方体相关推荐

  1. 【WebGL编程指南】GLSL ES语法基础

    [WebGL之巅]20-GLSL ES着色器语言语法详解 查看原文:[WebGL之巅]20-GLSL ES着色器语言语法详解 对应<WebGL编程指南>第六章 GLSL ES 总览 本章知 ...

  2. 【《WebGL编程指南》读书笔记-WebGL入门】

    <WebGL编程指南>读书笔记 目录链接:https://blog.csdn.net/floating_heart/article/details/124001572 第二章 WebGL入 ...

  3. 【WebGL】《WebGL编程指南》读书笔记——第5章

    一.前言        终于到了第五章了,貌似开始越来越复杂了. 二.正文         Example1:使用一个缓冲区去赋值多个顶点数据(包含坐标及点大小) function initVerte ...

  4. 【WebGL】《WebGL编程指南》读书笔记——第2章

    一.前言 最近看了<WebGL编程指南>这本书,发现还是很有意思的,故每章阅读后做个笔记. 二.正文 Example1:在canvas中绘制2D矩形 <!DOCTYPE html&g ...

  5. 【《WebGL编程指南》读书笔记——着色器和程序对象的准备】

    本文为<WebGL编程指南>第九章下半部分读书笔记 总目录链接:https://blog.csdn.net/floating_heart/article/details/124001572 ...

  6. WebGL编程指南-27 逐片元处理点光源光照效果

    1.demo效果 如上图,图二为逐片元处理点光源的效果,与之前的demo效果相比,物体表面的光照效果更佳柔和.细腻. 2.实现要点 在上一章中实现方式是逐顶点的方式,实现点光源在照射到立方体呈现出的效 ...

  7. WebGL编程指南-24 同时使用漫反射光和环境反射光、立方体平移旋转缩放变换时漫反射光和环境反射光处理

    1.demo效果 此效果是上一章绘制的立方体基础上,向Y轴方向平移一个单位,然后绕Z轴旋转30度. 如上图,归纳一下物体坐标变换法向量变化的规律如下 平移变换, 法向量不会改变 旋转变换, 大多数情况 ...

  8. WebGL编程指南-19 透视投影

    1.demo效果 如上,通过透视投影矩阵创建了左右两排三角形,呈现在页面中 2.透视投影 上一篇文章中说可视空间分为 正射投影 和 透视投影 ,在正射投影中不管图形与视点的距离是远还是近,图形有多大那 ...

  9. webGL编程指南实战教程

    学习路线: 如果你是在校大学生,有足够的时间去学习:前端>数学(几何+线性代数)>图形学>webgl>shader >threejs>three.js源码 如果你是 ...

最新文章

  1. 【组队学习】【34期】组队学习内容详情
  2. J2EE中的各种工程的介绍
  3. ASP.NET Core 注册单例方案
  4. CodeForces - 1152B二进制+思维
  5. 李洪强-C语言2-字符串
  6. 真无线蓝牙耳机霸主之争:苹果AirPods和索尼WF-1000XM3怎么选?
  7. python怎么和数据库连接_Java和Python都怎么连接数据库
  8. 扇贝有道180926每日一句
  9. PS更换照片底色的方法(红底变白底为例)
  10. 使用IK中文分词器做敏感词过滤
  11. linux查看进程的代码,Linux ps 查看进程(示例代码)
  12. 全开源!智能灯串开发资料全开源!为这个冬天装点烂漫“星空”
  13. 制造业案例 | 美创助力纳爱斯集团三层业务安全审计实践
  14. 好用的电台APP推荐|这些年,陪伴我上下班的声音
  15. Arxiv 2022|NoPe-NeRF:优化无位姿先验的神经辐射场
  16. python俄罗斯方块的消除算法_1.1.3python tkinter实现俄罗斯方块基础版-生成、移动、固定、消除...
  17. 2019年宁波顶岗实习
  18. 蒸馏 (distill_Distill-BERT:使用BERT进行更智能的文本生成
  19. http 返回码 405 解决方案之一
  20. python调用mysql数据_python使用mysql数据库(虫师)

热门文章

  1. 【JZOJ 省选模拟】铺路 (road )
  2. 又是一年高考季,Python爬虫数据分析家庭亲情剧《小欢喜》
  3. Linux授予权限命令
  4. kettle资源库备份
  5. 解决浏览器主页被劫持问题
  6. DNS知识点及服务搭建案例和解析状态异常
  7. 数字音视频编解码技术标准工作组会员单位
  8. 【树莓派】关于树莓派2代,更新最新内核后,DS18B20温度传感器无法找到对应文件的问题的解决
  9. odoo 恢复数据库前端报错
  10. 相传国际象棋是古印度舍罕王的宰相达依尔发明的.舍罕王十分喜爱象棋,决定让宰相自己选择何种赏赐.这位聪明的宰相指着8*8共64格的象棋说:陛下,请您赏给我一些麦子吧.就在棋盘的第1格放1粒,第2格放2粒