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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值