前提条件和预期结果

目前只有少数的浏览器支持 WebGL ,请看我的另外一篇文章:Can I use WebGL?.

下面的例子是在 Windows 下的 Chrome 16/23 以及 Android 下的 Firefox 17 进行测试。如果你使用的是非兼容浏览器访问则会弹出一个警告。 
在支持HTML5的浏览器上运行WebGL程序的方法

 图1:包含 Hello world 文本的动画的 WebGL 立方体
在兼容 HTML5 的浏览器上,你将会看到如下图所示的带动画效果的立方体:
在支持HTML5的浏览器上运行WebGL程序的方法

 图2: 示例运行的屏幕截图


该代码基于 Lighting in WebGL - How to simulate lighting effects in your WebGL context - 非常感谢这篇教程。在该实例初始运行时,动画的立方体是通过一个静态的 Bitmap 图形对象渲染的。

下面的代码演示如何在程序中动态的渲染文本:

XML/HTML Code复制内容到剪贴板
  1. // TODO #1 New method to create a texture   
  2. function createCubeTexture(text) {   
  3.     ...   
  4. }  

在这里使用 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); 是非常重要的,用来确保写文本时不会前后颠倒。剩下的就很容易理解了:

XML/HTML Code复制内容到剪贴板
  1. // TODO #2 Assign the created texture for display   
  2. cubeTexture = createCubeTexture("Hello World!");  

源码

// File #1: webgl-demo.htm

XML/HTML Code复制内容到剪贴板
  1. <html>  
  2.   <head>  
  3.     <title>WebGL - Hello World!</title>  
  4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  5.     <script src="sylvester.js" type="text/javascript"></script>  
  6.     <script src="glUtils.js" type="text/javascript"></script>  
  7.     <script src="webgl-demo.js" type="text/javascript"></script>  
  8.         
  9.     <!-- Fragment shader program -->  
  10.     <script id="shader-fs" type="x-shader/x-fragment">  
  11.       varying highp vec2 vTextureCoord;   
  12.       varying highp vec3 vLighting;   
  13.           
  14.       uniform sampler2D uSampler;   
  15.           
  16.       void main(void) {   
  17.         highp vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));   
  18.             
  19.         gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);   
  20.       }   
  21.     </script>  
  22.         
  23.     <!-- Vertex shader program -->  
  24.     <script id="shader-vs" type="x-shader/x-vertex">  
  25.       attribute highp vec3 aVertexNormal;   
  26.       attribute highp vec3 aVertexPosition;   
  27.       attribute highp vec2 aTextureCoord;   
  28.         
  29.       uniform highp mat4 uNormalMatrix;   
  30.       uniform highp mat4 uMVMatrix;   
  31.       uniform highp mat4 uPMatrix;   
  32.           
  33.       varying highp vec2 vTextureCoord;   
  34.       varying highp vec3 vLighting;   
  35.         
  36.       void main(void) {   
  37.         gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);   
  38.         vTextureCoord = aTextureCoord;   
  39.             
  40.         // Apply lighting effect   
  41.             
  42.         highp vec3 ambientLight = vec3(0.6, 0.6, 0.6);   
  43.         highp vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);   
  44.         highp vec3 directionalVector = vec3(0.85, 0.8, 0.75);   
  45.         highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);   
  46.        
  47.         highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);   
  48.         vLighting = ambientLight + (directionalLightColor * directional);   
  49.       }   
  50.     </script>  
  51.   </head>        
  52.       
  53.   <body onload="start()">  
  54.     <canvas id="glcanvas" width="640" height="480">  
  55.       Your browser doesn't appear to support the HTML5 <code><canvas></code> element.   
  56.     </canvas>  
  57.   </body>  
  58. </html>  

// File #02: webgl-demo.js

XML/HTML Code复制内容到剪贴板
  1. var canvas;   
  2. var gl;   
  3.     
  4. var cubeVerticesBuffer;   
  5. var cubeVerticesTextureCoordBuffer;   
  6. var cubeVerticesIndexBuffer;   
  7. var cubeVerticesIndexBuffer;   
  8. var cubeRotation = 0.0;   
  9. var lastCubeUpdateTime = 0;   
  10.     
  11. var cubeImage;   
  12. var cubeTexture;   
  13.     
  14. var mvMatrix;   
  15. var shaderProgram;   
  16. var vertexPositionAttribute;   
  17. var vertexNormalAttribute;   
  18. var textureCoordAttribute;   
  19. var perspectiveMatrix;   
  20.     
  21. //   
  22. // start   
  23. //   
  24. // Called when the canvas is created to get the ball rolling.   
  25. //   
  26. function start() {   
  27.   canvas = document.getElementById("glcanvas");   
  28.     
  29.   initWebGL(canvas);      // Initialize the GL context   
  30.       
  31.   // Only continue if WebGL is available and working   
  32.       
  33.   if (gl) {   
  34.     gl.clearColor(0.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque   
  35.     gl.clearDepth(1.0);                 // Clear everything   
  36.     gl.enable(gl.DEPTH_TEST);           // Enable depth testing   
  37.     gl.depthFunc(gl.LEQUAL);            // Near things obscure far things   
  38.         
  39.     // Initialize the shaders; this is where all the lighting for the   
  40.     // vertices and so forth is established.   
  41.         
  42.     initShaders();   
  43.         
  44.     // Here's where we call the routine that builds all the objects   
  45.     // we'll be drawing.   
  46.         
  47.     initBuffers();   
  48.         
  49.     // Next, load and set up the textures we'll be using.   
  50.         
  51.     // TODO#2 Start   
  52.     cubeTexture = createCubeTexture("Hello World!");   
  53.     // TODO#2 End   
  54.         
  55.     // Set up to draw the scene periodically.   
  56.         
  57.     setInterval(drawScene, 15);   
  58.   }   
  59. }   
  60.     
  61. //   
  62. // initWebGL   
  63. //   
  64. // Initialize WebGL, returning the GL context or null if   
  65. // WebGL isn't available or could not be initialized.   
  66. //   
  67. function initWebGL() {   
  68.   gl = null;   
  69.       
  70.   try {   
  71.     gl = canvas.getContext("experimental-webgl");   
  72.   }   
  73.   catch(e) {   
  74.   }   
  75.       
  76.   // If we don't have a GL context, give up now   
  77.       
  78.   if (!gl) {   
  79.     alert("Unable to initialize WebGL. Your browser may not support it.");   
  80.   }   
  81. }   
  82.     
  83. //   
  84. // initBuffers   
  85. //   
  86. // Initialize the buffers we'll need. For this demo, we just have   
  87. // one object -- a simple two-dimensional cube.   
  88. //   
  89. function initBuffers() {   
  90.       
  91.   // Create a buffer for the cube's vertices.   
  92.       
  93.   cubeVerticesBuffer = gl.createBuffer();   
  94.       
  95.   // Select the cubeVerticesBuffer as the one to apply vertex   
  96.   // operations to from here out.   
  97.       
  98.   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);   
  99.       
  100.   // Now create an array of vertices for the cube.   
  101.       
  102.   var vertices = [   
  103.     // Front face   
  104.     -1.0, -1.0,  1.0,   
  105.      1.0, -1.0,  1.0,   
  106.      1.0,  1.0,  1.0,   
  107.     -1.0,  1.0,  1.0,   
  108.         
  109.     // Back face   
  110.     -1.0, -1.0, -1.0,   
  111.     -1.0,  1.0, -1.0,   
  112.      1.0,  1.0, -1.0,   
  113.      1.0, -1.0, -1.0,   
  114.         
  115.     // Top face   
  116.     -1.0,  1.0, -1.0,   
  117.     -1.0,  1.0,  1.0,   
  118.      1.0,  1.0,  1.0,   
  119.      1.0,  1.0, -1.0,   
  120.         
  121.     // Bottom face   
  122.     -1.0, -1.0, -1.0,   
  123.      1.0, -1.0, -1.0,   
  124.      1.0, -1.0,  1.0,   
  125.     -1.0, -1.0,  1.0,   
  126.         
  127.     // Right face   
  128.      1.0, -1.0, -1.0,   
  129.      1.0,  1.0, -1.0,   
  130.      1.0,  1.0,  1.0,   
  131.      1.0, -1.0,  1.0,   
  132.         
  133.     // Left face   
  134.     -1.0, -1.0, -1.0,   
  135.     -1.0, -1.0,  1.0,   
  136.     -1.0,  1.0,  1.0,   
  137.     -1.0,  1.0, -1.0   
  138.   ];   
  139.       
  140.   // Now pass the list of vertices into WebGL to build the shape. We   
  141.   // do this by creating a Float32Array from the JavaScript array,   
  142.   // then use it to fill the current vertex buffer.   
  143.       
  144.   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);   
  145.     
  146.   // Set up the normals for the vertices, so that we can compute lighting.   
  147.       
  148.   cubeVerticesNormalBuffer = gl.createBuffer();   
  149.   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);   
  150.       
  151.   var vertexNormals = [   
  152.     // Front   
  153.      0.0,  0.0,  1.0,   
  154.      0.0,  0.0,  1.0,   
  155.      0.0,  0.0,  1.0,   
  156.      0.0,  0.0,  1.0,   
  157.         
  158.     // Back   
  159.      0.0,  0.0, -1.0,   
  160.      0.0,  0.0, -1.0,   
  161.      0.0,  0.0, -1.0,   
  162.      0.0,  0.0, -1.0,   
  163.         
  164.     // Top   
  165.      0.0,  1.0,  0.0,   
  166.      0.0,  1.0,  0.0,   
  167.      0.0,  1.0,  0.0,   
  168.      0.0,  1.0,  0.0,   
  169.         
  170.     // Bottom   
  171.      0.0, -1.0,  0.0,   
  172.      0.0, -1.0,  0.0,   
  173.      0.0, -1.0,  0.0,   
  174.      0.0, -1.0,  0.0,   
  175.         
  176.     // Right   
  177.      1.0,  0.0,  0.0,   
  178.      1.0,  0.0,  0.0,   
  179.      1.0,  0.0,  0.0,   
  180.      1.0,  0.0,  0.0,   
  181.         
  182.     // Left   
  183.     -1.0,  0.0,  0.0,   
  184.     -1.0,  0.0,  0.0,   
  185.     -1.0,  0.0,  0.0,   
  186.     -1.0,  0.0,  0.0   
  187.   ];   
  188.       
  189.   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals),   
  190.                 gl.STATIC_DRAW);   
  191.       
  192.   // Map the texture onto the cube's faces.   
  193.       
  194.   cubeVerticesTextureCoordBuffer = gl.createBuffer();   
  195.   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);   
  196.       
  197.   var textureCoordinates = [   
  198.     // Front   
  199.     0.0,  0.0,   
  200.     1.0,  0.0,   
  201.     1.0,  1.0,   
  202.     0.0,  1.0,   
  203.     // Back   
  204.     0.0,  0.0,   
  205.     1.0,  0.0,   
  206.     1.0,  1.0,   
  207.     0.0,  1.0,   
  208.     // Top   
  209.     0.0,  0.0,   
  210.     1.0,  0.0,   
  211.     1.0,  1.0,   
  212.     0.0,  1.0,   
  213.     // Bottom   
  214.     0.0,  0.0,   
  215.     1.0,  0.0,   
  216.     1.0,  1.0,   
  217.     0.0,  1.0,   
  218.     // Right   
  219.     0.0,  0.0,   
  220.     1.0,  0.0,   
  221.     1.0,  1.0,   
  222.     0.0,  1.0,   
  223.     // Left   
  224.     0.0,  0.0,   
  225.     1.0,  0.0,   
  226.     1.0,  1.0,   
  227.     0.0,  1.0   
  228.   ];   
  229.     
  230.   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),   
  231.                 gl.STATIC_DRAW);   
  232.     
  233.   // Build the element array buffer; this specifies the indices   
  234.   // into the vertex array for each face's vertices.   
  235.       
  236.   cubeVerticesIndexBuffer = gl.createBuffer();   
  237.   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);   
  238.       
  239.   // This array defines each face as two triangles, using the   
  240.   // indices into the vertex array to specify each triangle's   
  241.   // position.   
  242.       
  243.   var cubeVertexIndices = [   
  244.     0,  1,  2,      0,  2,  3,    // front   
  245.     4,  5,  6,      4,  6,  7,    // back   
  246.     8,  9,  10,     8,  10, 11,   // top   
  247.     12, 13, 14,     12, 14, 15,   // bottom   
  248.     16, 17, 18,     16, 18, 19,   // right   
  249.     20, 21, 22,     20, 22, 23    // left   
  250.   ]   
  251.       
  252.   // Now send the element array to GL   
  253.       
  254.   gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,   
  255.       new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);   
  256. }   
  257.     
  258. //   
  259. // initTextures   
  260. //   
  261. // Initialize the textures we'll be using, then initiate a load of   
  262. // the texture images. The handleTextureLoaded() callback will finish   
  263. // the job; it gets called each time a texture finishes loading.   
  264. //   
  265. // TODO#1 Start   
  266. function createCubeTexture(text) {   
  267.                     
  268.     // create a hidden canvas to draw the texture   
  269.     var canvas = document.createElement('canvas');   
  270.     canvas.id     = "hiddenCanvas";   
  271.     canvas.width  = 512;   
  272.     canvas.height = 512;   
  273.     canvas.style.display   = "none";   
  274.     var body = document.getElementsByTagName("body")[0];   
  275.     body.appendChild(canvas);          
  276.     
  277.     // draw texture   
  278.     var cubeImage = document.getElementById('hiddenCanvas');   
  279.     var ctx = cubeImage.getContext('2d');   
  280.     ctx.beginPath();   
  281.     ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);              
  282.     ctx.fillStyle = 'white';   
  283.     ctx.fill();   
  284.     ctx.fillStyle = 'black';   
  285.     ctx.font = "65px Arial";   
  286.     ctx.textAlign = 'center';              
  287.     ctx.fillText(text, ctx.canvas.width / 2, ctx.canvas.height / 2);   
  288.     ctx.restore();          
  289.     
  290.     // create new texture   
  291.     var texture = gl.createTexture();   
  292.     gl.bindTexture(gl.TEXTURE_2D, texture);   
  293.     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);   
  294.     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);   
  295.     gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);   
  296.     handleTextureLoaded(cubeImage, texture)   
  297.         
  298.     return texture;   
  299. }   
  300. // TODO#1 End   
  301.      
  302. function handleTextureLoaded(image, texture) {   
  303.   gl.bindTexture(gl.TEXTURE_2D, texture);   
  304.   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);   
  305.   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);   
  306.   gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);   
  307.   gl.generateMipmap(gl.TEXTURE_2D);   
  308.   gl.bindTexture(gl.TEXTURE_2D, null);   
  309. }   
  310.     
  311. //   
  312. // drawScene   
  313. //   
  314. // Draw the scene.   
  315. //   
  316. function drawScene() {   
  317.   // Clear the canvas before we start drawing on it.   
  318.     
  319.   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);   
  320.       
  321.   // Establish the perspective with which we want to view the   
  322.   // scene. Our field of view is 45 degrees, with a width/height   
  323.   // ratio of 640:480, and we only want to see objects between 0.1 units   
  324.   // and 100 units away from the camera.   
  325.       
  326.   perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0);   
  327.       
  328.   // Set the drawing position to the "identity" point, which is   
  329.   // the center of the scene.   
  330.       
  331.   loadIdentity();   
  332.       
  333.   // Now move the drawing position a bit to where we want to start   
  334.   // drawing the cube.   
  335.       
  336.   mvTranslate([0.0, 0.0, -6.0]);   
  337.       
  338.   // Save the current matrix, then rotate before we draw.   
  339.       
  340.   mvPushMatrix();   
  341.   mvRotate(cubeRotation, [1, 0, 1]);   
  342.       
  343.   // Draw the cube by binding the array buffer to the cube's vertices   
  344.   // array, setting attributes, and pushing it to GL.   
  345.       
  346.   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);   
  347.   gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);   
  348.       
  349.   // Set the texture coordinates attribute for the vertices.   
  350.       
  351.   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);   
  352.   gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);   
  353.       
  354.   // Bind the normals buffer to the shader attribute.   
  355.       
  356.   gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);   
  357.   gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);   
  358.       
  359.   // Specify the texture to map onto the faces.   
  360.       
  361.   gl.activeTexture(gl.TEXTURE0);   
  362.   gl.bindTexture(gl.TEXTURE_2D, cubeTexture);   
  363.   gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);   
  364.       
  365.   // Draw the cube.   
  366.       
  367.   gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);   
  368.   setMatrixUniforms();   
  369.   gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);   
  370.       
  371.   // Restore the original matrix   
  372.       
  373.   mvPopMatrix();   
  374.       
  375.   // Update the rotation for the next draw, if it's time to do so.   
  376.       
  377.   var currentTime = (new Date).getTime();   
  378.   if (lastCubeUpdateTime) {   
  379.     var delta = currentTime - lastCubeUpdateTime;   
  380.         
  381.     cubeRotation += (30 * delta) / 1000.0;   
  382.   }   
  383.       
  384.   lastCubeUpdateTime = currentTime;   
  385. }   
  386.     
  387. //   
  388. // initShaders   
  389. //   
  390. // Initialize the shaders, so WebGL knows how to light our scene.   
  391. //   
  392. function initShaders() {   
  393.   var fragmentShader = getShader(gl, "shader-fs");   
  394.   var vertexShader = getShader(gl, "shader-vs");   
  395.       
  396.   // Create the shader program   
  397.       
  398.   shaderProgram = gl.createProgram();   
  399.   gl.attachShader(shaderProgram, vertexShader);   
  400.   gl.attachShader(shaderProgram, fragmentShader);   
  401.   gl.linkProgram(shaderProgram);   
  402.       
  403.   // If creating the shader program failed, alert   
  404.       
  405.   if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {   
  406.     alert("Unable to initialize the shader program.");   
  407.   }   
  408.       
  409.   gl.useProgram(shaderProgram);   
  410.       
  411.   vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");   
  412.   gl.enableVertexAttribArray(vertexPositionAttribute);   
  413.       
  414.   textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");   
  415.   gl.enableVertexAttribArray(textureCoordAttribute);   
  416.       
  417.   vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");   
  418.   gl.enableVertexAttribArray(vertexNormalAttribute);   
  419. }   
  420.     
  421. //   
  422. // getShader   
  423. //   
  424. // Loads a shader program by scouring the current document,   
  425. // looking for a script with the specified ID.   
  426. //   
  427. function getShader(gl, id) {   
  428.   var shaderScript = document.getElementById(id);   
  429.       
  430.   // Didn't find an element with the specified ID; abort.   
  431.       
  432.   if (!shaderScript) {   
  433.     return null;   
  434.   }   
  435.       
  436.   // Walk through the source element's children, building the   
  437.   // shader source string.   
  438.       
  439.   var theSource = "";   
  440.   var currentChild = shaderScript.firstChild;   
  441.       
  442.   while(currentChild) {   
  443.     if (currentChild.nodeType == 3) {   
  444.       theSource += currentChild.textContent;   
  445.     }   
  446.         
  447.     currentChildcurrentChild = currentChild.nextSibling;   
  448.   }   
  449.       
  450.   // Now figure out what type of shader script we have,   
  451.   // based on its MIME type.   
  452.       
  453.   var shader;   
  454.       
  455.   if (shaderScript.type == "x-shader/x-fragment") {   
  456.     shader = gl.createShader(gl.FRAGMENT_SHADER);   
  457.   } else if (shaderScript.type == "x-shader/x-vertex") {   
  458.     shader = gl.createShader(gl.VERTEX_SHADER);   
  459.   } else {   
  460.     return null;  // Unknown shader type   
  461.   }   
  462.       
  463.   // Send the source to the shader object   
  464.       
  465.   gl.shaderSource(shader, theSource);   
  466.       
  467.   // Compile the shader program   
  468.       
  469.   gl.compileShader(shader);   
  470.       
  471.   // See if it compiled successfully   
  472.       
  473.   if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {   
  474.     alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));   
  475.     return null;   
  476.   }   
  477.       
  478.   return shader;   
  479. }   
  480.     
  481. //   
  482. // Matrix utility functions   
  483. //   
  484.     
  485. function loadIdentity() {   
  486.   mvMatrix = Matrix.I(4);   
  487. }   
  488.     
  489. function multMatrix(m) {   
  490.   mvMatrixmvMatrix = mvMatrix.x(m);   
  491. }   
  492.     
  493. function mvTranslate(v) {   
  494.   multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());   
  495. }   
  496.     
  497. function setMatrixUniforms() {   
  498.   var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");   
  499.   gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten()));   
  500.     
  501.   var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");   
  502.   gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));   
  503.       
  504.   var normalMatrix = mvMatrix.inverse();   
  505.   normalMatrixnormalMatrix = normalMatrix.transpose();   
  506.   var nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");   
  507.   gl.uniformMatrix4fv(nUniform, false, new Float32Array(normalMatrix.flatten()));   
  508. }   
  509.     
  510. var mvMatrixStack = [];   
  511.     
  512. function mvPushMatrix(m) {   
  513.   if (m) {   
  514.     mvMatrixStack.push(m.dup());   
  515.     mmvMatrix = m.dup();   
  516.   } else {   
  517.     mvMatrixStack.push(mvMatrix.dup());   
  518.   }   
  519. }   
  520.     
  521. function mvPopMatrix() {   
  522.   if (!mvMatrixStack.length) {   
  523.     throw("Can't pop from an empty matrix stack.");   
  524.   }   
  525.       
  526.   mvMatrix = mvMatrixStack.pop();   
  527.   return mvMatrix;   
  528. }   
  529.     
  530. function mvRotate(angle, v) {   
  531.   var inRadians = angle * Math.PI / 180.0;   
  532.       
  533.   var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();   
  534.   multMatrix(m);   
  535. }  
标签:
浏览器,WebGL

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
千金楼资源网 Copyright www.htabc.com

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?