1.点光源产生的漫反射光

<漫反射光颜色>=<入射光颜色>x<表面基底色>x cosB

<漫反射光颜色>=<入射光颜色>x<表面基底色>x(<光线方向>x<法线方向>)

由于点光源产生的光线在物体表面任意一点的入射角度都不相同,需要先计算入射方向矢量(由点光源指向顶点),根据矢量做减法在几何中的意义:

<光线方向>=<光源位置矢量>-<顶点矢量>

'vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));\n'

注意:光源位置在设定时使用的是世界坐标系,而顶点位置使用的是canvas坐标系,需要先将顶点位置坐标转变成世界坐标系

'vec4 vertexPosition = u_ModelMatrix * a_Position;\n'

WebGL坐标系之间的转换:

var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'attribute vec4 a_Normal;\n' +
'uniform mat4 u_NormalMatrix;\n' +
'uniform mat4 u_ModelMatrix;\n' +
'uniform vec3 u_LightPosition;\n' +
'uniform vec3 u_LightColor;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'uniform vec3 u_AmbientLight;\n' +
'varying vec4 v_Color;\n' +
'void main(){\n' +
'gl_Position = u_MvpMatrix * a_Position;\n' +
//对法向量进行归一化
'vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
//计算顶点世界坐标
'vec4 vertexPosition = u_ModelMatrix * a_Position;\n' +
//计算光线方向并归一化
'vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));\n' +
//计算光线方向和法向量乘积,已经完成归一化,u_LightDirection在js代码中已经完成归一化
'float nDotL = max(dot(lightDirection,normal),0.0);\n' +
//计算漫反射光的颜色
'vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;\n'+
//计算环境光产生的反射光颜色
'vec3 ambient = u_AmbientLight * a_Color.rgb;\n'+
//a_Color.a是GLSL ES中对矢量的访问符,r,g,b,a
'v_Color = vec4(diffuse + ambient,a_Color.a);\n' +
'}\n';var FSHADER_SOURCE =
'precision mediump float;\n'+
'varying vec4 v_Color;\n' +
'void main(){\n' +
'gl_FragColor = v_Color;\n' +
'}\n';function main(){
var canvas =document.getElementById('webgl');
var gl = canvas.getContext('webgl');
initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE);
var n = initVertexBuffers(gl);
//开启深度检测
gl.enable(gl.DEPTH_TEST);
gl.clearColor(1.0,0.0,0.0,1.0);//获取顶点着色器中变量
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
var u_ModelMatrix = gl.getUniformLocation(gl.program,'u_ModelMatrix');
var u_LightPosition = gl.getUniformLocation(gl.program,'u_LightPosition');
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
//设置光线颜色
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
//设置光源位置
gl.uniform3f(u_LightPosition,0.0,3.0,4.0);
//设置模型矩阵
var modelMatrix = new Matrix4();
modelMatrix.setRotate(90,0,1,0);
gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);//对环境光进行赋值
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);//对法向量矩阵赋值
var normalMatrix = new Matrix4();
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);//计算模型视图投影矩阵
var mvpMatrix = new Matrix4();
mvpMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.lookAt(3,3,7,0,0,0,0,1,0);
mvpMatrix.multiply(modelMatrix);
gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}function initVertexBuffers(gl){
var verteices = 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
]);
var 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,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,//顶面顶点法向量
0.0,-1.0,0.0, 0.0,-1.0,0.0, 0.0,-1.0,0.0, 0.0,-1.0,0.0//底面顶点法向量
]);
var colors = new Float32Array([
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //前面的顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //右面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //后面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //左面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //顶面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //底面顶点颜色
]);
var indices = 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 //底面顶点索引
]);
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);initArrayBuffer(gl,verteices,3,gl.FLOAT,'a_Position');
initArrayBuffer(gl,colors,3,gl.FLOAT,'a_Color');
initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal');
return indices.length;
}
function initArrayBuffer(gl,data,num,type,attribute){
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}

2.逐片元计算反射光的颜色,当场景中有多个点光源,就需要通过逐片元计算每个点光源的反射光颜色,进行相加

思路:(1)使用varying将变换后的顶点的世界坐标传入片元着色器,则片元着色器中接受到了每个片元坐标,即顶点矢量

'varying vec3 v_Position;\n' +

'v_Position = vec3(u_ModelMatrix * a_Position);\n' +

(2)在顶点着色器中进行计算光线方向矢量,并进行归一化,光线方向矢量 = 光源位置矢量 - 顶点矢量。

'vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +

(3)使用varying变量将经过(平移、旋转、缩放)后的法向量归一化后传入片元着色器,

'varying vec3 v_Normal;\n' +

v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +

(4)使用varying将内插后的原片元颜色传入顶点着色器,

'varying vec4 v_Color;\n' +

'v_Color = a_Color;\n'+

(5)在片元着色器中计算<光源颜色>x<片元颜色>x(<光线向量>.<法向量>)

//计算光线方向和法向量的点积

'float nDotL = max(dot(lightDirection,normal),0.0);\n' +

//计算漫反射光颜色

'vec3 diffuse = u_LightColor * vec3(v_Color) * nDotL;' +

(6)在片元着色器中计算环境光的反射光

'uniform vec3 u_AmbientLight;\n' +

'vec3 ambient = u_AmbientLight * v_Color.rgb;\n'+

(7)在片元着色器中计算反射光颜色

'gl_FragColor = vec4(diffuse + ambient,v_Color.a);\n' +

总的来说:顶点着色器和片元着色器分工如下:

顶点着色器:

(1)计算模型、视图、投影变换后的顶点坐标,赋值给gl_Position

(2)计算顶点的世界坐标,使用varying变量,将内插后片元的坐标传递给片元着色器

(3)计算经过模型变换后的法向量并进行归一化,将内插后的每一片元的法向量传递给顶点着色器

(4)将顶点颜色通过varying修饰符,将内插后每一片元的原本颜色传递给片元着色器

片元着色器:

(1)将片元法向量进行归一化

(2)计算光线方向向量并进行归一化

(3)计算点光源的漫反射光颜色

(4)计算环境光的反射颜色

(5)计算总反射光的颜色

4.逐片元计算反射光颜色程序实现:

var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Normal;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_NormalMatrix;\n' +
'uniform mat4 u_ModelMatrix;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'varying vec4 v_Color;\n' +
'varying vec3 v_Normal;\n' +
'varying vec3 v_Position;\n' +
'void main(){\n' +
'gl_Position = u_MvpMatrix * a_Position;\n' +
//计算顶点世界坐标
'v_Position = vec3(u_ModelMatrix * a_Position);\n' +
//对法向量进行归一化
'v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
'v_Color = a_Color;\n'+
'}\n';var FSHADER_SOURCE =
'precision mediump float;\n' +
'uniform vec3 u_LightColor;\n' +
'uniform vec3 u_LightPosition;\n' +
'uniform vec3 u_AmbientLight;\n' +
'varying vec3 v_Normal;\n' +
'varying vec3 v_Position;\n'+
'varying vec4 v_Color;\n' +
'void main(){\n' +
//计算法向量并归一化
'vec3 normal = normalize(v_Normal);\n' +
//计算光线方向并归一化
'vec3 lightDirection = normalize(u_LightPosition - v_Position);\n' +
//计算光线方向和法向量的点积
'float nDotL = max(dot(lightDirection,normal),0.0);\n' +
//计算漫反射光颜色
'vec3 diffuse = u_LightColor * vec3(v_Color) * nDotL;' +
'vec3 ambient = u_AmbientLight * v_Color.rgb;\n'+
'gl_FragColor = vec4(diffuse + ambient,v_Color.a);\n' +
'}\n';function main(){
var canvas =document.getElementById('webgl');
var gl = canvas.getContext('webgl');
initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE);
var n = initVertexBuffers(gl);
//开启深度检测
gl.enable(gl.DEPTH_TEST);
gl.clearColor(1.0,0.0,0.0,1.0);//获取顶点着色器中变量
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
var u_ModelMatrix = gl.getUniformLocation(gl.program,'u_ModelMatrix');
var u_LightPosition = gl.getUniformLocation(gl.program,'u_LightPosition');
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
//设置光线颜色
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
//设置光源位置
gl.uniform3f(u_LightPosition,0.0,3.0,4.0);
//设置模型矩阵
var modelMatrix = new Matrix4();
modelMatrix.setRotate(90,0,1,0);
gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);//对环境光进行赋值
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);//对法向量矩阵赋值
var normalMatrix = new Matrix4();
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);//计算模型视图投影矩阵
var mvpMatrix = new Matrix4();
mvpMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.lookAt(3,3,7,0,0,0,0,1,0);
mvpMatrix.multiply(modelMatrix);
gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}function initVertexBuffers(gl){
var verteices = 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
]);
var 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,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,//顶面顶点法向量
0.0,-1.0,0.0, 0.0,-1.0,0.0, 0.0,-1.0,0.0, 0.0,-1.0,0.0//底面顶点法向量
]);
var colors = new Float32Array([
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //前面的顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //右面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //后面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //左面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //顶面顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //底面顶点颜色
]);
var indices = 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 //底面顶点索引
]);
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);initArrayBuffer(gl,verteices,3,gl.FLOAT,'a_Position');
initArrayBuffer(gl,colors,3,gl.FLOAT,'a_Color');
initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal');
return indices.length;
}
function initArrayBuffer(gl,data,num,type,attribute){
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}

17.光照(点光源)相关推荐

  1. 计算机图形学第三次上机作业

    计算机图形学第三次上机作业 读取OBJ文件 仿照群中调用的代码 利用半边数据结构 画出上机作业2中一样的三角形 计算网格面法向 这里的面法向量储存在HE_face中的数据域 facevector中 计 ...

  2. WebGL实践篇(九)—— 光照:点光源

    1.点光源的光照值 光照来源于点,太阳也算是一个点光源,光照射到物体的同一面上有明有暗(即光照值不同),将面上的每个点到光源的矢量与法向量点乘得到的值就是光照值. 顶点着色器: 主要添加了光照位置的参 ...

  3. 【DirectX12龙书机翻整理】第8章 光照

    本文章使用机器翻译并略加修改,不保证完全正确.并且只用于学习用途,如有侵权请联系本人删除. 如果你对DirectX.OpenGL.Vulkan感兴趣,欢迎加群:C++图形学 818038139 第8章 ...

  4. 【Unity Shader】(六) ------ 复杂的光照(上)

    笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题.              [Unity Sha ...

  5. 16.光照(平行光)

    1.基本概念: 着色:根据光照条件,重建"物体表面明暗不一效果"的过程 光源类型: (1)平行光:没有衰减的平行的光线,类似于太阳光.用一个方向和一个颜色定义. (2)点光源:理想 ...

  6. GraphicsLab Project之基于物理的着色系统(Physical based shading)-直接光照

    作者:idovelemon 日期:2018 / 1 / 1 来源:CSDN 主题:PBS, Microfact Theory, Cook-Torrance 引言 近些年来,基于物理的光照着色系统(Ph ...

  7. Vulkan_Shader_Day06—光照(多光源_Multiple lights)

    多光源_Multiple lights 我们在前面的教程中已经学习了许多关于Vulkan中光照的知识,其中包括冯氏着色(Phong Shading).材质(Material).光照贴图(Lightin ...

  8. LearnOpenGL 光照—多光源

    文章目录 写在前面 多光源 定向光 点光源 合成结果 总结 练习 写在前面 原文链接.原文应该是github上的一个项目,本文主要用来记录一些知识点和自己遇到的问题. 多光源 我们在前面的教程中已经学 ...

  9. LearnOpenGL学习笔记—高级光照 09:SSAO

    LearnOpenGL学习笔记-高级光照 09:SSAO 1 原理引入 2 样本缓冲 3 法向半球 4 随机核心转动 5 SSAO着色器 6 环境遮蔽模糊 7 应用环境遮蔽 8 动手试试 8.0 个人 ...

  10. LearnOpenGL->光照->投光物/多光源

    投光物 我们目前使用的光照都来自于空间中的一个点.它能给我们不错的效果,但现实世界中,我们有很多种类的光照,每种的表现都不同.将光投射(Cast)到物体的光源叫做投光物(Light Caster).在 ...

最新文章

  1. Activity的四种启动模式
  2. 软件项目管理的内在定律
  3. Android的init过程:init.rc解析流程
  4. mysql批量提交的优化
  5. Chrome浏览器调试踩坑
  6. 《Algorithms》Comparable 实现插入排序
  7. 为nopcommerce自定义用户积分功能(1)
  8. 读《非暴力沟通》马歇尔·卢森堡
  9. 同步图计算:GraphLite的安装和使用
  10. 你的目的是什么是谁指使你_魔家四将的师傅是谁?隐藏的高人,只配合太上老君的布局...
  11. python汉化之后好用吗_Python官方中文文档上线了:各种教程已汉化,不用再苦等野生翻译...
  12. pg数据库游标的使用
  13. 国外有哪些免费软件可以实现华为的多屏协同功能
  14. 南大计算机技术复试分数线,南大计算机复试分数线
  15. JAVA中将标准的IEEE754 4字节16进制数据转换为float类型数据
  16. 563. 二叉树的坡度【我亦无他唯手熟尔】
  17. 【英语-同义词汇词组】therefore、hence、thus的用法及区别
  18. 基于JAVA共享汽车管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
  19. 关闭win10的繁体字快捷键ctrl+shift+f
  20. 如何申请注册163邮箱账号?

热门文章

  1. ad 原理图放置差分对_Altium Designer差分对设置方法
  2. excel二进制移位运算_Excel定位神技能Ctrl+G,10种不可绕开的操作技巧
  3. 有哪些好用的论文检索网站?
  4. Word排版技巧数模论文必备
  5. PPT学习整理(八)PPT图片技巧
  6. 2009-2019年五级(到村/居委会)行政区划代码数据
  7. Tungsten Fabric知识库丨构建、安装与公有云部署
  8. 读《因果的真相》第五章摘抄笔记
  9. 层次分析法 - MATLAB代码详解
  10. Jenkins | 搭建你第一个Jenkins应用