8-光照
一、学习要点
本章主要讨论光照问题,如何在三维场景中实现不同类型的光照以及其产生的效果。
- 明暗、阴影、不同类型的光 : 点光源光,平行光和散射光。
- 物体表面反射光线的方式: 漫反射和环境反射
- 编写代码实现光照效果,使三维模型更逼真
二、光照原理
现实世界中物体被光照射时会反着一部分光。只有当反射光线进入你的眼睛是,你才能看到并辨认出他的颜色。
在现实世界中,当光照射到物体上时,发生了两个重要的现象。
- 根据光源和光线的方向,物体不同表面的明暗程度变得不一致。
- 根据光源和光线的方向,物体向地面投下影子。
现实生活中我们会注意到阴影,却很少关注明暗差异。实际上敏感差异给了我们物体立体感。
在三维图形学中术语 着色(shading) 的真生含义就是,根据光照条件重建“物体各个表面明暗不一的效果”的过程。
在讨论着色之前我们考虑两件事情:
- 光源的类型
- 物体表面如何反射光线
光源类型
- 平行光:顾名思义,平行光的管线是相互平行的,平行光具有方向。平行光可以看做是无限远处的光源(比如太阳)发出的光。平行光很简单,可以用一个方向和一个颜色来定义。
- 点光源:点光源光是从一个点想周围的所有方向发出的光。点光源光可以用来表示灯泡,火焰等。我们需要制定光源的位置和颜色。光线的方向根据点光源的位置和配照射指出的位置计算出来。因为点光源的光线方向在场景没不同位置是不同的。
- 环境光:(间接光) 指那些经光源发出后,被墙壁等物体多次反射然后找到物体表面的光。环境光从各个角度照射物体,其强度都是一致的。环境光只需指定颜色即可。
反射类型
物体向哪个方向反射光,反射光是什么颜色的,取决于以下两个因素: 入射光和物体表面的类型。入射光的信息包括入射光的方向和颜色,二物体表面信息包括物体的固有颜色和反射特性。
- 漫反射:漫反射针对于平行光或者点光源而言。漫反射的繁盛光在各个方向上是均匀的。漫反射的反射光的颜色取决于入射光的颜色、反射表面的基底色、入射光与表面行车的入射角。
其计算公式为 <漫反射光颜色> = <入射光颜色> * <表面基底色> * cosθ
- 环境反射:在环境反射中,反射的方向可以认为就是入射光的反方向。 其计算公式为 <漫反射光颜色> = <入射光颜色> * <表面基底色> * cosθ
三、平行光下的漫反射
<漫反射光颜色> = <入射光颜色> * <表面基底色> * cosθ 比如 白色的光找到一个红色额基底色上,如果是垂直照射 cosθ = 1.0
R = 1.0 * 1.0 * 1.0;
G = 1.0 * 0.0 * 1.0;
B = 1.0 * 0.0 * 1.0; 计算得出还是红色, 这是符合我们现实生活的。看起来计算并不困难。 但是实际中我们不知道入射角θ 只能知道光线的方向。
根据光线和表面的方向计算入射角
在程序中,我们没办法想前一届最后直接说入射角度是多少。我们必须根据入射光的方向和物体表面的朝向(即法线方向)来计算出入射角。这并不简单, 因为在创建三维模型的时候,我们无法预先确定光线将以怎样的角度照射到每个表面上。但是我们可以确定每个表面的朝向。 我们可以通过计算两个矢量的点积,来计算着两个矢量的夹角的余璇值cosθ 所以公式可以改成 <漫反射光颜色> = <入射光颜色> * <表面基底色> * (<光线方向> . <法线方向>) 这里要注意:
- 的是光线方向和法线方向的长度必须为1,否则反射光的颜色会过暗或者过亮。将一个矢量长度调整为1 的过程称为归一化。
- 光线方向实际上是入射方向的反方向。即从如何点只想光源方向。 那又有个疑问,法线方向如何得到呢?
法线: 表面的朝向
物体表面的朝向,即垂直于表面的方向,又称法线或者法向量。涉及到表面和法向量的问题时,必须考虑一下两点:
- 一个表面具有两个法向量,每个面都有正反两面,即有正反两个法向量
在三维图形学中,表面的正面和背面取决于绘制表面时的顶点顺序。当你按照v0,v1,v2,v3的顶点顺序绘制了一个平面,那么当你从正面观察这个表面时,这四个顶点是顺镇的,而你从背面观察该表面,这4个顶点是逆时针的。(右手法则)上图平面的整法向量是(0,0,-1) 2. 平面的法向量唯一,由于法向量表示的是方向,与位置无关,所以一个平面只有一个法向量。换句话说 屏慢的任意一点都具有相同的法向量。 下图展示立方体的法向量
一旦计算好每个平面的法向量,接下来的任务就是将数据传给着色器程序。以前的程序把颜色作为“逐顶点数据”处处在缓冲区中,并传给着色器。对法向量数据也可以这样做。每个顶点对应3个法向量。
// 示例程序 一个光照下的红色盒子
// 顶点着色器
var VSHANER_SOURCE =
`
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightDirection;
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;
v_Color = vec4(diffuse,a_Color.a);
}
`;
// 片元着色器
var FSHADER_SOURCE =
`
precision mediump float; // 需要声明浮点数精度否则报错
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`
function main() {
let canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('error');
return;
}
// 初始化着色器
if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
console.log('error');
return;
}
var n = initVertexBuffers(gl);
if(n<0){
console.log("error");
return;
}
gl.clearColor(0.0,0.0,0.0,1.0);
// 开启隐藏面消除
gl.enable(gl.DEPTH_TEST);
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_LightDirection = gl.getUniformLocation(gl.program,'u_LightDirection');
// 设置光线颜色(白色)
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
// 设置光线方向(世界坐标系下的)
var lightDirection = new Vector3([0.5,3.0,4.0]);
lightDirection.normalize(); // 归一化
gl.uniform3fv(u_LightDirection,lightDirection.elements);
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
// 混合投影
var mvpMatrix = new Matrix4();
// 设置视点 视线 和上方向
var viewMatrix = new Matrix4();
// 投影矩阵
var projMatrix = new Matrix4();
viewMatrix.setLookAt(3,3,7,0,0,0,0,1,0);
projMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.set(projMatrix).multiply(viewMatrix);
// 将试图矩阵和投影矩阵传递给参数
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) {
let v0 = [1.0,1.0,1.0];
let v1 = [-1.0,1.0,1.0];
let v2 = [-1.0,-1.0,1.0];
let v3 = [1.0,-1.0,1.0];
let v4 = [1.0,-1.0,-1.0];
let v5 = [1.0,1.0,-1.0];
let v6 = [-1.0,1.0,-1.0];
let 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,
...v2,...v3,...v4,...v7,
...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 // 后
])
var color = new Float32Array([
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,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,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,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,0.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,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
])
// 创建缓冲区对象
var indexBuffer = gl.createBuffer();
if(!initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position')){
return -1;
}
if(!initArrayBuffer(gl,color,3,gl.FLOAT,'a_Color')){
return -1;
}
if(!initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal')){
return -1;
}
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);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
// 将缓冲区对象分配给 a_Position变量
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
max(dot(u_LightDirection,normal), 0.0); 顶点着色器中 取了点积和0的最大值,表示如果光照来自于表面的背面,我们现在认为表面时完全不透光的。
四、环境光下的漫反射
我们发现 正方体还是有些和我们实际的生活中的不太一样,比如右侧的面全部都是黑色的。这不符合我们实际的情况。这其实是因为现实生活中除了直射光的影响,环境中的折射光也会对物体的颜色产生影响
<环境反射光颜色> = <入射光颜色> * <表面基底色>
<表面的反射光颜色> = <漫反射光颜色> + <表面基底色>
// 顶点着色器
var VSHANER_SOURCE =
`
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightDirection;
uniform vec3 u_AmbientLight;
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,a_Color.a);
}
`;
// 片元着色器
var FSHADER_SOURCE =
`
precision mediump float; // 需要声明浮点数精度否则报错
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`
function main() {
let canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('error');
return;
}
// 初始化着色器
if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
console.log('error');
return;
}
var n = initVertexBuffers(gl);
if(n<0){
console.log("error");
return;
}
gl.clearColor(0.0,0.0,0.0,1.0);
// 开启隐藏面消除
gl.enable(gl.DEPTH_TEST);
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_LightDirection = gl.getUniformLocation(gl.program,'u_LightDirection');
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
// 设置光线颜色(白色)
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
// 设置环境光
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);
// 设置光线方向(世界坐标系下的)
var lightDirection = new Vector3([0.5,3.0,4.0]);
lightDirection.normalize(); // 归一化
gl.uniform3fv(u_LightDirection,lightDirection.elements);
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
// 混合投影
var mvpMatrix = new Matrix4();
// 设置视点 视线 和上方向
var viewMatrix = new Matrix4();
// 投影矩阵
var projMatrix = new Matrix4();
viewMatrix.setLookAt(3,3,7,0,0,0,0,1,0);
projMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.set(projMatrix).multiply(viewMatrix);
// 将试图矩阵和投影矩阵传递给参数
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) {
let v0 = [1.0,1.0,1.0];
let v1 = [-1.0,1.0,1.0];
let v2 = [-1.0,-1.0,1.0];
let v3 = [1.0,-1.0,1.0];
let v4 = [1.0,-1.0,-1.0];
let v5 = [1.0,1.0,-1.0];
let v6 = [-1.0,1.0,-1.0];
let 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,
...v2,...v3,...v4,...v7,
...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 // 后
])
var color = new Float32Array([
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,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,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,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,0.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,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
])
// 创建缓冲区对象
var indexBuffer = gl.createBuffer();
if(!initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position')){
return -1;
}
if(!initArrayBuffer(gl,color,3,gl.FLOAT,'a_Color')){
return -1;
}
if(!initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal')){
return -1;
}
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);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
// 将缓冲区对象分配给 a_Position变量
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
五、运动物体的光照效果
立方体旋转时 每个表面的法向量也会随之变化。由下午我们发现
- 平移不会使得法向量变化,
- 而旋转会引起法向量的变化。
- 缩放变化比较复杂 有时引起 有时不引起。
那这个法向量的变化怎么计算得到呢?
魔法矩阵:你转置矩阵
变化之后的法向量 = 变化之前的法向量 * 模型矩阵的 逆转置矩阵
逆转置矩阵:
- 求原矩阵的逆矩阵。
- 将上一步求得的逆矩阵进行转置。
// 顶点着色器
var VSHANER_SOURCE =
`
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_NormalMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightDirection;
uniform vec3 u_AmbientLight;
varying vec4 v_Color;
void main() {
gl_Position =u_MvpMatrix * a_Position;
vec3 normal = normalize(vec3(u_NormalMatrix * 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,a_Color.a);
}
`;
// 片元着色器
var FSHADER_SOURCE =
`
precision mediump float; // 需要声明浮点数精度否则报错
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`
function main() {
let canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('error');
return;
}
// 初始化着色器
if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
console.log('error');
return;
}
var n = initVertexBuffers(gl);
if(n<0){
console.log("error");
return;
}
gl.clearColor(0.0,0.0,0.0,1.0);
// 开启隐藏面消除
gl.enable(gl.DEPTH_TEST);
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_LightDirection = gl.getUniformLocation(gl.program,'u_LightDirection');
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
// 设置光线颜色(白色)
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
// 设置环境光
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);
// 设置光线方向(世界坐标系下的)
var lightDirection = new Vector3([0.5,3.0,4.0]);
lightDirection.normalize(); // 归一化
gl.uniform3fv(u_LightDirection,lightDirection.elements);
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
// 混合投影
var mvpMatrix = new Matrix4();
// 逆转置矩阵
var normalMatrix = new Matrix4();
// 模型矩阵
var modelMatrix = new Matrix4();
modelMatrix.setTranslate(0,0.5,0);// 沿Y轴平移
modelMatrix.rotate(90,0,0,1);// 沿Z轴平移
// 设置视点 视线 和上方向
var viewMatrix = new Matrix4();
// 投影矩阵
var projMatrix = new Matrix4();
viewMatrix.setLookAt(3,3,7,0,0,0,0,1,0);
projMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
// 将试图矩阵和投影矩阵传递给参数
gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);
// 开启偏移
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}
function initVertexBuffers(gl) {
let v0 = [1.0,1.0,1.0];
let v1 = [-1.0,1.0,1.0];
let v2 = [-1.0,-1.0,1.0];
let v3 = [1.0,-1.0,1.0];
let v4 = [1.0,-1.0,-1.0];
let v5 = [1.0,1.0,-1.0];
let v6 = [-1.0,1.0,-1.0];
let 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,
...v2,...v3,...v4,...v7,
...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 // 后
])
var color = new Float32Array([
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,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,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,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,0.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,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
])
// 创建缓冲区对象
var indexBuffer = gl.createBuffer();
if(!initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position')){
return -1;
}
if(!initArrayBuffer(gl,color,3,gl.FLOAT,'a_Color')){
return -1;
}
if(!initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal')){
return -1;
}
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);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
// 将缓冲区对象分配给 a_Position变量
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
这个正方体除了向上移动了一点好像没什么变化,其实主要是因为正好旋转了90度的原因。
六 点光源光
与平行光想必,点光源发出的光,在三维空间的不同位置上期方向也不同。所以在对点光源光下的物体进行着色时,需要每个入射点计算点光源光在该处的方向。
// 顶点着色器
var VSHANER_SOURCE =
`
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_ModelMatrix;
uniform mat4 u_NormalMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightPosition;
uniform vec3 u_AmbientLight;
varying vec4 v_Color;
void main() {
gl_Position =u_MvpMatrix * a_Position;
vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));
vec4 vertexPosition = u_ModelMatrix * a_Position;
vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));
float nDotL = max(dot(lightDirection,normal), 0.0);
vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
vec3 ambient = u_AmbientLight * a_Color.rgb;
v_Color = vec4(diffuse + ambient,a_Color.a);
}
`;
// 片元着色器
var FSHADER_SOURCE =
`
precision mediump float; // 需要声明浮点数精度否则报错
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`
function main() {
let canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('error');
return;
}
// 初始化着色器
if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
console.log('error');
return;
}
var n = initVertexBuffers(gl);
if(n<0){
console.log("error");
return;
}
gl.clearColor(0.0,0.0,0.0,1.0);
// 开启隐藏面消除
gl.enable(gl.DEPTH_TEST);
var u_ModelMatrix = gl.getUniformLocation(gl.program,'u_ModelMatrix');
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_LightPosition = gl.getUniformLocation(gl.program,'u_LightPosition');
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
// 设置光线颜色(白色)
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
// 设置环境光
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);
// 设置光线方向(世界坐标系下的)
// var lightDirection = new Vector3([0.5,3.0,4.0]);
// lightDirection.normalize(); // 归一化
gl.uniform3f(u_LightPosition,2.0,3.0,3.0);
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
// 混合投影
var mvpMatrix = new Matrix4();
// 逆转置矩阵
var normalMatrix = new Matrix4();
// 模型矩阵
var modelMatrix = new Matrix4();
modelMatrix.setTranslate(0,0.5,0);// 沿Y轴平移
modelMatrix.rotate(90,0,0,1);// 沿Z轴平移
// 设置视点 视线 和上方向
var viewMatrix = new Matrix4();
// 投影矩阵
var projMatrix = new Matrix4();
viewMatrix.setLookAt(3,3,7,0,0,0,0,1,0);
projMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
// 将试图矩阵和投影矩阵传递给参数
gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);
gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);
// 开启偏移
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}
function initVertexBuffers(gl) {
let v0 = [1.0,1.0,1.0];
let v1 = [-1.0,1.0,1.0];
let v2 = [-1.0,-1.0,1.0];
let v3 = [1.0,-1.0,1.0];
let v4 = [1.0,-1.0,-1.0];
let v5 = [1.0,1.0,-1.0];
let v6 = [-1.0,1.0,-1.0];
let 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,
...v2,...v3,...v4,...v7,
...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 // 后
])
var color = new Float32Array([
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,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,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,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,0.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,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
])
// 创建缓冲区对象
var indexBuffer = gl.createBuffer();
if(!initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position')){
return -1;
}
if(!initArrayBuffer(gl,color,3,gl.FLOAT,'a_Color')){
return -1;
}
if(!initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal')){
return -1;
}
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);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
// 将缓冲区对象分配给 a_Position变量
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
我们发现现在的效果更加逼真了, 可是还是感觉不太自然,因为我们是逐顶点计算光照找过的,正方体上的面上像素的颜色是根据顶点颜色来渐变出来的,现实世界中每个像素都是自己根据光照计算出自己的颜色的。 下面有这个正方体运动起来的示例可以比较明显的看出这一点。
// 运动的立方体
// 顶点着色器
var VSHANER_SOURCE =
`
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_ModelMatrix;
uniform mat4 u_NormalMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightPosition;
uniform vec3 u_AmbientLight;
varying vec4 v_Color;
void main() {
gl_Position =u_MvpMatrix * a_Position;
vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));
vec4 vertexPosition = u_ModelMatrix * a_Position;
vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));
float nDotL = max(dot(lightDirection,normal), 0.0);
vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
vec3 ambient = u_AmbientLight * a_Color.rgb;
v_Color = vec4(diffuse + ambient,a_Color.a);
}
`;
// 片元着色器
var FSHADER_SOURCE =
`
precision mediump float; // 需要声明浮点数精度否则报错
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`
function main() {
let canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('error');
return;
}
// 初始化着色器
if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
console.log('error');
return;
}
var n = initVertexBuffers(gl);
if(n<0){
console.log("error");
return;
}
gl.clearColor(0.0,0.0,0.0,1.0);
// 开启隐藏面消除
gl.enable(gl.DEPTH_TEST);
var u_ModelMatrix = gl.getUniformLocation(gl.program,'u_ModelMatrix');
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_LightPosition = gl.getUniformLocation(gl.program,'u_LightPosition');
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
// 设置光线颜色(白色)
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
// 设置环境光
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);
// 设置点光源的位置
gl.uniform3f(u_LightPosition,2.3,4.0,3.5);
// 混合投影
var mvpMatrix = new Matrix4();
// 逆转置矩阵
var normalMatrix = new Matrix4();
// 模型矩阵
var modelMatrix = new Matrix4();
// 设置视点 视线 和上方向
var viewMatrix = new Matrix4();
// 投影矩阵
var projMatrix = new Matrix4();
viewMatrix.setLookAt(3,3,7,0,0,0,0,1,0);
projMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
var currentAngle = 0.0;
var tick = function () {
currentAngle = animate(currentAngle);
modelMatrix.setTranslate(0,0.5,0);// 沿Y轴平移
modelMatrix.rotate(currentAngle,0,1,0);// 沿Z轴平移
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
// 将试图矩阵和投影矩阵传递给参数
gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);
gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);
// 开启偏移
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
requestAnimationFrame(tick);
}
tick();
}
function initVertexBuffers(gl) {
let v0 = [1.0,1.0,1.0];
let v1 = [-1.0,1.0,1.0];
let v2 = [-1.0,-1.0,1.0];
let v3 = [1.0,-1.0,1.0];
let v4 = [1.0,-1.0,-1.0];
let v5 = [1.0,1.0,-1.0];
let v6 = [-1.0,1.0,-1.0];
let 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,
...v2,...v3,...v4,...v7,
...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 // 后
])
var color = new Float32Array([
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,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,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,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,0.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,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
])
// 创建缓冲区对象
var indexBuffer = gl.createBuffer();
if(!initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position')){
return -1;
}
if(!initArrayBuffer(gl,color,3,gl.FLOAT,'a_Color')){
return -1;
}
if(!initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal')){
return -1;
}
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);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
// 将缓冲区对象分配给 a_Position变量
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
var ANGLE_STEP = 30.0;
var g_last = Date.now();
function animate(angle) {
var now = Date.now();
var elapsed = now - g_last;
g_last = now;
var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
return newAngle %= 360;
}
七、更逼真 逐片元光照
我们只需要在片元着色器里面进行计算就可以。
// 顶点着色器
var VSHANER_SOURCE =
`
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_NormalMatrix;
uniform mat4 u_ModelMatrix;
varying vec3 v_Normal;
varying vec3 v_Position;
varying vec4 v_Color;
void main() {
gl_Position =u_MvpMatrix * a_Position;
v_Position = vec3(u_ModelMatrix * a_Position);
v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));
v_Color = a_Color;
}
`;
// 片元着色器
var FSHADER_SOURCE =
`
precision mediump float; // 需要声明浮点数精度否则报错
uniform vec3 u_LightColor;
uniform vec3 u_LightPosition;
uniform vec3 u_AmbientLight;
varying vec3 v_Normal;
varying vec3 v_Position;
varying vec4 v_Color;
void main() {
vec3 normal = normalize(v_Normal);
vec3 lightDirection = normalize(u_LightPosition - v_Position);
float nDotL = max(dot(lightDirection,normal), 0.0);
vec3 diffuse = u_LightColor * vec3(v_Color) * nDotL;
vec3 ambient = u_AmbientLight * v_Color.rgb;
gl_FragColor = vec4(diffuse + ambient , v_Color.a );
}
`
function main() {
let canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if(!gl){
console.log('error');
return;
}
// 初始化着色器
if(!initShaders(gl,VSHANER_SOURCE,FSHADER_SOURCE)){
console.log('error');
return;
}
var n = initVertexBuffers(gl);
if(n<0){
console.log("error");
return;
}
gl.clearColor(0.0,0.0,0.0,1.0);
// 开启隐藏面消除
gl.enable(gl.DEPTH_TEST);
var u_ModelMatrix = gl.getUniformLocation(gl.program,'u_ModelMatrix');
var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor');
var u_LightPosition = gl.getUniformLocation(gl.program,'u_LightPosition');
var u_AmbientLight = gl.getUniformLocation(gl.program,'u_AmbientLight');
// 设置光线颜色(白色)
gl.uniform3f(u_LightColor,1.0,1.0,1.0);
// 设置环境光
gl.uniform3f(u_AmbientLight,0.2,0.2,0.2);
// 设置光线方向(世界坐标系下的)
// var lightDirection = new Vector3([0.5,3.0,4.0]);
// lightDirection.normalize(); // 归一化
gl.uniform3f(u_LightPosition,2.0,3.0,3.0);
var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');
// 混合投影
var mvpMatrix = new Matrix4();
// 逆转置矩阵
var normalMatrix = new Matrix4();
// 模型矩阵
var modelMatrix = new Matrix4();
modelMatrix.setTranslate(0,0.5,0);// 沿Y轴平移
modelMatrix.rotate(90,0,0,1);// 沿Z轴平移
// 设置视点 视线 和上方向
var viewMatrix = new Matrix4();
// 投影矩阵
var projMatrix = new Matrix4();
viewMatrix.setLookAt(3,3,7,0,0,0,0,1,0);
projMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
// 将试图矩阵和投影矩阵传递给参数
gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements);
normalMatrix.setInverseOf(modelMatrix);
normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix,false,normalMatrix.elements);
gl.uniformMatrix4fv(u_ModelMatrix,false,modelMatrix.elements);
// 开启偏移
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}
function initVertexBuffers(gl) {
let v0 = [1.0,1.0,1.0];
let v1 = [-1.0,1.0,1.0];
let v2 = [-1.0,-1.0,1.0];
let v3 = [1.0,-1.0,1.0];
let v4 = [1.0,-1.0,-1.0];
let v5 = [1.0,1.0,-1.0];
let v6 = [-1.0,1.0,-1.0];
let 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,
...v2,...v3,...v4,...v7,
...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 // 后
])
var color = new Float32Array([
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,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,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,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,0.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,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
])
// 创建缓冲区对象
var indexBuffer = gl.createBuffer();
if(!initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position')){
return -1;
}
if(!initArrayBuffer(gl,color,3,gl.FLOAT,'a_Color')){
return -1;
}
if(!initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal')){
return -1;
}
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);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
// 将缓冲区对象分配给 a_Position变量
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
片元处的表面的法向量和片元的位置信息,是在从顶点缓冲区传递到片元缓冲区时webgl内部进行的插值计算好的。
这一张我们介绍了几种不同的光照类型和反射类型,讨论了如何为场景实现光照效果,下一章我们不再使用简单的正方体而是创建层次模型。