17.光照(点光源)
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.光照(点光源)相关推荐
- 计算机图形学第三次上机作业
计算机图形学第三次上机作业 读取OBJ文件 仿照群中调用的代码 利用半边数据结构 画出上机作业2中一样的三角形 计算网格面法向 这里的面法向量储存在HE_face中的数据域 facevector中 计 ...
- WebGL实践篇(九)—— 光照:点光源
1.点光源的光照值 光照来源于点,太阳也算是一个点光源,光照射到物体的同一面上有明有暗(即光照值不同),将面上的每个点到光源的矢量与法向量点乘得到的值就是光照值. 顶点着色器: 主要添加了光照位置的参 ...
- 【DirectX12龙书机翻整理】第8章 光照
本文章使用机器翻译并略加修改,不保证完全正确.并且只用于学习用途,如有侵权请联系本人删除. 如果你对DirectX.OpenGL.Vulkan感兴趣,欢迎加群:C++图形学 818038139 第8章 ...
- 【Unity Shader】(六) ------ 复杂的光照(上)
笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Sha ...
- 16.光照(平行光)
1.基本概念: 着色:根据光照条件,重建"物体表面明暗不一效果"的过程 光源类型: (1)平行光:没有衰减的平行的光线,类似于太阳光.用一个方向和一个颜色定义. (2)点光源:理想 ...
- GraphicsLab Project之基于物理的着色系统(Physical based shading)-直接光照
作者:idovelemon 日期:2018 / 1 / 1 来源:CSDN 主题:PBS, Microfact Theory, Cook-Torrance 引言 近些年来,基于物理的光照着色系统(Ph ...
- Vulkan_Shader_Day06—光照(多光源_Multiple lights)
多光源_Multiple lights 我们在前面的教程中已经学习了许多关于Vulkan中光照的知识,其中包括冯氏着色(Phong Shading).材质(Material).光照贴图(Lightin ...
- LearnOpenGL 光照—多光源
文章目录 写在前面 多光源 定向光 点光源 合成结果 总结 练习 写在前面 原文链接.原文应该是github上的一个项目,本文主要用来记录一些知识点和自己遇到的问题. 多光源 我们在前面的教程中已经学 ...
- LearnOpenGL学习笔记—高级光照 09:SSAO
LearnOpenGL学习笔记-高级光照 09:SSAO 1 原理引入 2 样本缓冲 3 法向半球 4 随机核心转动 5 SSAO着色器 6 环境遮蔽模糊 7 应用环境遮蔽 8 动手试试 8.0 个人 ...
- LearnOpenGL->光照->投光物/多光源
投光物 我们目前使用的光照都来自于空间中的一个点.它能给我们不错的效果,但现实世界中,我们有很多种类的光照,每种的表现都不同.将光投射(Cast)到物体的光源叫做投光物(Light Caster).在 ...
最新文章
- Activity的四种启动模式
- 软件项目管理的内在定律
- Android的init过程:init.rc解析流程
- mysql批量提交的优化
- Chrome浏览器调试踩坑
- 《Algorithms》Comparable 实现插入排序
- 为nopcommerce自定义用户积分功能(1)
- 读《非暴力沟通》马歇尔·卢森堡
- 同步图计算:GraphLite的安装和使用
- 你的目的是什么是谁指使你_魔家四将的师傅是谁?隐藏的高人,只配合太上老君的布局...
- python汉化之后好用吗_Python官方中文文档上线了:各种教程已汉化,不用再苦等野生翻译...
- pg数据库游标的使用
- 国外有哪些免费软件可以实现华为的多屏协同功能
- 南大计算机技术复试分数线,南大计算机复试分数线
- JAVA中将标准的IEEE754 4字节16进制数据转换为float类型数据
- 563. 二叉树的坡度【我亦无他唯手熟尔】
- 【英语-同义词汇词组】therefore、hence、thus的用法及区别
- 基于JAVA共享汽车管理系统计算机毕业设计源码+数据库+lw文档+系统+部署
- 关闭win10的繁体字快捷键ctrl+shift+f
- 如何申请注册163邮箱账号?