WebGL笔记(六):简单灯光
按MDN的顺序,这篇应该是讲贴图的。但贴图有两个问题不好处理:
1、贴图来源跨域。这种约束的感觉和AJAX差不多,而且MDN也有解释,我想根据经验应该很容易理解;
2、图片格式。这个交待得比较含糊,仅仅有一个提示:
Note: Textures' widths and heights must be a power of two number of pixels (that is, 1, 2, 4, 8, 16, etc).
其实图片格式的限制远不止这么蛋疼。
相比之下灯光问题更容易解决,所以打算先说这个。
首先,使用iWebGL和ArrayHelper/GroupHelper等这几个库,快速创建一个白色的立方体:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGL Step 03</title>
<style type="text/css">
canvas{ background-color:#666; }
</style>
<script type="text/ecmascript" src="http://muse-js-lib.googlecode.com/files/sylvester.js"></script>
<script type="text/ecmascript" src="http://muse-js-lib.googlecode.com/files/glUtils_mod.js"></script>
<script type="text/ecmascript" src="http://muse-js-lib.googlecode.com/files/iWebGL_beta_0.4.js"></script>
<script type="text/ecmascript" src="http://muse-js-lib.googlecode.com/files/ArrayHelper_beta_1.0.js"></script>
<script id="shader-fs" type="x-shader/x-fragment">
varying highp vec2 vTextureCoord;
varying highp vec3 vLighting;
varying lowp vec4 vColor;
uniform sampler2D uSampler;
void main(void) {
highp vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vColor;
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute highp vec3 aVertexNormal;
attribute highp vec3 aVertexPosition;
attribute highp vec2 aTextureCoord;
attribute highp vec4 aVertexColor;
uniform highp mat4 uNormalMatrix;
uniform highp mat4 uMVMatrix;
uniform highp mat4 uPMatrix;
varying highp vec2 vTextureCoord;
varying highp vec3 vLighting;
varying lowp vec4 vColor;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
highp vec3 ambientLight = vec3(0.6, 0.6, 0.6);
highp vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);
highp vec3 directionalVector = vec3(0.85, 0.8, 0.75);
highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
vLighting = ambientLight + (directionalLightColor * directional);
vColor = aVertexColor;
}
</script>
</head>
<body>
<canvas id="glcanvas" width="640" height="480">看来您的浏览器不支持<code><canvas></code>标记</canvas>
<script type="text/ecmascript">
//iWebGL对象初始化
var igl = new iWebGL('glcanvas', 0);
//顶点管理对象
var vg = CubeVertices();
//颜色管理对象
var cg = CubeColors();
//设置六个面的颜色
cg.Front('f');
cg.Back('f');
cg.Left('f');
cg.Right('f');
cg.Top('f');
cg.Bottom('f');
//顶点位置数据
igl.paramVertices('aVertexPosition').define(vg.data);
//顶点着色数据
igl.paramColors('aVertexColor').define(cg.data);
//面三角形顶点索引顺序
igl.paramVerticesIndex().define(vg.indices);
//顶点光照数据
//设置场景
igl.matrix.trans([0.0, 0.0, -6.0]);
igl.matrix.make(40, 640 / 480, 0.1, 100.0);
//动画函数
var animate = function(){
igl.matrix.rotate(1, [1, 0, 1]);
igl.drawCube();
}
//转吧
setInterval(animate, 40);
</script>
</body>
</html>
运行效果如下:
下面我们修改一下FragmentShader脚本中的main函数:
void main(void) {
highp vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
gl_FragColor = vec4(vColor.a * vLighting, vColor.a);
}
猜测一下第三行:计算vColor的Alpha通道值与灯光值vLighting的乘积,并重新赋值给vColor的Alpha属性。这句算法是关键。
下面定义顶点光源数据并传递给Shader:
//顶点光源数据
igl.paramVertices('aVertexNormal').define([
// Front
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
// Back
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
// Top
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
// Bottom
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
// Right
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
// Left
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
]);
见下面的效果
完整示例:WebGL-Step-06.html
下篇讲贴图