千家信息网

如何在HTML5的浏览器上运行WebGL程序

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,本篇内容主要讲解"如何在HTML5的浏览器上运行WebGL程序",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何在HTML5的浏览器上运行WebGL程序"
千家信息网最后更新 2025年01月19日如何在HTML5的浏览器上运行WebGL程序

本篇内容主要讲解"如何在HTML5的浏览器上运行WebGL程序",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何在HTML5的浏览器上运行WebGL程序"吧!

前提条件和预期结果

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

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

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

图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. <script id="shader-fs" type="x-shader/x-fragment">

  9. varying highp vec2 vTextureCoord;

  10. varying highp vec3 vLighting;

  11. uniform sampler2D uSampler;

  12. void main(void) {

  13. highp vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));

  14. gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);

  15. }

  16. script>

  17. <script id="shader-vs" type="x-shader/x-vertex">

  18. attribute highp vec3 aVertexNormal;

  19. attribute highp vec3 aVertexPosition;

  20. attribute highp vec2 aTextureCoord;

  21. uniform highp mat4 uNormalMatrix;

  22. uniform highp mat4 uMVMatrix;

  23. uniform highp mat4 uPMatrix;

  24. varying highp vec2 vTextureCoord;

  25. varying highp vec3 vLighting;

  26. void main(void) {

  27. gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);

  28. vTextureCoord = aTextureCoord;

  29. // Apply lighting effect

  30. highp vec3 ambientLight = vec3(0.6, 0.6, 0.6);

  31. highp vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);

  32. highp vec3 directionalVector = vec3(0.85, 0.8, 0.75);

  33. highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);

  34. highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);

  35. vLighting = ambientLight + (directionalLightColor * directional);

  36. }

  37. script>

  38. head>

  39. <body onload="start()">

  40. <canvas id="glcanvas" width="640" height="480">

  41. Your browser doesn't appear to support the HTML5 <code><canvas>code> element.

  42. canvas>

  43. body>

  44. html>

// File #02: webgl-demo.js

XML/HTML Code复制内容到剪贴板

  1. var canvas;

  2. var gl;

  3. var cubeVerticesBuffer;

  4. var cubeVerticesTextureCoordBuffer;

  5. var cubeVerticesIndexBuffer;

  6. var cubeVerticesIndexBuffer;

  7. var cubeRotation = 0.0;

  8. var lastCubeUpdateTime = 0;

  9. var cubeImage;

  10. var cubeTexture;

  11. var mvMatrix;

  12. var shaderProgram;

  13. var vertexPositionAttribute;

  14. var vertexNormalAttribute;

  15. var textureCoordAttribute;

  16. var perspectiveMatrix;

  17. //

  18. // start

  19. //

  20. // Called when the canvas is created to get the ball rolling.

  21. //

  22. function start() {

  23. canvas = document.getElementById("glcanvas");

  24. initWebGL(canvas); // Initialize the GL context

  25. // Only continue if WebGL is available and working

  26. if (gl) {

  27. gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque

  28. gl.clearDepth(1.0); // Clear everything

  29. gl.enable(gl.DEPTH_TEST); // Enable depth testing

  30. gl.depthFunc(gl.LEQUAL); // Near things obscure far things

  31. // Initialize the shaders; this is where all the lighting for the

  32. // vertices and so forth is established.

  33. initShaders();

  34. // Here's where we call the routine that builds all the objects

  35. // we'll be drawing.

  36. initBuffers();

  37. // Next, load and set up the textures we'll be using.

  38. // TODO#2 Start

  39. cubeTexture = createCubeTexture("Hello World!");

  40. // TODO#2 End

  41. // Set up to draw the scene periodically.

  42. setInterval(drawScene, 15);

  43. }

  44. }

  45. //

  46. // initWebGL

  47. //

  48. // Initialize WebGL, returning the GL context or null if

  49. // WebGL isn't available or could not be initialized.

  50. //

  51. function initWebGL() {

  52. gl = null;

  53. try {

  54. gl = canvas.getContext("experimental-webgl");

  55. }

  56. catch(e) {

  57. }

  58. // If we don't have a GL context, give up now

  59. if (!gl) {

  60. alert("Unable to initialize WebGL. Your browser may not support it.");

  61. }

  62. }

  63. //

  64. // initBuffers

  65. //

  66. // Initialize the buffers we'll need. For this demo, we just have

  67. // one object -- a simple two-dimensional cube.

  68. //

  69. function initBuffers() {

  70. // Create a buffer for the cube's vertices.

  71. cubeVerticesBuffer = gl.createBuffer();

  72. // Select the cubeVerticesBuffer as the one to apply vertex

  73. // operations to from here out.

  74. gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);

  75. // Now create an array of vertices for the cube.

  76. var vertices = [

  77. // Front face

  78. -1.0, -1.0, 1.0,

  79. 1.0, -1.0, 1.0,

  80. 1.0, 1.0, 1.0,

  81. -1.0, 1.0, 1.0,

  82. // Back face

  83. -1.0, -1.0, -1.0,

  84. -1.0, 1.0, -1.0,

  85. 1.0, 1.0, -1.0,

  86. 1.0, -1.0, -1.0,

  87. // Top face

  88. -1.0, 1.0, -1.0,

  89. -1.0, 1.0, 1.0,

  90. 1.0, 1.0, 1.0,

  91. 1.0, 1.0, -1.0,

  92. // Bottom face

  93. -1.0, -1.0, -1.0,

  94. 1.0, -1.0, -1.0,

  95. 1.0, -1.0, 1.0,

  96. -1.0, -1.0, 1.0,

  97. // Right face

  98. 1.0, -1.0, -1.0,

  99. 1.0, 1.0, -1.0,

  100. 1.0, 1.0, 1.0,

  101. 1.0, -1.0, 1.0,

  102. // Left face

  103. -1.0, -1.0, -1.0,

  104. -1.0, -1.0, 1.0,

  105. -1.0, 1.0, 1.0,

  106. -1.0, 1.0, -1.0

  107. ];

  108. // Now pass the list of vertices into WebGL to build the shape. We

  109. // do this by creating a Float32Array from the JavaScript array,

  110. // then use it to fill the current vertex buffer.

  111. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

  112. // Set up the normals for the vertices, so that we can compute lighting.

  113. cubeVerticesNormalBuffer = gl.createBuffer();

  114. gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);

  115. var vertexNormals = [

  116. // Front

  117. 0.0, 0.0, 1.0,

  118. 0.0, 0.0, 1.0,

  119. 0.0, 0.0, 1.0,

  120. 0.0, 0.0, 1.0,

  121. // Back

  122. 0.0, 0.0, -1.0,

  123. 0.0, 0.0, -1.0,

  124. 0.0, 0.0, -1.0,

  125. 0.0, 0.0, -1.0,

  126. // Top

  127. 0.0, 1.0, 0.0,

  128. 0.0, 1.0, 0.0,

  129. 0.0, 1.0, 0.0,

  130. 0.0, 1.0, 0.0,

  131. // Bottom

  132. 0.0, -1.0, 0.0,

  133. 0.0, -1.0, 0.0,

  134. 0.0, -1.0, 0.0,

  135. 0.0, -1.0, 0.0,

  136. // Right

  137. 1.0, 0.0, 0.0,

  138. 1.0, 0.0, 0.0,

  139. 1.0, 0.0, 0.0,

  140. 1.0, 0.0, 0.0,

  141. // Left

  142. -1.0, 0.0, 0.0,

  143. -1.0, 0.0, 0.0,

  144. -1.0, 0.0, 0.0,

  145. -1.0, 0.0, 0.0

  146. ];

  147. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals),

  148. gl.STATIC_DRAW);

  149. // Map the texture onto the cube's faces.

  150. cubeVerticesTextureCoordBuffer = gl.createBuffer();

  151. gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);

  152. var textureCoordinates = [

  153. // Front

  154. 0.0, 0.0,

  155. 1.0, 0.0,

  156. 1.0, 1.0,

  157. 0.0, 1.0,

  158. // Back

  159. 0.0, 0.0,

  160. 1.0, 0.0,

  161. 1.0, 1.0,

  162. 0.0, 1.0,

  163. // Top

  164. 0.0, 0.0,

  165. 1.0, 0.0,

  166. 1.0, 1.0,

  167. 0.0, 1.0,

  168. // Bottom

  169. 0.0, 0.0,

  170. 1.0, 0.0,

  171. 1.0, 1.0,

  172. 0.0, 1.0,

  173. // Right

  174. 0.0, 0.0,

  175. 1.0, 0.0,

  176. 1.0, 1.0,

  177. 0.0, 1.0,

  178. // Left

  179. 0.0, 0.0,

  180. 1.0, 0.0,

  181. 1.0, 1.0,

  182. 0.0, 1.0

  183. ];

  184. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),

  185. gl.STATIC_DRAW);

  186. // Build the element array buffer; this specifies the indices

  187. // into the vertex array for each face's vertices.

  188. cubeVerticesIndexBuffer = gl.createBuffer();

  189. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);

  190. // This array defines each face as two triangles, using the

  191. // indices into the vertex array to specify each triangle's

  192. // position.

  193. var cubeVertexIndices = [

  194. 0, 1, 2, 0, 2, 3, // front

  195. 4, 5, 6, 4, 6, 7, // back

  196. 8, 9, 10, 8, 10, 11, // top

  197. 12, 13, 14, 12, 14, 15, // bottom

  198. 16, 17, 18, 16, 18, 19, // right

  199. 20, 21, 22, 20, 22, 23 // left

  200. ]

  201. // Now send the element array to GL

  202. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,

  203. new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);

  204. }

  205. //

  206. // initTextures

  207. //

  208. // Initialize the textures we'll be using, then initiate a load of

  209. // the texture images. The handleTextureLoaded() callback will finish

  210. // the job; it gets called each time a texture finishes loading.

  211. //

  212. // TODO#1 Start

  213. function createCubeTexture(text) {

  214. // create a hidden canvas to draw the texture

  215. var canvas = document.createElement('canvas');

  216. canvas.id = "hiddenCanvas";

  217. canvas.width = 512;

  218. canvas.height = 512;

  219. canvas.style.display = "none";

  220. var body = document.getElementsByTagName("body")[0];

  221. body.appendChild(canvas);

  222. // draw texture

  223. var cubeImage = document.getElementById('hiddenCanvas');

  224. var ctx = cubeImage.getContext('2d');

  225. ctx.beginPath();

  226. ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);

  227. ctx.fillStyle = 'white';

  228. ctx.fill();

  229. ctx.fillStyle = 'black';

  230. ctx.font = "65px Arial";

  231. ctx.textAlign = 'center';

  232. ctx.fillText(text, ctx.canvas.width / 2, ctx.canvas.height / 2);

  233. ctx.restore();

  234. // create new texture

  235. var texture = gl.createTexture();

  236. gl.bindTexture(gl.TEXTURE_2D, texture);

  237. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

  238. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);

  239. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

  240. handleTextureLoaded(cubeImage, texture)

  241. return texture;

  242. }

  243. // TODO#1 End

  244. function handleTextureLoaded(image, texture) {

  245. gl.bindTexture(gl.TEXTURE_2D, texture);

  246. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

  247. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

  248. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);

  249. gl.generateMipmap(gl.TEXTURE_2D);

  250. gl.bindTexture(gl.TEXTURE_2D, null);

  251. }

  252. //

  253. // drawScene

  254. //

  255. // Draw the scene.

  256. //

  257. function drawScene() {

  258. // Clear the canvas before we start drawing on it.

  259. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  260. // Establish the perspective with which we want to view the

  261. // scene. Our field of view is 45 degrees, with a width/height

  262. // ratio of 640:480, and we only want to see objects between 0.1 units

  263. // and 100 units away from the camera.

  264. perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0);

  265. // Set the drawing position to the "identity" point, which is

  266. // the center of the scene.

  267. loadIdentity();

  268. // Now move the drawing position a bit to where we want to start

  269. // drawing the cube.

  270. mvTranslate([0.0, 0.0, -6.0]);

  271. // Save the current matrix, then rotate before we draw.

  272. mvPushMatrix();

  273. mvRotate(cubeRotation, [1, 0, 1]);

  274. // Draw the cube by binding the array buffer to the cube's vertices

  275. // array, setting attributes, and pushing it to GL.

  276. gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);

  277. gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

  278. // Set the texture coordinates attribute for the vertices.

  279. gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);

  280. gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);

  281. // Bind the normals buffer to the shader attribute.

  282. gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);

  283. gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);

  284. // Specify the texture to map onto the faces.

  285. gl.activeTexture(gl.TEXTURE0);

  286. gl.bindTexture(gl.TEXTURE_2D, cubeTexture);

  287. gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);

  288. // Draw the cube.

  289. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);

  290. setMatrixUniforms();

  291. gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

  292. // Restore the original matrix

  293. mvPopMatrix();

  294. // Update the rotation for the next draw, if it's time to do so.

  295. var currentTime = (new Date).getTime();

  296. if (lastCubeUpdateTime) {

  297. var delta = currentTime - lastCubeUpdateTime;

  298. cubeRotation += (30 * delta) / 1000.0;

  299. }

  300. lastCubeUpdateTime = currentTime;

  301. }

  302. //

  303. // initShaders

  304. //

  305. // Initialize the shaders, so WebGL knows how to light our scene.

  306. //

  307. function initShaders() {

  308. var fragmentShader = getShader(gl, "shader-fs");

  309. var vertexShader = getShader(gl, "shader-vs");

  310. // Create the shader program

  311. shaderProgram = gl.createProgram();

  312. gl.attachShader(shaderProgram, vertexShader);

  313. gl.attachShader(shaderProgram, fragmentShader);

  314. gl.linkProgram(shaderProgram);

  315. // If creating the shader program failed, alert

  316. if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {

  317. alert("Unable to initialize the shader program.");

  318. }

  319. gl.useProgram(shaderProgram);

  320. vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");

  321. gl.enableVertexAttribArray(vertexPositionAttribute);

  322. textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");

  323. gl.enableVertexAttribArray(textureCoordAttribute);

  324. vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");

  325. gl.enableVertexAttribArray(vertexNormalAttribute);

  326. }

  327. //

  328. // getShader

  329. //

  330. // Loads a shader program by scouring the current document,

  331. // looking for a script with the specified ID.

  332. //

  333. function getShader(gl, id) {

  334. var shaderScript = document.getElementById(id);

  335. // Didn't find an element with the specified ID; abort.

  336. if (!shaderScript) {

  337. return null;

  338. }

  339. // Walk through the source element's children, building the

  340. // shader source string.

  341. var theSource = "";

  342. var currentChild = shaderScript.firstChild;

  343. while(currentChild) {

  344. if (currentChild.nodeType == 3) {

  345. theSource += currentChild.textContent;

  346. }

  347. currentChildcurrentChild = currentChild.nextSibling;

  348. }

  349. // Now figure out what type of shader script we have,

  350. // based on its MIME type.

  351. var shader;

  352. if (shaderScript.type == "x-shader/x-fragment") {

  353. shader = gl.createShader(gl.FRAGMENT_SHADER);

  354. } else if (shaderScript.type == "x-shader/x-vertex") {

  355. shader = gl.createShader(gl.VERTEX_SHADER);

  356. } else {

  357. return null; // Unknown shader type

  358. }

  359. // Send the source to the shader object

  360. gl.shaderSource(shader, theSource);

  361. // Compile the shader program

  362. gl.compileShader(shader);

  363. // See if it compiled successfully

  364. if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

  365. alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));

  366. return null;

  367. }

  368. return shader;

  369. }

  370. //

  371. // Matrix utility functions

  372. //

  373. function loadIdentity() {

  374. mvMatrix = Matrix.I(4);

  375. }

  376. function multMatrix(m) {

  377. mvMatrixmvMatrix = mvMatrix.x(m);

  378. }

  379. function mvTranslate(v) {

  380. multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());

  381. }

  382. function setMatrixUniforms() {

  383. var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");

  384. gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten()));

  385. var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");

  386. gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));

  387. var normalMatrix = mvMatrix.inverse();

  388. normalMatrixnormalMatrix = normalMatrix.transpose();

  389. var nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");

  390. gl.uniformMatrix4fv(nUniform, false, new Float32Array(normalMatrix.flatten()));

  391. }

  392. var mvMatrixStack = [];

  393. function mvPushMatrix(m) {

  394. if (m) {

  395. mvMatrixStack.push(m.dup());

  396. mmvMatrix = m.dup();

  397. } else {

  398. mvMatrixStack.push(mvMatrix.dup());

  399. }

  400. }

  401. function mvPopMatrix() {

  402. if (!mvMatrixStack.length) {

  403. throw("Can't pop from an empty matrix stack.");

  404. }

  405. mvMatrix = mvMatrixStack.pop();

  406. return mvMatrix;

  407. }

  408. function mvRotate(angle, v) {

  409. var inRadians = angle * Math.PI / 180.0;

  410. var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();

  411. multMatrix(m);

  412. }

到此,相信大家对"如何在HTML5的浏览器上运行WebGL程序"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0