您的位置:首页 > 其它

WebGL笔记(三):绘制立方体

2011-12-01 01:43 274 查看
终于要在三维的场景里绘制一个三维的物体了——1个Cube。

我们先来厘清几个事情:

一个立方体有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原文:

https://developer.mozilla.org/en/WebGL/Creating_3D_objects_using_WebGL


The
cubeVertexIndices
arraydefineseachfaceasapairoftriangles,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;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航