版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wpxu08/article/details/78348456
1.实验目的和要求
- 目的:了解简单光照明模型的基本原理,掌握简单光照明模型的计算方法;
- 要求:读懂WebGL光照示范代码,实现简单物体的光照效果。
2. 实验过程
(1) 示范代码为立方体在一束平行光照射下的漫反射光照效果。结合示范代码,学习掌握简单光照明模型的基本原理与实现;
(2) 修改示范代码,给出不同光照参数和立方体位置,观察与验证光照效果;
(3) 示范代码仅有漫反射光的光照效果,请尝试为其添加环境反射光和镜面反射光效果。
3.实验结果
仅有漫反射光的光照效果如下图所示:
添加环境反射光后的立方体效果如下图所示:
添加环境反射光与镜面反射光后的立方体效果如下图所示:
4.实验分析
简单光照明模型指的是物体表面上一点P反射到视点的光强I为环境光的反射光强
、理想漫反射光强
、和镜面反射光
的总和,即
其中R,V,N为单位矢量,如下图所示。 为点光源发出的入射光强; 为环境光的漫反射光强; 为环境光的漫反射系数; 为漫反射系数; 为镜面反射系数;n为镜面反射指数,用以反映物体表面的光滑程度,表面越光滑,n越大。这些参数与材料表面特性有关。
在用Phong模型进行真实感图形计算时,对物体表面上的每个点P,均需计算光线的反射方向R,再由V计算 。为减少计算量,常用 近似 ,这里H为L和V的角平分向量,即:
本次实验中,光线为平行光,光线方向为单位向量L(-0.5, 1, 1),视点在点(0.0, 0.0, 5.0)处,视线方向V需要逐点计算。
5.实验代码
gl-matrix.js 下载地址:http://oty0nwcbq.bkt.clouddn.com/gl-matrix.js
(1) 仅有漫反射光的立方体效果
(i) LightedCube-Parallel.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGl光照</title>
</head>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal; // Normal
uniform mat4 u_MvpMatrix;
uniform vec3 u_LightColor; // Light color
uniform vec3 u_LightDirection; // Light direction (in the world coordinate, normalized)
varying vec4 v_Color;
void main() {
gl_Position = u_MvpMatrix * a_Position ;
// Make the length of the normal 1.0
vec3 normal = normalize(a_Normal.xyz);
// Dot product of the light direction and the orientation of a surface (the normal)
float nDotL = max(dot(u_LightDirection, normal), 0.0);
// Calculate the color due to diffuse reflection
vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;
v_Color = vec4(diffuse, a_Color.a);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
</script>
<body onload="startup()">
<canvas id="myGLCanvas" width="600" height="600">
</canvas>
</body>
<script type="text/javascript" src="gl-matrix.js"></script>
<script type="text/javascript" src="LightedCube-Parallel.js"></script>
</html>
(ii) LightedCube-Parallel.js
var gl;
function startup(){
var canvas = document.getElementById('myGLCanvas');//获取<canvas>元素
gl = createGLContext(canvas);
setupShaders();
// Write the positions of vertices to a vertex shader
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
// Set clear color and enable hidden surface removal
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Get the storage location of u_MvpMatrix
var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
var u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection');
if (!u_MvpMatrix || !u_LightColor || !u_LightDirection) {
console.log('Failed to get the storage location');
return;
}
// Set the light color (white)
gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
// Set the light direction (in the world coordinate)
var lightDirection = vec3.fromValues(-0.5, 1, 1);
vec3.normalize(lightDirection,lightDirection); // Normalize
gl.uniform3fv(u_LightDirection, lightDirection);
// Set the eye point and the viewing volume
// View Matrix
var eye = vec3.fromValues(0.0, 0.0, 5.0);
var center = vec3.fromValues(0.0, 0.0, 0.0);
var up = vec3.fromValues(0.0, 1.0, 0.0);
var vMatrix = mat4.create();
mat4.lookAt(vMatrix, eye, center, up);
// Model Matrix
var mMatrix = mat4.create();
mat4.scale(mMatrix, mMatrix, [1.0, 1.0, 1.0]);
mat4.rotate(mMatrix, mMatrix, Math.PI/4, [0.0, 1.0, 0.0]);
// Projection Matrix
var pMatrix = mat4.create();
mat4.frustum(pMatrix, -1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
var mvpMatrix = mat4.create();
mat4.multiply(mvpMatrix, vMatrix, mMatrix);
mat4.multiply(mvpMatrix, pMatrix, mvpMatrix);
// Pass the model view projection matrix to u_MvpMatrix
gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the cube
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}
function createGLContext(canvas) {
var names = ["webgl", "experimental-webgl"];
var context = null;
for (var i=0; i < names.length; i++) {
try {
context = canvas.getContext(names[i]); //获取webgl context绘图上下文
} catch(e) {}
if (context) {
break;
}
}
if (context) {
context.viewportWidth = canvas.width;
context.viewportHeight = canvas.height;
} else {
alert("Failed to create WebGL context!");
}
return context;
}
function setupShaders() {
var vertexShader = loadShader(gl.VERTEX_SHADER, "vertex-shader");
var fragmentShader = loadShader(gl.FRAGMENT_SHADER, "fragment-shader");
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Failed to setup shaders");
}
gl.useProgram(shaderProgram);
gl.program= shaderProgram;
}
function loadShader(type, ShaderId) {
var shaderScript = document.getElementById( ShaderId );
var shader = gl.createShader(type);
gl.shaderSource( shader, shaderScript.text );
gl.compileShader( shader );
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("Error compiling shader" + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
// 立方体绘制采用《WebGL Programming Guide》第7章示例程序ColoredCube
function initVertexBuffers(gl) {
// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
var vertices = new Float32Array([ // Vertex coordinates
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0,-1.0, 1.0, 1.0,-1.0, 1.0, // v0-v1-v2-v3 front
1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, 1.0, 1.0,-1.0, // v0-v3-v4-v5 right
1.0, 1.0, 1.0, 1.0, 1.0,-1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
-1.0, 1.0, 1.0, -1.0, 1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0, 1.0, // v1-v6-v7-v2 left
-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0, // v7-v4-v3-v2 down
1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0 // v4-v7-v6-v5 back
]);
var colors = new Float32Array([ // Colors
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v1-v2-v3 front
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v5-v6-v1 up
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v1-v6-v7-v2 left
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v7-v4-v3-v2 down
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 // v4-v7-v6-v5 back
]);
var normals = new Float32Array([ // Normal
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back
]);
var indices = new Uint8Array([ // Indices of the vertices
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);
// Create a buffer object
var indexBuffer = gl.createBuffer();
if (!indexBuffer)
return -1;
if (!initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT)) return -1;
if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;
if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;
// Write the indices to the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}
function initArrayBuffer (gl, attribute, data, num, type) {
// Create a buffer object
var buffer = gl.createBuffer();
if (!buffer) {
console.log('Failed to create the buffer object');
return false;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// Assign the buffer object to the attribute variable
var a_attribute = gl.getAttribLocation(gl.program, attribute);
if (a_attribute < 0) {
console.log('Failed to get the storage location of ' + attribute);
return false;
}
gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
// Enable the assignment of the buffer object to the attribute variable
gl.enableVertexAttribArray(a_attribute);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return true;
}
(2) 添加环境反射光后的立方体效果
(i) LightedCube-ParallelAmbient.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGl光照</title>
</head>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal; // Normal
uniform mat4 u_MvpMatrix;
uniform vec3 u_DiffuseLight; // Light color
uniform vec3 u_LightDirection; // Light direction (in the world coordinate, normalized)
uniform vec3 u_AmbientLight; // Color of an ambient light
varying vec4 v_Color;
void main() {
gl_Position = u_MvpMatrix * a_Position ;
// Make the length of the normal 1.0
vec3 normal = normalize(a_Normal.xyz);
// Dot product of the light direction and the orientation of a surface (the normal)
float nDotL = max(dot(u_LightDirection, normal), 0.0);
// Calculate the color due to diffuse reflection
vec3 diffuse = u_DiffuseLight * a_Color.rgb * nDotL;
// Calculate the color due to ambient reflection
vec3 ambient = u_AmbientLight * a_Color.rgb;
// Add the surface colors due to diffuse reflection and ambient reflection
v_Color = vec4(diffuse + ambient, a_Color.a);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
</script>
<body onload="startup()">
<canvas id="myGLCanvas" width="600" height="600">
</canvas>
</body>
<script type="text/javascript" src="gl-matrix.js"></script>
<script type="text/javascript" src="LightedCube-ParallelAmbient.js"></script>
</html>
(ii) LightedCube-ParallelAmbient.js
var gl;
function startup(){
var canvas = document.getElementById('myGLCanvas');//获取<canvas>元素
gl = createGLContext(canvas);
setupShaders();
// Write the positions of vertices to a vertex shader
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
// Set clear color and enable hidden surface removal
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Get the storage location of u_MvpMatrix
var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
var u_DiffuseLight = gl.getUniformLocation(gl.program, 'u_DiffuseLight');
var u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection');
var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
if (!u_MvpMatrix || !u_DiffuseLight || !u_LightDirection || !u_AmbientLight) {
console.log('Failed to get the storage location');
return;
}
// Set the light color (white)
gl.uniform3f(u_DiffuseLight, 1.0, 1.0, 1.0);
// Set the light direction (in the world coordinate)
var lightDirection = vec3.fromValues(-0.5, 1, 1);
vec3.normalize(lightDirection,lightDirection); // Normalize
gl.uniform3fv(u_LightDirection, lightDirection);
// Set the ambient light
gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
// Set the eye point and the viewing volume
// View Matrix
var eye = vec3.fromValues(0.0, 0.0, 5.0);
var center = vec3.fromValues(0.0, 0.0, 0.0);
var up = vec3.fromValues(0.0, 1.0, 0.0);
var vMatrix = mat4.create();
mat4.lookAt(vMatrix, eye, center, up);
// Model Matrix
var mMatrix = mat4.create();
mat4.scale(mMatrix, mMatrix, [1.0, 1.0, 1.0]);
mat4.rotate(mMatrix, mMatrix, Math.PI/4, [0.0, 1.0, 0.0]);
// Projection Matrix
var pMatrix = mat4.create();
mat4.frustum(pMatrix, -1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
var mvpMatrix = mat4.create();
mat4.multiply(mvpMatrix, vMatrix, mMatrix);
mat4.multiply(mvpMatrix, pMatrix, mvpMatrix);
// Pass the model view projection matrix to u_MvpMatrix
gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the cube
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}
... // 其他代码相同,故略去
(3) 添加环境反射光与镜面反射光后的立方体效果
(i) LightedCube-ParallelAmbientSpecular.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGl光照</title>
</head>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal; // Normal
uniform mat4 u_MvpMatrix;
uniform vec3 u_DiffuseLight; // Light color
uniform vec3 u_SpecularLight; // Color of an Mirror light
uniform vec3 u_LightDirection; // Light direction (in the world coordinate, normalized)
uniform vec3 u_AmbientLight; // Color of an ambient light
uniform float u_Shininess;
uniform vec3 u_Eye;
varying vec4 v_Color;
void main() {
gl_Position = u_MvpMatrix * a_Position ;
// Make the length of the normal 1.0
vec3 normal = normalize(a_Normal.xyz);
vec3 viewDirection = normalize(u_Eye - a_Position.xyz);
vec3 H = normalize(u_LightDirection + viewDirection);
// Dot product of the light direction and the orientation of a surface (the normal)
float nDotL = max(dot(u_LightDirection, normal), 0.0);
float nDotH = max(dot(H, normal), 0.0);
// Calculate the color due to diffuse reflection
vec3 diffuse = u_DiffuseLight * a_Color.rgb * nDotL;
vec3 specular = pow(nDotH, u_Shininess) * u_SpecularLight;
// Calculate the color due to ambient reflection
vec3 ambient = u_AmbientLight * a_Color.rgb;
// Add the surface colors due to diffuse reflection and ambient reflection
v_Color = vec4(diffuse + specular + ambient, a_Color.a);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
</script>
<body onload="startup()">
<canvas id="myGLCanvas" width="600" height="600">
</canvas>
</body>
<script type="text/javascript" src="gl-matrix.js"></script>
<script type="text/javascript" src="LightedCube-ParallelAmbientSpecular.js"></script>
</html>
(ii) LightedCube-ParallelAmbientSpecular.js
var gl;
function startup(){
var canvas = document.getElementById('myGLCanvas');//获取<canvas>元素
gl = createGLContext(canvas);
setupShaders();
// Write the positions of vertices to a vertex shader
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
// Set clear color and enable hidden surface removal
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Get the storage location of u_MvpMatrix
var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
var u_DiffuseLight = gl.getUniformLocation(gl.program, 'u_DiffuseLight');
var u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection');
var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
var u_SpecularLight = gl.getUniformLocation(gl.program, 'u_SpecularLight');
var u_Shininess = gl.getUniformLocation(gl.program, 'u_Shininess');
var u_Eye = gl.getUniformLocation(gl.program, 'u_Eye');
if (!u_MvpMatrix || !u_DiffuseLight || !u_LightDirection || !u_AmbientLight ||!u_SpecularLight || !u_Shininess || !u_Eye) {
console.log('Failed to get the storage location');
return;
}
// Set the light color (white)
gl.uniform3f(u_DiffuseLight, 1.0, 1.0, 1.0);
// Set the light direction (in the world coordinate)
var lightDirection = vec3.fromValues(-0.5, 1, 1);
vec3.normalize(lightDirection,lightDirection); // Normalize
gl.uniform3fv(u_LightDirection, lightDirection);
// Set the ambient light
gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
gl.uniform3f(u_DiffuseLight, 1.0, 1.0, 1.0);
gl.uniform3f(u_SpecularLight, 1.0, 1.0, 1.0);
gl.uniform1f(u_Shininess, 20.0);
var eye = vec3.fromValues(0.0, 0.0, 5.0);
gl.uniform3f(u_Eye, eye[0], eye[1], eye[2]);
// Set the eye point and the viewing volume
// View Matrix
var center = vec3.fromValues(0.0, 0.0, 0.0);
var up = vec3.fromValues(0.0, 1.0, 0.0);
var vMatrix = mat4.create();
mat4.lookAt(vMatrix, eye, center, up);
// Model Matrix
var mMatrix = mat4.create();
mat4.scale(mMatrix, mMatrix, [1.0, 1.0, 1.0]);
mat4.rotate(mMatrix, mMatrix, Math.PI/4, [0.0, 1.0, 0.0]);
// Projection Matrix
var pMatrix = mat4.create();
mat4.frustum(pMatrix, -1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
var mvpMatrix = mat4.create();
mat4.multiply(mvpMatrix, vMatrix, mMatrix);
mat4.multiply(mvpMatrix, pMatrix, mvpMatrix);
// Pass the model view projection matrix to u_MvpMatrix
gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the cube
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}
... // 其他代码相同,故略去