WebGL笔记(三):绘制立方体
2011-12-01 01:43
274 查看
终于要在三维的场景里绘制一个三维的物体了——1个Cube。
我们先来厘清几个事情:
一个立方体有6个面,每个面4个顶点,所以要绘制24个顶点。
每个顶点位置由3个数字表示,所以顶点信息是72个数字的数组。
每个顶点颜色由4个数字表示,所以颜色信息是96个数字的数组。
先看一看长长的顶点数组:
[code]//Frontface
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
这没什么可说的。比较有趣的是,还有一个“顶点索引”数组:
[code]0,1,2,0,2,3,//front
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
开头说过了,一共24个顶点,这些数字应该是顶点的索引值。那他们的用处是什么呢?引用MDN原文:
https://developer.mozilla.org/en/WebGL/Creating_3D_objects_using_WebGL
The
我们先来厘清几个事情:
一个立方体有6个面,每个面4个顶点,所以要绘制24个顶点。
每个顶点位置由3个数字表示,所以顶点信息是72个数字的数组。
每个顶点颜色由4个数字表示,所以颜色信息是96个数字的数组。
先看一看长长的顶点数组:
varvertices=[
[code]//Frontface
-1.0,-1.0,1.0,
1.0,-1.0,1.0,
1.0,1.0,1.0,
-1.0,1.0,1.0,
//Backface
-1.0,-1.0,-1.0,
-1.0,1.0,-1.0,
1.0,1.0,-1.0,
1.0,-1.0,-1.0,
//Topface
-1.0,1.0,-1.0,
-1.0,1.0,1.0,
1.0,1.0,1.0,
1.0,1.0,-1.0,
//Bottomface
-1.0,-1.0,-1.0,
1.0,-1.0,-1.0,
1.0,-1.0,1.0,
-1.0,-1.0,1.0,
//Rightface
1.0,-1.0,-1.0,
1.0,1.0,-1.0,
1.0,1.0,1.0,
1.0,-1.0,1.0,
//Leftface
-1.0,-1.0,-1.0,
-1.0,-1.0,1.0,
-1.0,1.0,1.0,
-1.0,1.0,-1.0
];
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
这没什么可说的。比较有趣的是,还有一个“顶点索引”数组:
varcubeVertexIndices=[
[code]0,1,2,0,2,3,//front
4,5,6,4,6,7,//back
8,9,10,8,10,11,//top
12,13,14,12,14,15,//bottom
16,17,18,16,18,19,//right
20,21,22,20,22,23//left
]
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
开头说过了,一共24个顶点,这些数字应该是顶点的索引值。那他们的用处是什么呢?引用MDN原文:
The
cubeVertexIndicesarraydefineseachfaceasapairoftriangles,specifyingeachtriangle'sverticesasanindexintothecube'svertexarray.Thusthecubeisdescribedasacollectionof12triangles.
E文不好的童鞋不用担心我来翻译一下,咳:大概其啊,呐,cubeVertexIndices这个数组呢,将每一个面定义为一对三角形,并且标出了每个三角形顶点在vertices数组中的索引键。这样以来呢,这个Cube——就是立方体啦——就被描述为一个12个三角形的集合。接触过3D建模的童鞋,可能对此不会太陌生。
然后是颜色数组。MDN原文为了减少篇幅,只定义了6个颜色给6个面,然后用程序扩展为96个。
varcolorGroups=[
[code][1.0,0.0,1.0,1.0],//white
[1.0,0.0,0.0,1.0],//red
[0.0,1.0,0.0,1.0],//green
[0.0,0.0,1.0,1.0],//blue
[0.0,1.0,1.0,1.0],
[1.0,1.0,0.0,1.0]
];
vargeneratedColors=[];
for(vari=0;i<6;i++){
for(varj=0;j<4;j++){
generatedColors=generatedColors.concat(colorGroups[i]);
}
}
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
颜色每个值的取值范围是0.0~1.0之间的浮点数,每一组4个值分别是红、绿、蓝和透明度。那段扩展的代码比较简单:用一个嵌套循环,将每个数组复制4次,组成一个新的数组。
虽然颜色和顶点的数据有所变化,但是它们的定义和操作没有变化。
绘制开始前,有两个需要注意的地方:
一、在绘制(draw…)之前,应当对场景做初始设置。
//黑底,不透明
[code]gl.clearColor(0.0,0.0,0.0,1.0);
//清除所有
gl.clearDepth(1.0);
//Enabledepthtesting/开启...深度测试?
gl.enable(gl.DEPTH_TEST);
//Nearthingsobscurefarthings/近处物体遮挡远处物体?
gl.depthFunc(gl.LEQUAL);
[/code]
因为这次涉及较为复杂的图形,如果不做设置,尤其是不开启DEPTH_TEST的话,往往会出现比较搞笑的情况。
二、有些语句是有顺序依赖的。
在第一篇中曾经提到过类似问题,本例中也有一处:
//定义顶点
[code]varcubeVerticesBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cubeVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(vertices),gl.STATIC_DRAW);
//传送数据到Shader指定变量
gl.vertexAttribPointer(vertexPositionAttribute,3,gl.FLOAT,false,0,0);
//定义颜色
varcubeVerticesColorBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cubeVerticesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(generatedColors),gl.STATIC_DRAW);
//传送颜色数据到Shader
gl.vertexAttribPointer(vertexColorAttribute,4,gl.FLOAT,false,0,0);
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
在某个数据被bindBuffer之后,当前缓存数据即为该数据,在下次更改之前,必须及时传递到Shader中(vertexAttribPointer)。上面第6、13行如果顺序发生变化的话可能会引发顶点绘制错误。
下面附上所有代码,简单写了注释,不再赘述。MatrixHelper增加了rotate方法,末尾写了一个小动画,可以看到立方体旋转起来。
从下一篇开始,要尝试封装自己的WebGL库,像颜色、顶点之类的复杂数据也计划设计为便于操作的js类。
<!DOCTYPEHTML>
[code]<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=utf-8">
<title>WebGLStep03</title>
<styletype="text/css">
canvas{background-color:#666;}
</style>
<scripttype="text/ecmascript"src="http://files.cnblogs.com/muse/sylvester.js"></script>
<scripttype="text/ecmascript"src="http://files.cnblogs.com/muse/glUtils.js"></script>
<scripttype="text/ecmascript">
functionMatrixHelper(){this.matrix=Matrix.I(4);}
MatrixHelper.prototype={
/*makePerspective*/
make:function(fovy,aspect,znear,zfar){
this.ppm=makePerspective(fovy,aspect,znear,zfar);
},
/*multMatrix*/
mult:function(m){
this.matrix=this.matrix.x(m);
},
/*mvTranslate*/
trans:function(v){
this.mult(Matrix.Translation($V([v[0],v[1],v[2]])).ensure4x4());
},
/*setMatrixUniforms*/
set:function(gl,sProg){
if(!!this.ppm){
gl.uniformMatrix4fv(gl.getUniformLocation(sProg,"uPMatrix")
,false,newFloat32Array(this.ppm.flatten()));
}
if(!!this.matrix){
gl.uniformMatrix4fv(gl.getUniformLocation(sProg,"uMVMatrix")
,false,newFloat32Array(this.matrix.flatten()));
}
},
/*mvRotate*/
rotate:function(angle,v){
varm=Matrix.Rotation(angle*Math.PI/180.0,$V([v[0],v[1],v[2]])).ensure4x4();
this.mult(m);
}
}
</script>
</head>
<body>
<canvasid="glcanvas"width="640"height="480">看来您的浏览器不支持<code><canvas></code>标记</canvas>
<scripttype="text/ecmascript">
vartestVertexCode='\
attributevec3aVertexPosition;\
attributevec4aVertexColor;\
uniformmat4uMVMatrix;\
uniformmat4uPMatrix;\
varyinglowpvec4vColor;\
voidmain(void){\
gl_Position=uPMatrix*uMVMatrix*vec4(aVertexPosition,1.0);\
vColor=aVertexColor;\
}',
testFragmentCode='\
varyinglowpvec4vColor;\
voidmain(void){\
gl_FragColor=vColor;\
}'
;
varvertices=[
//Frontface
-1.0,-1.0,1.0,
1.0,-1.0,1.0,
1.0,1.0,1.0,
-1.0,1.0,1.0,
//Backface
-1.0,-1.0,-1.0,
-1.0,1.0,-1.0,
1.0,1.0,-1.0,
1.0,-1.0,-1.0,
//Topface
-1.0,1.0,-1.0,
-1.0,1.0,1.0,
1.0,1.0,1.0,
1.0,1.0,-1.0,
//Bottomface
-1.0,-1.0,-1.0,
1.0,-1.0,-1.0,
1.0,-1.0,1.0,
-1.0,-1.0,1.0,
//Rightface
1.0,-1.0,-1.0,
1.0,1.0,-1.0,
1.0,1.0,1.0,
1.0,-1.0,1.0,
//Leftface
-1.0,-1.0,-1.0,
-1.0,-1.0,1.0,
-1.0,1.0,1.0,
-1.0,1.0,-1.0
];
varcubeVertexIndices=[
0,1,2,0,2,3,//front
4,5,6,4,6,7,//back
8,9,10,8,10,11,//top
12,13,14,12,14,15,//bottom
16,17,18,16,18,19,//right
20,21,22,20,22,23//left
]
varcolorGroups=[
[1.0,0.0,1.0,1.0],//white
[1.0,0.0,0.0,1.0],//red
[0.0,1.0,0.0,1.0],//green
[0.0,0.0,1.0,1.0],//blue
[0.0,1.0,1.0,1.0],
[1.0,1.0,0.0,1.0]
];
vargeneratedColors=[];
for(vari=0;i<6;i++){
for(varj=0;j<4;j++){
generatedColors=generatedColors.concat(colorGroups[i]);
}
}
varcanvas=document.getElementById('glcanvas');
vargl=canvas.getContext('experimental-webgl');
//黑底,不透明
gl.clearColor(0.0,0.0,0.0,1.0);
//清除所有
gl.clearDepth(1.0);
//Enabledepthtesting/开启...深度测试?
gl.enable(gl.DEPTH_TEST);
//Nearthingsobscurefarthings/近处物体遮挡远处物体?
gl.depthFunc(gl.LEQUAL);
//定义VertextShader
varvertShader=gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader,testVertexCode);
gl.compileShader(vertShader);
//定义FragmentShader
varfragShader=gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader,testFragmentCode);
gl.compileShader(fragShader);
//定义Program
varprogram=gl.createProgram();
//附加两个Shader到program
gl.attachShader(program,vertShader);
gl.attachShader(program,fragShader);
//引用
gl.linkProgram(program);
gl.useProgram(program);
//定位Shader所需变量并启用
varvertexPositionAttribute=gl.getAttribLocation(program,'aVertexPosition');
gl.enableVertexAttribArray(vertexPositionAttribute);
varvertexColorAttribute=gl.getAttribLocation(program,'aVertexColor');
gl.enableVertexAttribArray(vertexColorAttribute);
//定义顶点索引
varcubeVerticesIndexBuffer=gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,cubeVerticesIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,newUint16Array(cubeVertexIndices),gl.STATIC_DRAW);
//定义顶点
varcubeVerticesBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cubeVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(vertices),gl.STATIC_DRAW);
//传送数据到Shader指定变量
gl.vertexAttribPointer(vertexPositionAttribute,3,gl.FLOAT,false,0,0);
//定义颜色
varcubeVerticesColorBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,cubeVerticesColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(generatedColors),gl.STATIC_DRAW);
//传送颜色数据到Shader
gl.vertexAttribPointer(vertexColorAttribute,4,gl.FLOAT,false,0,0);
//调整位置
varmatrix=newMatrixHelper();
matrix.trans([0.0,0.0,-6.0]);
matrix.make(40,640/480,0.1,100.0);
//动画函数
varanimate=function(){
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
matrix.rotate(1,[1,0,1]);
matrix.set(gl,program);
gl.drawElements(gl.TRIANGLES,36,gl.UNSIGNED_SHORT,0);
}
//转吧
setInterval(animate,40);
</script>
</body>
</html>
[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
相关文章推荐
- webgl学习笔记2--图形绘制的几个重要方法详解
- Android OpenGL ES学习笔记之绘制一个立方体
- 41 WebGL绘制一个具有交互的立方体
- webgl+three.js,学习笔记,画一个立方体+解析
- 【C++ OpenGL ES 2.0编程笔记】8: 使用VBO和IBO绘制立方体
- [置顶] 用webgl绘制一个彩色旋转立方体
- 29 WebGL绘制立方体并为立方体每个表面指定颜色
- webgl学习笔记1--如何绘制一个基本图形
- 43 WebGL绘制一个自动旋转的立方体盒子,点击获取点击位置颜色
- 【C++ OpenGL ES 2.0编程笔记】8: 使用VBO和IBO绘制立方体 【转】
- 28 WebGL绘制立方体
- WebGL之旅(十二)IBO绘制立方体
- OpenCV学习笔记5 - 图像绘制功能
- Isometric Game Programming 笔记(一)绘制地图
- 游戏开发笔记之五——游戏画面绘图(二)绘制位图
- 在D3D中绘制一个三角形的一个完整过程(学习3D游戏笔记一)
- opengl学习小笔记(2)使用OpenGL绘制嵌套旋转六边形
- 1.Android 视图及View绘制分析笔记之setContentView
- Cocos2d-x学习笔记(十五)之 绘制图形
- 学习笔记-斯坦福iOS7-第七课:视图,绘制,手势识别