zoukankan      html  css  js  c++  java
  • Web三维编程入门总结之一:WebGL与Threejs入门知识

      1 /*在这里对这段时间学习的3D编程知识做个总结,以备再次出发。计划分成“webgl与three.js基础介绍”、“面向对象的基础3D场景框架编写”、“模型导入与简单3D游戏编写”三个部分,其他零散知识以后有机会再总结。*/
      2 /*第一部分,webgl与three.js基础介绍,要求读者掌握JavaScript入门知识*/
      3 //webgl原理:通过JavaScript语言在浏览器端生成glsl代码,把glsl代码送入显卡执行,把执行结果显示在浏览器中
      4 //简单例程:
      5 //根据Tony Parisi著《WebGL入门指南》第一章修改而来(简称T)
      6 window.onload=webGLStart;
      7 var gl;
      8 function webGLStart()
      9 {    
     10     var canvas = document.getElementById("can_main");//canvas是html5下的绘图标签,可以支持3D绘图
     11     gl=initGL(canvas);//初始化“绘制上下文”,以后的绘制都要通过它进行
     12     var square=createSquare(gl);//建立一个演示用的四边形,包括顶点坐标,顶点数组格式和顶点绘制方法
     13     var matrix=initMatrices();//定义两个矩阵
     14     
     15     var shaderProgram=initShaders();//定义着色器程序(glsl)
     16 
     17     draw(gl,square,matrix,shaderProgram);//调用显卡进行绘制
     18     onLoad();//稍后用来触发three.js方式的绘图
     19 }
     20 function initGL(canvas){
     21     var gl;
     22     try
     23     {
     24         gl = canvas.getContext("experimental-webgl");//从canvas中获取webgl上下文
     25         gl.viewport(0,0,canvas.width,canvas.height);//设置视口
     26     }
     27     catch(e)
     28     {
     29         var msg="Error creating WebGL Context!: "  e.toString();
     30         alert(msg);  //弹出错误信息      
     31     }
     32     return gl;
     33 }
     34 function createSquare(gl)
     35 {
     36     var vertexBuffer=gl.createBuffer();//建立一个顶点缓存
     37     gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
     38     var verts = [
     39         1.0,  1.0,  0.0,
     40         -1.0,  1.0,  0.0,
     41         1.0, -1.0,  0.0,
     42         -1.0, -1.0,  0.0
     43     ];//把三维空间中的四个顶点存储在一个一维数组中
     44     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);//把数组元素的存储方式设为“32位浮点数”
     45     var square={buffer:vertexBuffer,vertSize:3,nVerts:4,primtype:gl.TRIANGLE_STRIP};    //使用一个JavaScript对象返回信息:使用vertexBuffer缓存顶点信息,三维空间顶点,共四个顶点,使用“三角形带”图元绘制方法
     46     return square;
     47 }
     48 function initMatrices()
     49 {
     50     //定义姿态矩阵,即所有物体共用的相对于原点的位置和姿态
     51     var modelViewMatrix=new Float32Array(
     52         [1,0,0,0,
     53             0,1,0,0,
     54             0,0,1,0,
     55             0,0,-30.333,1]
     56     );
     57     //定义投影矩阵,即物体近大远小的透视程度
     58     var projectionMatrix=new Float32Array([
     59         2.41421,0,0,0,
     60         0,2.41421,0,0,
     61         0,0,-1.002002,-1,
     62         0,0,-0.2002002,0
     63     ]);
     64     var matrix={mvm:modelViewMatrix,pjm:projectionMatrix};
     65     return matrix;
     66 }
     67 function initShaders()
     68 {
     69     /*着色器(Shader)位于显卡上,分为顶点着色器和片元着色器两种,数量各以千记。
     70     其中顶点着色器运行顶点着色器程序,负责对每个顶点的位置颜色信息的计算;
     71     片元着色器运行片元着色器程序,负责对顶点之间的内容进行“插值”,得出每个像素的颜色;
     72     顶点着色器 片元着色器 光栅化=显卡渲染管线*/
     73     //顶点着色器
     74     var vertexShaderSource=
     75         " attribute vec3 vertexPos;
    " 
     76         " uniform mat4 modelViewMatrix;
    " 
     77         " uniform mat4 projectionMatrix;
    " 
     78         " void main(void) {
    " 
     79         " //返回变换并投影后的顶点数据
    " 
     80         " gl_Position=projectionMatrix*modelViewMatrix*vec4(vertexPos,1.0);
    " 
     81         " }
    ";
     82     //片元着色器
     83     var fragmentShaderSource=
     84         " void main(void){
    " 
     85         " //返回像素颜色:永远输出白色
    " 
     86         " gl_FragColor=vec4(1.0,1.0,1.0,1.0);
    " 
     87         " }
    ";
     88     //glsl的注释是“//
     89 
     90     //这里是对shader代码的编译
     91     var vertexShader=gl.createShader(gl.VERTEX_SHADER);
     92     gl.shaderSource(vertexShader, vertexShaderSource);
     93     gl.compileShader(vertexShader);
     94     if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
     95         alert(gl.getShaderInfoLog(shader));
     96     }
     97 
     98     var fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
     99     gl.shaderSource(fragmentShader, fragmentShaderSource);
    100     gl.compileShader(fragmentShader);
    101     if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
    102         alert(gl.getShaderInfoLog(shader));
    103     }
    104 
    105     //对glsl进行连接
    106     var shaderProgram = gl.createProgram();
    107     gl.attachShader(shaderProgram, vertexShader);
    108     gl.attachShader(shaderProgram, fragmentShader);
    109     gl.linkProgram(shaderProgram);
    110     gl.getProgramParameter(shaderProgram, gl.LINK_STATUS);
    111 
    112     return shaderProgram;//返回编译连接之后的着色器程序
    113 }
    114 function draw(gl,obj,matrix,shaderProgram)//这里只进行了一个物体的一次绘制,事实上obj完全可以是一个物体数组
    115 {
    116     gl.clearColor(0.0,0.0,0.0,1.0);//使用完全不透明的黑色清屏
    117     gl.clear(gl.COLOR_BUFFER_BIT);
    118 
    119     gl.bindBuffer(gl.ARRAY_BUFFER,obj.buffer);//将gl对象与这个物体的缓存暂时绑定
    120 
    121     gl.useProgram(shaderProgram);//让gl使用上面定义的着色器程序
    122 
    123     gl.enableVertexAttribArray(gl.getAttribLocation(shaderProgram, "vertexPos"));//告诉WebGL我们将通过一个array提供顶点信息
    124     gl.vertexAttribPointer(gl.getAttribLocation(shaderProgram, "vertexPos"),obj.vertSize,gl.FLOAT,false,0,0);//提供顶点信息,顶点信息被保存在顶点着色器的vertexPos属性里(变量映射)
    125     gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, "projectionMatrix"),false,matrix.pjm);
    126     gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram, "modelViewMatrix"),false,matrix.mvm);//将两个矩阵的信息发送给显卡
    127 
    128     gl.drawArrays(obj.primtype,0,obj.nVerts);//通知显卡按照顶点数组画图
    129 }
     1 //为提高编程效率,人们编写了一些基于WebGL的绘图引擎,Three.js是其中应用较广的一种:
     2 //使用Three.js实现同样的绘制
     3 function onLoad()
     4 {
     5     var container=document.getElementById("container");
     6 
     7     //Three.js定义的“场景”对象
     8     var scene=new THREE.Scene();
     9     //进行WebGL兼容性判断
    10     if(webglAvailable()){
    11         var renderer=new THREE.WebGLRenderer();
    12     }else{
    13         var renderer=new THREE.CanvasRenderer();//对于环境支持html5但不支持webgl的情况,可以尝试使用更慢一些的2Dcanvas来软件绘图,但效果差强人意
    14     }
    15     renderer.setSize(container.offsetWidth,container.offsetHeight);//render可以看成是对canvas的一种扩展
    16     container.appendChild(renderer.domElement);
    17 
    18     //定义相机,类似于WebGL中的定义投影矩阵,
    19     var camera=new THREE.PerspectiveCamera(45,container.offsetWidth/container.offsetHeight,1,4000);
    20     camera.position.set(0,0,30.3333);//起原版中姿态矩阵的共用部分的作用,但不同的是:这里是观察者向相反的方向移动了。
    21     scene.add(camera);//相机对象被添加到了场景中,可以认为场景对象是用来与显卡进行交互的东西,其中包含了变量映射
    22 
    23     var geometry=new THREE.PlaneGeometry(2,2);//库中包含预制的几何体,通过少量参数即可生成完整的顶点数组,这里是一个宽高为二的四边形
    24     var mesh=new THREE.Mesh(geometry,new THREE.MeshBasicMaterial());//赋予这个几何体材质,材质对应反光性
    25     scene.add(mesh);
    26 
    27     renderer.render(scene,camera);// 渲染
    28 }
    29 function webglAvailable()
    30 {//webgl的绘图是建立在显卡的基础上的,如果这台计算机没有显卡,或者浏览器不支持和显卡的通信,webgl上下文的建立将会失败
    31     try{
    32         var canvas=document.createElement("canvas");
    33         return !!(window.WebGLRenderingContext
    34         &&(canvas.getContext("webgl")||canvas.getContext("experimental-webgl"))
    35         );
    36     }catch(e){
    37         return false;
    38     }
    39 }
     1 <!DOCTYPE html>
     2 <html>
     3 <head lang="en">
     4     <meta charset="UTF-8">
     5     <title>webgl与three.js基础介绍</title>
     6 </head>
     7 <body>
     8     <!--在canvas中使用webglAPI绘制-->
     9     <canvas id="can_main" width="500" height="500"
    10             style="500px;height:500px;float: left"></canvas>
    11     <!--使用Three.js库绘制-->
    12     <div id="container" style="500px;height:500px;background-color: #000000;float: left"></div>
    13 </body>
    14 
    15 <script>
    16     
    17 </script>
    18 <!---->
    19 <script src="mygl1.js"></script>
    20 <script src="mygl1b.js"></script>
    21 
    22 <!--引用three.js库文件-->
    23 <!--three库是由多个文件联合成的一个大库,链接方式不同、库版本不同会产生不同的库文件!!-->
    24 
    25 <!--这个版本旧一些但是只需要引用一个文件-->
    26 <!--https://github.com/tparisi/WebGLBook/tree/master/libs-->
    27 <!--script src="../LIBS/Three.js"></script-->
    28 
    29 <!--这个版本较新但需要引用额外的文件-->
    30 <!--https://github.com/mrdoob/three.js/tree/master/build-->
    31 <!--https://github.com/mrdoob/three.js/tree/master/examples/js/renderers-->
    32 <script src="three.min.js"></script>
    33 <script src="Projector.js"></script>
    34 <script src="CanvasRenderer.js"></script>
    35 
    36 </html>
      1 <!DOCTYPE html>
      2 <html>
      3 <head lang="en">
      4 <title>加入光照、纹理、运动效果</title>
      5 <meta charset="UTF-8">
      6 <!--稍微复杂一点的场景,根据Giles Thomas的learningwebgl.com第七章修改而来(简称G)-->
      7 <!--一个数学库用来实现一些数学计算-->
      8 <script src="glMatrix-0.9.5.min.js" type="text/javascript"></script>
      9 <!--google的一个帧动画辅助库-->
     10 <script src="webgl-utils.js" type="text/javascript"></script>
     11 
     12 <!--G把着色器代码放在了script标签里-->
     13 <script id="shader-vs" type="x-shader/x-vertex">
     14     attribute vec3 aVertexPosition;//顶点位置数组
     15     attribute vec3 aVertexNormal;//法线向量数组
     16     attribute vec2 aTextureCoord;//纹理坐标数组
     17 
     18     uniform mat4 uMVMatrix;//模型姿态矩阵
     19     uniform mat4 uPMatrix;//投影矩阵
     20     uniform mat3 uNMatrix;
     21 
     22     uniform vec3 uAmbientColor;//环境光
     23 
     24     uniform vec3 uLightingDirection;//方向光方向
     25     uniform vec3 uDirectionalColor;//方向光颜色
     26 
     27     uniform bool uUseLighting;//是否使用光照
     28 //在glsl中,attribute和uniform是输入顶点着色器的只读常量,varying是从顶点着色器中输入片元着色器的变量
     29 //vec3是含有三个分量的元素组成的数组,mat4是4*4矩阵    
     30     varying vec2 vTextureCoord;
     31     varying vec3 vLightWeighting;//顶点光照
     32 
     33     void main(void) {
     34         gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);//顶点位置数组经过模型姿态矩阵和投影矩阵变化后得到顶点位置
     35         vTextureCoord = aTextureCoord;
     36         
     37         if (!uUseLighting) {
     38             vLightWeighting = vec3(1.0, 1.0, 1.0);//如果选择不使用光照则设为最强白光
     39         } else {
     40             vec3 transformedNormal = uNMatrix * aVertexNormal;//对法线向量数组进行姿态变换
     41             float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);//按照法线方向和方向光方向计算反射光强度
     42             vLightWeighting = uAmbientColor   uDirectionalColor * directionalLightWeighting;//反射光加环境光得到顶点光照情况,这里使用的是最简单的光照模型,没有涉及材质。            
     43         }
     44     }
     45 </script>
     46 <script id="shader-fs" type="x-shader/x-fragment">
     47     precision mediump float;//显卡处理浮点数的精度
     48 
     49     varying vec2 vTextureCoord;
     50     varying vec3 vLightWeighting;
     51 
     52     uniform sampler2D uSampler;//二维纹理句柄
     53 
     54     void main(void) {
     55         vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));//根据纹理坐标对纹理进行切割
     56         //OpenGL标准显卡为提高模型缩放时的渲染效率,需要为模型纹理建立多个逐渐缩小的缩略图,受此限制图片的边长必须为2的整数次方,但实际纹理基本不会符合此要求,所以实际纹理图片会把不规则纹理放在规则图片中,再使用纹理坐标进行切割提取
     57         gl_FragColor = vec4(textureColor.rgb * vLightWeighting, textureColor.a);//纹理颜色乘以光照,再加上透明度信息作为实际片元颜色
     58     }
     59 </script>
     60 <!--gl_FragColor是glsl的保留字,表示片元着色器的输出-->
     61 
     62 
     63 <!--程序入口在webGLStart()函数-->
     64 <script type="text/javascript">
     65 
     66 var gl;
     67 //初始化weblg上下文
     68 function initGL(canvas) {
     69     try {
     70         gl = canvas.getContext("experimental-webgl");
     71         gl.viewportWidth = canvas.width;
     72         gl.viewportHeight = canvas.height;
     73     } catch (e) {
     74     }
     75     if (!gl) {
     76         alert("Could not initialise WebGL, sorry :-(");
     77     }
     78 }
     79 
     80 //生成着色器代码
     81 function getShader(gl, id) {
     82     var shaderScript = document.getElementById(id);
     83     if (!shaderScript) {
     84         return null;
     85     }
     86 
     87     var str = "";
     88     var k = shaderScript.firstChild;
     89     while (k) {
     90         if (k.nodeType == 3) {
     91             str  = k.textContent;
     92         }
     93         k = k.nextSibling;
     94     }
     95 
     96     var shader;
     97     if (shaderScript.type == "x-shader/x-fragment") {
     98         shader = gl.createShader(gl.FRAGMENT_SHADER);
     99     } else if (shaderScript.type == "x-shader/x-vertex") {
    100         shader = gl.createShader(gl.VERTEX_SHADER);
    101     } else {
    102         return null;
    103     }
    104 
    105     gl.shaderSource(shader, str);//根据网页标签里的内容去生成shader program内容
    106     gl.compileShader(shader);
    107 
    108     if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    109         alert(gl.getShaderInfoLog(shader));
    110         return null;
    111     }
    112 
    113     return shader;
    114 }
    115 
    116 
    117 var shaderProgram;//用来和显卡交互的对象,是很多属性的结合体
    118 //初始化着色器
    119 function initShaders() {
    120     var fragmentShader = getShader(gl, "shader-fs");
    121     var vertexShader = getShader(gl, "shader-vs");//根据标签内容编译着色器代码
    122 
    123     shaderProgram = gl.createProgram();
    124     gl.attachShader(shaderProgram, vertexShader);
    125     gl.attachShader(shaderProgram, fragmentShader);//把两个着色器的代码分别装填到shaderProgram中
    126     gl.linkProgram(shaderProgram);//连接着色器代码
    127 
    128     if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {//通过gl的属性验证连接是否成功
    129         alert("Could not initialise shaders");
    130     }
    131 
    132     gl.useProgram(shaderProgram);
    133     //下面是需要传给显卡的参数(变量映射),通过这种方式把JavaScript中的变量和glsl中的输入量关联起来
    134     shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    135     gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
    136 
    137     shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
    138     gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);
    139 
    140     shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    141     gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
    142 
    143     shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    144     shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    145     shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
    146     shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
    147     shaderProgram.useLightingUniform = gl.getUniformLocation(shaderProgram, "uUseLighting");
    148     shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");
    149     shaderProgram.lightingDirectionUniform = gl.getUniformLocation(shaderProgram, "uLightingDirection");
    150     shaderProgram.directionalColorUniform = gl.getUniformLocation(shaderProgram, "uDirectionalColor");
    151 }
    152 
    153 
    154 //处理载入的图片文件
    155 function handleLoadedTexture(texture) {
    156     gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    157 
    158     gl.bindTexture(gl.TEXTURE_2D, texture);
    159     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);//将图片对象变成纹理对象
    160     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);//图片放大或扭曲时的插值方式
    161     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
    162     gl.generateMipmap(gl.TEXTURE_2D);//缩略图
    163 
    164     gl.bindTexture(gl.TEXTURE_2D, null);
    165 }
    166 
    167 
    168 var crateTexture;
    169 var neheTexture;
    170 //载入图片文件
    171 function initTexture() {
    172     crateTexture = gl.createTexture();
    173     crateTexture.image = new Image();
    174     crateTexture.image.onload = function () {//onload事件代表图片载入完成
    175         handleLoadedTexture(crateTexture)
    176     }
    177     crateTexture.image.src = "crate.gif";//使用google chrome进行本地测试时注意跨域设置!!
    178 
    179     neheTexture = gl.createTexture();
    180     neheTexture.image = new Image();
    181     neheTexture.image.onload = function () {
    182         handleLoadedTexture(neheTexture)
    183     }
    184     neheTexture.image.src = "nehe.gif";
    185     //这里载入了两个图片,其实完全可以把两幅图片合在一起使用纹理坐标切割选择
    186 }
    187 
    188 
    189 var mvMatrix = mat4.create();
    190 var mvMatrixStack = [];
    191 var pMatrix = mat4.create();
    192 
    193 //考虑到场景中存在多个物体,它们的姿态矩阵有公用的部分也有私有的部分,故在设置私有部分时把共有部分入栈
    194 function mvPushMatrix() {
    195     var copy = mat4.create();
    196     mat4.set(mvMatrix, copy);
    197     mvMatrixStack.push(copy);
    198 }
    199 //设置完私有部分后将共有部分出栈,再去设置下一个物体
    200 function mvPopMatrix() {
    201     if (mvMatrixStack.length == 0) {
    202         throw "Invalid popMatrix!";
    203     }
    204     mvMatrix = mvMatrixStack.pop();
    205 }
    206 
    207 //三个矩阵的变量映射
    208 function setMatrixUniforms() {
    209     gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);//投影
    210     gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);//顶点
    211 
    212     var normalMatrix = mat3.create();//法线
    213     mat4.toInverseMat3(mvMatrix, normalMatrix);
    214     mat3.transpose(normalMatrix);
    215     gl.uniformMatrix3fv(shaderProgram.nMatrixUniform, false, normalMatrix);
    216 }
    217 
    218 //角度转化为弧度,webgl默认支持弧度
    219 function degToRad(degrees) {
    220     return degrees * Math.PI / 180;
    221 }
    222 
    223 
    224 
    225 var xRot = 0;
    226 var xSpeed = 3;
    227 
    228 var yRot = 0;
    229 var ySpeed = -3;
    230 
    231 var z = -5.0;
    232 
    233 //键盘处理,通过这种方式可以处理同时按下多个按键
    234 var currentlyPressedKeys = {};
    235 
    236 function handleKeyDown(event) {
    237     currentlyPressedKeys[event.keyCode] = true;
    238 }
    239 
    240 
    241 function handleKeyUp(event) {
    242     currentlyPressedKeys[event.keyCode] = false;
    243 }
    244 
    245 
    246 function handleKeys() {
    247     if (currentlyPressedKeys[33]) {
    248         // Page Up
    249         z -= 0.05;
    250     }
    251     if (currentlyPressedKeys[34]) {
    252         // Page Down
    253         z  = 0.05;
    254     }
    255     if (currentlyPressedKeys[37]) {
    256         // Left cursor key
    257         ySpeed -= 1;
    258     }
    259     if (currentlyPressedKeys[39]) {
    260         // Right cursor key
    261         ySpeed  = 1;
    262     }
    263     if (currentlyPressedKeys[38]) {
    264         // Up cursor key
    265         xSpeed -= 1;
    266     }
    267     if (currentlyPressedKeys[40]) {
    268         // Down cursor key
    269         xSpeed  = 1;
    270     }
    271 }
    272 
    273 var cubeVertexPositionBuffer;
    274 var cubeVertexNormalBuffer;
    275 var cubeVertexTextureCoordBuffer;
    276 var cubeVertexIndexBuffer;
    277 var cubeVertexIndexBuffer2;
    278 //初始化缓存
    279 function initBuffers() {
    280     cubeVertexPositionBuffer = gl.createBuffer();
    281     gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    282     //一个正方形的顶点数组
    283     vertices = [
    284         // Front face
    285         -1.0, -1.0,  1.0,
    286         1.0, -1.0,  1.0,
    287         1.0,  1.0,  1.0,
    288         -1.0,  1.0,  1.0,
    289 
    290         // Back face
    291         -1.0, -1.0, -1.0,
    292         -1.0,  1.0, -1.0,
    293         1.0,  1.0, -1.0,
    294         1.0, -1.0, -1.0,
    295 
    296         // Top face
    297         -1.0,  1.0, -1.0,
    298         -1.0,  1.0,  1.0,
    299         1.0,  1.0,  1.0,
    300         1.0,  1.0, -1.0,
    301 
    302         // Bottom face
    303         -1.0, -1.0, -1.0,
    304         1.0, -1.0, -1.0,
    305         1.0, -1.0,  1.0,
    306         -1.0, -1.0,  1.0,
    307 
    308         // Right face
    309         1.0, -1.0, -1.0,
    310         1.0,  1.0, -1.0,
    311         1.0,  1.0,  1.0,
    312         1.0, -1.0,  1.0,
    313 
    314         // Left face
    315         -1.0, -1.0, -1.0,
    316         -1.0, -1.0,  1.0,
    317         -1.0,  1.0,  1.0,
    318         -1.0,  1.0, -1.0,
    319     ];
    320     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    321     cubeVertexPositionBuffer.itemSize = 3;
    322     cubeVertexPositionBuffer.numItems = 24;
    323 
    324     //正方形每个面的法线向量
    325     cubeVertexNormalBuffer = gl.createBuffer();//法线向量
    326     gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);
    327     var vertexNormals = [
    328         // Front face
    329         0.0,  0.0,  1.0,
    330         0.0,  0.0,  1.0,
    331         0.0,  0.0,  1.0,
    332         0.0,  0.0,  1.0,
    333 
    334         // Back face
    335         0.0,  0.0, -1.0,
    336         0.0,  0.0, -1.0,
    337         0.0,  0.0, -1.0,
    338         0.0,  0.0, -1.0,
    339 
    340         // Top face
    341         0.0,  1.0,  0.0,
    342         0.0,  1.0,  0.0,
    343         0.0,  1.0,  0.0,
    344         0.0,  1.0,  0.0,
    345 
    346         // Bottom face
    347         0.0, -1.0,  0.0,
    348         0.0, -1.0,  0.0,
    349         0.0, -1.0,  0.0,
    350         0.0, -1.0,  0.0,
    351 
    352         // Right face
    353         1.0,  0.0,  0.0,
    354         1.0,  0.0,  0.0,
    355         1.0,  0.0,  0.0,
    356         1.0,  0.0,  0.0,
    357 
    358         // Left face
    359         -1.0,  0.0,  0.0,
    360         -1.0,  0.0,  0.0,
    361         -1.0,  0.0,  0.0,
    362         -1.0,  0.0,  0.0
    363     ];
    364     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals), gl.STATIC_DRAW);
    365     cubeVertexNormalBuffer.itemSize = 3;
    366     cubeVertexNormalBuffer.numItems = 24;
    367 
    368     //每个面的纹理坐标
    369     cubeVertexTextureCoordBuffer = gl.createBuffer();
    370     gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    371     var textureCoords = [
    372         // Front face
    373         0.0, 0.0,
    374         1.0, 0.0,
    375         1.0, 1.0,
    376         0.0, 1.0,
    377 
    378         // Back face
    379         1.0, 0.0,
    380         1.0, 1.0,
    381         0.0, 1.0,
    382         0.0, 0.0,
    383 
    384         // Top face
    385         0.0, 1.0,
    386         0.0, 0.0,
    387         1.0, 0.0,
    388         1.0, 1.0,
    389 
    390         // Bottom face
    391         1.0, 1.0,
    392         0.0, 1.0,
    393         0.0, 0.0,
    394         1.0, 0.0,
    395 
    396         // Right face
    397         1.0, 0.0,
    398         1.0, 1.0,
    399         0.0, 1.0,
    400         0.0, 0.0,
    401 
    402         // Left face
    403         0.0, 0.0,
    404         1.0, 0.0,
    405         1.0, 1.0,
    406         0.0, 1.0
    407     ];
    408     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
    409     cubeVertexTextureCoordBuffer.itemSize = 2;
    410     cubeVertexTextureCoordBuffer.numItems = 24;
    411 
    412     //顶点绘制顺序,即存在24个顶点,分别使用其中的哪几个顶点绘制三角形
    413     //因为使用了两个纹理句柄,这里将正方形分成了两个物体,降低了效率
    414     cubeVertexIndexBuffer = gl.createBuffer();
    415     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    416     var cubeVertexIndices = [
    417         //0, 1, 2,      0, 2, 3,    // Front face
    418         //4, 5, 6,      4, 6, 7,    // Back face
    419         //8, 9, 10,     8, 10, 11,  // Top face
    420         12, 13, 14,   12, 14, 15, // Bottom face
    421         16, 17, 18,   16, 18, 19, // Right face
    422         20, 21, 22,   20, 22, 23  // Left face
    423     ];
    424     gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
    425     //cubeVertexIndexBuffer.itemSize = 1;
    426     //cubeVertexIndexBuffer.numItems = 36;
    427 
    428     cubeVertexIndexBuffer2 = gl.createBuffer();
    429     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer2);
    430     var cubeVertexIndices2 = [
    431         0, 1, 2,      0, 2, 3,    // Front face
    432         4, 5, 6,      4, 6, 7,    // Back face
    433         8, 9, 10,     8, 10, 11  // Top face
    434         //12, 13, 14,   12, 14, 15, // Bottom face
    435         //16, 17, 18,   16, 18, 19, // Right face
    436         //20, 21, 22,   20, 22, 23  // Left face
    437     ];
    438     gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices2), gl.STATIC_DRAW);
    439 }
    440 
    441 //场景绘制
    442 function drawScene() {
    443     gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    444     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    445 
    446     //光照
    447     var lighting = document.getElementById("lighting").checked;
    448     gl.uniform1i(shaderProgram.useLightingUniform, lighting);
    449     //从html中读取光照设置
    450     if (lighting) {
    451         gl.uniform3f(
    452                 shaderProgram.ambientColorUniform,
    453                 parseFloat(document.getElementById("ambientR").value),
    454                 parseFloat(document.getElementById("ambientG").value),
    455                 parseFloat(document.getElementById("ambientB").value)
    456         );
    457         var lightingDirection = [
    458             parseFloat(document.getElementById("lightDirectionX").value),
    459             parseFloat(document.getElementById("lightDirectionY").value),
    460             parseFloat(document.getElementById("lightDirectionZ").value)
    461         ];
    462         var adjustedLD = vec3.create();
    463         vec3.normalize(lightingDirection, adjustedLD);
    464 
    465         vec3.scale(adjustedLD, -1);
    466         gl.uniform3fv(shaderProgram.lightingDirectionUniform, adjustedLD);
    467         gl.uniform3f(
    468                 shaderProgram.directionalColorUniform,
    469                 parseFloat(document.getElementById("directionalR").value),
    470                 parseFloat(document.getElementById("directionalG").value),
    471                 parseFloat(document.getElementById("directionalB").value)
    472         );
    473     }
    474 
    475     //变换姿态矩阵,创造出物体运动效果
    476     mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
    477     mat4.identity(mvMatrix);
    478     mat4.translate(mvMatrix, [0.0, 0.0, z]);
    479     mat4.rotate(mvMatrix, degToRad(xRot), [1, 0, 0]);
    480     mat4.rotate(mvMatrix, degToRad(yRot), [0, 1, 0]);
    481     setMatrixUniforms();//考虑到多个物体的变化,这个矩阵设置加入在绘制之前,如果需要在另一个位置绘制物体,就再设置一次姿态矩阵
    482 
    483     //顶点数组变量映射
    484     gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    485     gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
    486     gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexNormalBuffer);
    487     gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, cubeVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
    488     gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    489     gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
    490 
    491     //纹理与顶点索引
    492     gl.activeTexture(gl.TEXTURE0);
    493     gl.bindTexture(gl.TEXTURE_2D, crateTexture);
    494     gl.uniform1i(shaderProgram.samplerUniform, 0);//传给着色器
    495 
    496     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    497     gl.drawElements(gl.TRIANGLES, 18, gl.UNSIGNED_SHORT, 0);//与上一例程中的“三角形带”方式不同,包含顶点绘制顺序时使用drawElements方法绘制
    498 
    499     gl.activeTexture(gl.TEXTURE1);
    500     gl.bindTexture(gl.TEXTURE_2D, neheTexture);
    501     gl.uniform1i(shaderProgram.samplerUniform, 1);//传给着色器,替换了上一个samplerUniform变量的值
    502 
    503     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer2);
    504     gl.drawElements(gl.TRIANGLES, 18, gl.UNSIGNED_SHORT, 0);
    505 }
    506 
    507 
    508 var lastTime = 0;
    509 //根据延迟时间计算动画效果,使得动画效果不受帧率影响
    510 function animate() {
    511     var timeNow = new Date().getTime();
    512     if (lastTime != 0) {
    513         var elapsed = timeNow - lastTime;
    514 
    515         xRot  = (xSpeed * elapsed) / 1000.0;
    516         yRot  = (ySpeed * elapsed) / 1000.0;
    517     }
    518     lastTime = timeNow;
    519 }
    520 
    521 
    522 function tick() {
    523     requestAnimFrame(tick);//在浏览器认为可以时重调循环,这样可以随着系统负载情况不同产生动态帧率
    524     handleKeys();//处理键盘
    525     drawScene();//绘制场景
    526     animate();//帧动画
    527 }
    528 
    529 
    530 function webGLStart() {
    531     var canvas = document.getElementById("lesson07-canvas");
    532     initGL(canvas);//上下文
    533     initShaders();//着色器
    534     initBuffers();//缓存
    535     initTexture();//纹理
    536 
    537     gl.clearColor(0.0, 0.0, 0.0, 1.0);
    538     gl.enable(gl.DEPTH_TEST);//深度探测打开,webgl认为被遮挡的三角形将不被渲染,处理半透明物体时需关掉深度探测
    539 
    540     document.onkeydown = handleKeyDown;//声明键盘事件
    541     document.onkeyup = handleKeyUp;
    542 
    543     tick();//绘制循环
    544 }
    545 /*可以看到,随着页面复杂度的提高,webglAPI绘制方法的变量映射和glsl代码越来越多,因此在实际应用中往往使用运行库对这部分代码进行封装。至于顶点数组、法线向量、纹理坐标、纹理图片则使用标准绘制函数或模型文件进行封装*/
    546 </script>
    547 
    548 
    549 </head>
    550 
    551 
    552 <body onload="webGLStart();">
    553 <a href="http://learningwebgl.com/blog/?p=684">&lt;&lt; Back to Lesson 7</a><br>
    554 
    555 <canvas width="500" height="500" id="lesson07-canvas" style="border: currentColor; border-image: none;"></canvas>
    556 
    557 <br>
    558 <input id="lighting" type="checkbox" checked=""> Use lighting<br>
    559 (Use cursor keys to spin the box and <code>Page Up</code>/<code>Page Down</code> to zoom out/in)
    560 
    561 <br>
    562 <h2>Directional light:</h2>
    563 
    564 <table style="padding: 10px; border: 0px currentColor; border-image: none;">
    565     <tbody><tr>
    566         <td><b>Direction:</b>
    567         <td>X: <input id="lightDirectionX" type="text" value="-0.25">
    568         <td>Y: <input id="lightDirectionY" type="text" value="-0.25">
    569         <td>Z: <input id="lightDirectionZ" type="text" value="-1.0">
    570     </tr>
    571     <tr>
    572         <td><b>Colour:</b>
    573         <td>R: <input id="directionalR" type="text" value="0.8">
    574         <td>G: <input id="directionalG" type="text" value="0.8">
    575         <td>B: <input id="directionalB" type="text" value="0.8">
    576     </tr>
    577     </tbody></table>
    578 
    579 <h2>Ambient light:</h2>
    580 <table style="padding: 10px; border: 0px currentColor; border-image: none;">
    581     <tbody><tr>
    582         <td><b>Colour:</b>
    583         <td>R: <input id="ambientR" type="text" value="0.2">
    584         <td>G: <input id="ambientG" type="text" value="0.2">
    585         <td>B: <input id="ambientB" type="text" value="0.2">
    586     </tr>
    587     </tbody></table>
    588 
    589 <a href="http://learningwebgl.com/blog/?p=684">&lt;&lt; Back to Lesson 7</a>
    590 
    591 
    592 
    593 </body></html>
      1 <!DOCTYPE html>
      2 <html>
      3 <head lang="en">
      4 <title>使用Three.js实现上述效果</title>
      5 <meta charset="UTF-8">
      6     <link rel="stylesheet" href="../css/webglbook.css" /> 
      7     <script src="Three.js"></script>
      8     <script src="webgl-utils.js"></script>
      9     <script>
     10     
     11     var renderer = null, 
     12         scene = null, 
     13         camera = null,
     14         cube = null,
     15         animating = false;
     16     
     17     function onLoad()
     18     {
     19         // Grab our container div
     20         //取得作为容器的div,事实上容器不局限于div标签
     21         var container = document.getElementById("container");
     22 
     23         // Create the Three.js renderer, add it to our div
     24         //建立Three.js渲染器,并把它加入容器div中
     25         renderer = new THREE.WebGLRenderer( { antialias: true } );
     26         renderer.setSize(container.offsetWidth, container.offsetHeight);
     27         container.appendChild( renderer.domElement );
     28 
     29         // Create a new Three.js scene
     30         //建立一个Three.js场景
     31         scene = new THREE.Scene();
     32 
     33         // Put in a camera
     34         //引入一个相机
     35         camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 4000 );
     36         camera.position.set( 0, 0, 3 );
     37 
     38         // Create a directional light to show off the object
     39         //建立一个方向光来照亮场景中的物体
     40         var light = new THREE.DirectionalLight( 0xffffff, 1.5);
     41         light.position.set(0, 0, 1);
     42         scene.add( light );
     43 
     44         // Create a shaded, texture-mapped cube and add it to the scene
     45         //建立一个具有阴影效果和纹理效果的立方体,并把它加入到场景中
     46         // First, create the texture map
     47         //第一步,建立纹理图片(Three.js不要求图片尺寸是2的整数次方)
     48         var mapUrl = "molumen_small_funny_angry_monster.jpg";
     49         var map = THREE.ImageUtils.loadTexture(mapUrl);
     50         
     51         // Now, create a Phong material to show shading; pass in the map
     52         //建立一个Phong类型的材质对象来表现光照和阴影;把这个材质传入纹理图中
     53         var material = new THREE.MeshPhongMaterial({ map: map });
     54 
     55         // Create the cube geometry
     56         //建立一个默认的几何体
     57         var geometry = new THREE.CubeGeometry(1, 1, 1);
     58 
     59         // And put the geometry and material together into a mesh
     60         //把“多边形”和“材质”组合成一个“网格”
     61         cube = new THREE.Mesh(geometry, material);
     62 
     63         // Turn it toward the scene, or we won't see the cube shape!
     64         //稍微旋转一下物体,否则我们看不出立体的效果!
     65         cube.rotation.x = Math.PI / 5;
     66         cube.rotation.y = Math.PI / 5;
     67 
     68         // Add the cube to our scene
     69         //把物体加入到场景中
     70         scene.add( cube );
     71 
     72         // Add a mouse up handler to toggle the animation
     73         //添加鼠标监听
     74         addMouseHandler();
     75 
     76         // Run our render loop
     77         //启动渲染循环
     78         run();
     79     }
     80 
     81     function run()
     82     {
     83         // Render the scene
     84         //渲染场景,renderer是canvas的绘制上下文,scene是变量映射接口,camera是姿态矩阵和投影矩阵的结合
     85         renderer.render( scene, camera );
     86 
     87         // Spin the cube for next frame
     88         //旋转物体生成下一帧画面
     89         if (animating)
     90         {
     91             cube.rotation.y -= 0.01;
     92         }
     93             
     94         // Ask for another frame
     95         //请求下一帧(循环)
     96         requestAnimFrame(run);    
     97     }
     98 
     99     function addMouseHandler()
    100     {
    101         var dom = renderer.domElement;
    102         
    103         dom.addEventListener( 'mouseup', onMouseUp, false);
    104     }
    105     
    106     function onMouseUp    (event)
    107     {
    108         event.preventDefault();
    109 
    110         animating = !animating;
    111     }    
    112     
    113     </script>
    114 
    115 </head>
    116 <body onLoad="onLoad();" style="">
    117     <center><h1>Welcome to WebGL!</h1></center>
    118     <div id="container" style="95%; height:80%; position:absolute;"></div>
    119     <div id="prompt" style="95%; height:6%; bottom:0; text-align:center; position:absolute;">Click to animate the cube</div>
    120 
    121 </body>
    122 </html>

     

  • 相关阅读:
    MOSS的CSS样式说明
    RSS 简介(一)
    母版页详细分析
    导出 WINDOWS\assembly中DLL文件
    文件下载代码
    列表Field属性的巧妙运用(隐藏栏)
    javascript弹出窗口总结
    转[VBA起步]常用的、带解释的 VBA 短句
    如何生成自定义列表
    mysql 连接字符串与SQL不同
  • 原文地址:https://www.cnblogs.com/smedas/p/12449206.html
Copyright © 2011-2022 走看看