立方体平移旋转缩放变换时漫反射光和环境反射光处理
1.demo效果
如上,图一是没添加环境光的效果,图二为添加环境光后的效果,添加环境光后整个立方体变的更亮了一些,是因为环境光从各个方向照射在了物体上
2.相关知识点
2.1 相关回顾
在之前的学习中,我们知道,在WebGL中,光源主要分为三类: 平行光、点光源、环境光
物体表面反射光线的方式有两种: 漫反射 和 环境反射 ,漫反射是针对平行光和点光源,环境反射是针对环境光的。
漫反射光计算模型
<漫反射光颜色> = <入射光颜色> x <表面基底色> x ( <入射光线方向> ● <法线方向>)
2.2 环境反射光计算模型
接下来说是环境反射光计算模型,它相比漫反射计算要简单一点
<环境反射光颜色> = <环境光颜色> x <表面基底色>
2.3 物体表面反射光计算
现实中,光照射到物体上,那些背光的物体也不会非常黑,是因为这些背光面被非直射光(如墙壁反射光等)照亮,环境光的作用就是模拟这部分光。现实中至少会平行光和环境光照射在物体上,这样就出现了计算物体表面反射光的模型
<物体表面反射光颜色> = <漫反射光颜色> + <环境反射光颜色>
示例代码-只展光照计算相关代码
'attribute vec4 a_Color;\\n' + //声明attribute变量a_Color,用来存放顶点颜色信息
'attribute vec4 a_Normal;\\n' + //声明attribute变量a_Normal,用来存放法向量
'uniform vec3 u_LightColor;\\n' + //声明uniform变量u_LightColor,用来存放光线颜色
'uniform vec3 u_LightDirection;\\n' + //声明uniform变量u_LightDirection,用来存放入射光方向,归一化的世界坐标
'uniform vec3 u_AmbientLightColor;\\n' + //声明uniform变量u_AmbientLightColor,用来存放环境光颜色
'varying vec4 v_Color;\\n' + //声明varying变量v_Color,用来向片元着色器传值顶点颜色信息
'void main(){\\n' +
' vec3 normal = normalize(vec3(a_Normal));\\n' + //对法向量归一化处理
' vec3 lightDirection = normalize(vec3(u_LightDirection));\\n' + //对入射光向量归一化处理
//u_LightColor:入射光颜色,a_Color:表面基底色,lightDirection:入射光线方向,normal:法线方向,u_AmbientLightColor:环境光颜色
' vec3 diffuse = u_LightColor * vec3(a_Color) * dot(lightDirection, normal);\\n' + //计算漫反射光的颜色
' vec3 ambient = u_AmbientLightColor * vec3(a_Color);\\n' + //计算环境漫反射光的颜色
' v_Color = vec4(diffuse + ambient, a_Color.a);\\n' + //将漫反射光的颜色和环境漫反射光的颜色相加的结果传给片元着色器,
'}\\n';
3.demo代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--通过canvas标签创建一个800px*800px大小的画布-->
<canvas id="webgl" width="800" height="800"></canvas>
<script type="text/javascript" src="./lib/cuon-matrix.js"></script>
<script>
//顶点着色器
var VSHADER_SOURCE = '' +
'attribute vec4 a_Position;\\n' + //声明attribute变量a_Position,用来存放顶点位置信息
'attribute vec4 a_Color;\\n' + //声明attribute变量a_Color,用来存放顶点颜色信息
'attribute vec4 a_Normal;\\n' + //声明attribute变量a_Normal,用来存放法向量
'uniform mat4 u_MvpMatrix;\\n' + //声明uniform变量u_MvpMatrix,用来存放模型视图投影组合矩阵
'uniform mat4 u_NormalMatrix;\\n' + //声明uniform变量u_NormalMatrix,用来存放变换法向量矩阵
'uniform vec3 u_LightColor;\\n' + //声明uniform变量u_LightColor,用来存放光线颜色
'uniform vec3 u_LightDirection;\\n' + //声明uniform变量u_LightDirection,用来存放入射光方向,归一化的世界坐标
'uniform vec3 u_AmbientLightColor;\\n' + //声明uniform变量u_AmbientLightColor,用来存放环境光颜色
'varying vec4 v_Color;\\n' + //声明varying变量v_Color,用来向片元着色器传值顶点颜色信息
'void main(){\\n' +
' gl_Position = u_MvpMatrix * a_Position;\\n' + //将模型视图投影组合矩阵与顶点坐标相乘赋值给顶点着色器内置变量gl_Position
' vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\\n' + //对计算变换后的法向量并归一化处理
' float nDotL = max(dot(u_LightDirection, normal), 0.0);\\n' + //计算光线方向和法向量点积
' vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;\\n' + //计算漫反射光的颜色
' vec3 ambient = u_AmbientLightColor * vec3(a_Color);\\n' + //计算环境漫反射光的颜色
' v_Color = vec4(diffuse + ambient, a_Color.a);\\n' + //将漫反射光的颜色和环境漫反射光的颜色相加的结果传给片元着色器
'}\\n';
//片元着色器
var FSHADER_SOURCE = '' +
'#ifdef GL_ES\\n' +
' precision mediump float;\\n' + // 设置精度
'#endif\\n' +
'varying vec4 v_Color;\\n' + //声明varying变量v_Color,用来接收顶点着色器传送的片元颜色信息
'void main(){\\n' +
//将varying变量v_Color接收的颜色信息赋值给内置变量gl_FragColor
' gl_FragColor = v_Color;\\n' +
'}\\n';
//初始化着色器函数
function initShader(gl, VSHADER_SOURCE, FSHADER_SOURCE) {
//创建顶点着色器对象
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
//创建片元着色器对象
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
//引入顶点、片元着色器源代码
gl.shaderSource(vertexShader, VSHADER_SOURCE);
gl.shaderSource(fragmentShader, FSHADER_SOURCE);
//编译顶点、片元着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
//创建程序对象program
var program = gl.createProgram();
//附着顶点着色器和片元着色器到program
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
//链接program
gl.linkProgram(program);
//使用program
gl.useProgram(program);
gl.program = program
//返回程序program对象
return program;
}
function init() {
//通过getElementById()方法获取canvas画布
var canvas = document.getElementById('webgl');
//通过方法getContext()获取WebGL上下文
var gl = canvas.getContext('webgl');
//初始化着色器
if (!initShader(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('初始化着色器失败');
return;
}
// 设置canvas的背景色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//初始化顶点坐标和顶点颜色
var n = initVertexBuffers(gl)
setMatrixAndDraw(gl, n)
}
//设置矩阵并绘图
function setMatrixAndDraw(gl, n) {
//开启隐藏面消除
gl.enable(gl.DEPTH_TEST)
//清空颜色和深度缓冲区
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//获取顶点着色器uniform变量u_MvpMatrix的存储地址
var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix')
//获取顶点着色器uniform变量u_NormalMatrix-变换法向量矩阵的存储地址
var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix')
var modelMatrix = new Matrix4() //创建模矩阵
var normalMatrix = new Matrix4() //创建变换法向量矩阵
var mvpMatrix = new Matrix4() //创建模型视图投影矩阵
modelMatrix.setTranslate(0, 0.8, 0) //设置模型矩阵-沿x轴平移0.8
modelMatrix.rotate(90, 0, 0, 1) //设置模型矩阵-绕Z轴旋转90度
modelMatrix.scale(1, 1.5, 1) //设置模型矩阵-Y轴放大1.5倍
mvpMatrix.setPerspective(30, 1, 1, 100) //设置透视投影矩阵
mvpMatrix.lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0) //设置视点、视线和上方向
mvpMatrix.multiply(modelMatrix) //透视投影矩阵与模型矩阵相乘
//将模型视图投影组合矩阵传给顶点着色器uniform变量u_MvpMatrix
gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements)
//根据模型矩阵计算变换法向量的矩阵
normalMatrix.setInverseOf(modelMatrix)
normalMatrix.transpose()
//将变换法向量传给顶点着色器uniform变量u_NormalMatrix
gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements)
//获取顶点着色器uniform变量u_AmbientLightColor的存储地址
var u_AmbientLightColor = gl.getUniformLocation(gl.program, 'u_AmbientLightColor')
//给顶点着色器uniform变量u_AmbientLightColor- 环境光颜色传值(0.2, 0.2, 0.2)
gl.uniform3f(u_AmbientLightColor, 0.2, 0.2, 0.2)
//获取顶点着色器uniform变量u_LightColor的存储地址
var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor')
//给顶点着色器uniform变量u_LightColor- 光线颜色传值(1.0,1.0,1.0)
gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0)
//获取顶点着色器uniform变量u_LightDirection的存储地址
var u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection')
var lightDirection = new Vector3([1.5, 3.0, 4.0])
lightDirection.normalize() //归一化
//给顶点着色器uniform变量u_LightColor- 光线颜色传值(1.0,1.0,1.0)
gl.uniform3fv(u_LightDirection, lightDirection.elements)
//绘制立方体
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0)
}
//初始化顶点坐标和顶点颜色
function initVertexBuffers(gl) {
var v0 = [1.0, 1.0, 1.0]
var v1 = [-1.0, 1.0, 1.0]
var v2 = [-1.0, -1.0, 1.0]
var v3 = [1.0, -1.0, 1.0]
var v4 = [1.0, -1.0, -1.0]
var v5 = [1.0, 1.0, -1.0]
var v6 = [-1.0, 1.0, -1.0]
var v7 = [-1.0, -1.0, -1.0]
//顶点
var vertices = new Float32Array([
...v0, ...v1, ...v2, ...v3, // 前
...v0, ...v3, ...v4, ...v5, // 右
...v0, ...v5, ...v6, ...v1, // 上
...v1, ...v6, ...v7, ...v2, // 左
...v7, ...v4, ...v3, ...v2, // 下
...v4, ...v7, ...v6, ...v5 // 后
])
var fontColor = [1.0, 0.0, 0.0]
var backColor = [1.0, 0.0, 0.0]
var leftColor = [0.0, 1.0, 0.0]
var rightColor = [0.0, 1.0, 0.0]
var topColor = [0.0, 0.0, 1.0]
var downColor = [0.0, 0.0, 1.0]
// 顶点的颜色
var colors = new Float32Array([
...fontColor, ...fontColor, ...fontColor, ...fontColor, // v0-v1-v2-v3 前
...rightColor, ...rightColor, ...rightColor, ...rightColor, // v0-v3-v4-v5 右
...topColor, ...topColor, ...topColor, ...topColor, // v0-v5-v6-v1 上
...leftColor, ...leftColor, ...leftColor, ...leftColor, // v1-v6-v7-v2 左
...downColor, ...downColor, ...downColor, ...downColor, // v7-v4-v3-v2 下
...backColor, ...backColor, ...backColor, ...backColor, // v4-v7-v6-v5 后
]);
var font = [0.0, 0.0, 1.0]
var back = [0.0, 0.0, -1.0]
var left = [-1.0, 0.0, 0.0]
var right = [1.0, 0.0, 0.0]
var top = [0.0, 1.0, 0.0]
var down = [0.0, -1.0, 0.0]
// 法向量
var normals = new Float32Array([
...font, ...font, ...font, ...font, // v0-v1-v2-v3 前
...right, ...right, ...right, ...right, // v0-v3-v4-v5 右
...top, ...top, ...top, ...top, // v0-v5-v6-v1 上
...left, ...left, ...left, ...left, // v1-v6-v7-v2 左
...down, ...down, ...down, ...down, // v7-v4-v3-v2 下
...back, ...back, ...back, ...back, // v4-v7-v6-v5 后
]);
// 绘制的索引
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 // 后
]);
if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) {
return -1
}
if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color')) {
return -1
}
if (!initArrayBuffer(gl, normals, 3, gl.FLOAT, 'a_Normal')) {
return -1
}
//创建缓冲区对象
var indexBuffer = gl.createBuffer()
//将顶点索引写入缓冲区对象
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)
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)
//获取顶点着色器attribute变量存储地址, 分配缓存并开启
var a_Attribute = gl.getAttribLocation(gl.program, attribute);
gl.vertexAttribPointer(a_Attribute, num, type, false, 0, 0)
gl.enableVertexAttribArray(a_Attribute)
return true
}
init()
</script>
</body>
</html>
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容