手机
当前位置:查字典教程网 >手机 >微信教程 >在支持HTML5的浏览器上运行WebGL程序的方法
在支持HTML5的浏览器上运行WebGL程序的方法
摘要:前提条件和预期结果目前只有少数的浏览器支持WebGL,请看我的另外一篇文章:CanIuseWebGL?.下面的例子是在Windows下的Ch...

前提条件和预期结果

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

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

2015618155306361.png (418380)

图1:包含 Hello world 文本的动画的 WebGL 立方体

在兼容 HTML5 的浏览器上,你将会看到如下图所示的带动画效果的立方体:

2015618155324527.jpg (600404)

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

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

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

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

// TODO #1 New method to create a texture

function createCubeTexture(text) {

...

}

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

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

// TODO #2 Assign the created texture for display

cubeTexture = createCubeTexture(Hello World!

源码

// File #1: webgl-demo.htm

XML/HTML Code复制内容到剪贴板 titleWebGL - Hello World!/title meta http-equiv=Content-Type content=text/html; charset=utf-8 script src=sylvester.js type=text/javascript/script script src=glUtils.js type=text/javascript/script script src=webgl-demo.js type=text/javascript/script !-- Fragment shader program -- script id=shader-fs type=x-shader/x-fragment varying highp vec2 vTextureCoord; varying highp vec3 vLighting; uniform sampler2D uSampler; void main(void) { highp vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a); } /script !-- Vertex shader program -- script id=shader-vs type=x-shader/x-vertex attribute highp vec3 aVertexNormal; attribute highp vec3 aVertexPosition; attribute highp vec2 aTextureCoord; uniform highp mat4 uNormalMatrix; uniform highp mat4 uMVMatrix; uniform highp mat4 uPMatrix; varying highp vec2 vTextureCoord; varying highp vec3 vLighting; void main(void) { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vTextureCoord = aTextureCoord; // Apply lighting effect highp vec3 ambientLight = vec3(0.6, 0.6, 0.6); highp vec3 directionalLightColor = vec3(0.5, 0.5, 0.75); highp vec3 directionalVector = vec3(0.85, 0.8, 0.75); highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0); highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0); vLighting = ambientLight + (directionalLightColor * directional); } /script /head body onload=start() canvas id=glcanvas width=640 height=480 Your browser doesn't appear to support the HTML5 canvas/code element. /canvas /body /html

// File #02: webgl-demo.js

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

var canvas;

var gl;

var cubeVerticesBuffer;

var cubeVerticesTextureCoordBuffer;

var cubeVerticesIndexBuffer;

var cubeVerticesIndexBuffer;

var cubeRotation = 0.0;

var lastCubeUpdateTime = 0;

var cubeImage;

var cubeTexture;

var mvMatrix;

var shaderProgram;

var vertexPositionAttribute;

var vertexNormalAttribute;

var textureCoordAttribute;

var perspectiveMatrix;

//

// start

//

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

//

function start() {

canvas = document.getElementById(glcanvas

initWebGL(canvas); // Initialize the GL context

// Only continue if WebGL is available and working

if (gl) {

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

gl.clearDepth(1.0); // Clear everything

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

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

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

// vertices and so forth is established.

initShaders();

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

// we'll be drawing.

initBuffers();

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

// TODO#2 Start

cubeTexture = createCubeTexture(Hello World!

// TODO#2 End

// Set up to draw the scene periodically.

setInterval(drawScene, 15);

}

}

//

// initWebGL

//

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

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

//

function initWebGL() {

gl = null;

try {

gl = canvas.getContext(experimental-webgl

}

catch(e) {

}

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

if (!gl) {

alert(Unable to initialize WebGL. Your browser may not support it.

}

}

//

// initBuffers

//

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

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

//

function initBuffers() {

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

cubeVerticesBuffer = gl.createBuffer();

// Select the cubeVerticesBuffer as the one to apply vertex

// operations to from here out.

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);

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

var vertices = [

// Front face

-1.0, -1.0, 1.0,

1.0, -1.0, 1.0,

1.0, 1.0, 1.0,

-1.0, 1.0, 1.0,

// Back face

-1.0, -1.0, -1.0,

-1.0, 1.0, -1.0,

1.0, 1.0, -1.0,

1.0, -1.0, -1.0,

// Top face

-1.0, 1.0, -1.0,

-1.0, 1.0, 1.0,

1.0, 1.0, 1.0,

1.0, 1.0, -1.0,

// Bottom face

-1.0, -1.0, -1.0,

1.0, -1.0, -1.0,

1.0, -1.0, 1.0,

-1.0, -1.0, 1.0,

// Right face

1.0, -1.0, -1.0,

1.0, 1.0, -1.0,

1.0, 1.0, 1.0,

1.0, -1.0, 1.0,

// Left face

-1.0, -1.0, -1.0,

-1.0, -1.0, 1.0,

-1.0, 1.0, 1.0,

-1.0, 1.0, -1.0

];

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

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

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

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

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

cubeVerticesNormalBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);

var vertexNormals = [

// Front

0.0, 0.0, 1.0,

0.0, 0.0, 1.0,

0.0, 0.0, 1.0,

0.0, 0.0, 1.0,

// Back

0.0, 0.0, -1.0,

0.0, 0.0, -1.0,

0.0, 0.0, -1.0,

0.0, 0.0, -1.0,

// Top

0.0, 1.0, 0.0,

0.0, 1.0, 0.0,

0.0, 1.0, 0.0,

0.0, 1.0, 0.0,

// Bottom

0.0, -1.0, 0.0,

0.0, -1.0, 0.0,

0.0, -1.0, 0.0,

0.0, -1.0, 0.0,

// Right

1.0, 0.0, 0.0,

1.0, 0.0, 0.0,

1.0, 0.0, 0.0,

1.0, 0.0, 0.0,

// Left

-1.0, 0.0, 0.0,

-1.0, 0.0, 0.0,

-1.0, 0.0, 0.0,

-1.0, 0.0, 0.0

];

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

gl.STATIC_DRAW);

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

cubeVerticesTextureCoordBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);

var textureCoordinates = [

// Front

0.0, 0.0,

1.0, 0.0,

1.0, 1.0,

0.0, 1.0,

// Back

0.0, 0.0,

1.0, 0.0,

1.0, 1.0,

0.0, 1.0,

// Top

0.0, 0.0,

1.0, 0.0,

1.0, 1.0,

0.0, 1.0,

// Bottom

0.0, 0.0,

1.0, 0.0,

1.0, 1.0,

0.0, 1.0,

// Right

0.0, 0.0,

1.0, 0.0,

1.0, 1.0,

0.0, 1.0,

// Left

0.0, 0.0,

1.0, 0.0,

1.0, 1.0,

0.0, 1.0

];

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

gl.STATIC_DRAW);

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

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

cubeVerticesIndexBuffer = gl.createBuffer();

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);

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

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

// position.

var cubeVertexIndices = [

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

]

// Now send the element array to GL

gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,

new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);

}

//

// initTextures

//

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

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

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

//

// TODO#1 Start

function createCubeTexture(text) {

// create a hidden canvas to draw the texture

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

canvas.id = hiddenCanvas

canvas.width = 512;

canvas.height = 512;

canvas.style.display = none

var body = document.getElementsByTagName(body

body.appendChild(canvas);

// draw texture

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

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

ctx.beginPath();

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

ctx.fillStyle = 'white';

ctx.fill();

ctx.fillStyle = 'black';

ctx.font = 65px Arial

ctx.textAlign = 'center';

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

ctx.restore();

// create new texture

var texture = gl.createTexture();

gl.bindTexture(gl.TEXTURE_2D, texture);

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

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

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

handleTextureLoaded(cubeImage, texture)

return texture;

}

// TODO#1 End

function handleTextureLoaded(image, texture) {

gl.bindTexture(gl.TEXTURE_2D, texture);

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

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

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

gl.generateMipmap(gl.TEXTURE_2D);

gl.bindTexture(gl.TEXTURE_2D, null);

}

//

// drawScene

//

// Draw the scene.

//

function drawScene() {

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

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

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

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

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

// and 100 units away from the camera.

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

// Set the drawing position to the identity point, which is

// the center of the scene.

loadIdentity();

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

// drawing the cube.

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

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

mvPushMatrix();

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

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

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

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer);

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

// Set the texture coordinates attribute for the vertices.

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);

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

// Bind the normals buffer to the shader attribute.

gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);

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

// Specify the texture to map onto the faces.

gl.activeTexture(gl.TEXTURE0);

gl.bindTexture(gl.TEXTURE_2D, cubeTexture);

gl.uniform1i(gl.getUniformLocation(shaderProgram, uSampler

// Draw the cube.

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);

setMatrixUniforms();

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

// Restore the original matrix

mvPopMatrix();

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

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

if (lastCubeUpdateTime) {

var delta = currentTime - lastCubeUpdateTime;

cubeRotation += (30 * delta) / 1000.0;

}

lastCubeUpdateTime = currentTime;

}

//

// initShaders

//

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

//

function initShaders() {

var fragmentShader = getShader(gl, shader-fs

var vertexShader = getShader(gl, shader-vs

// Create the shader program

shaderProgram = gl.createProgram();

gl.attachShader(shaderProgram, vertexShader);

gl.attachShader(shaderProgram, fragmentShader);

gl.linkProgram(shaderProgram);

// If creating the shader program failed, alert

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

alert(Unable to initialize the shader program.

}

gl.useProgram(shaderProgram);

vertexPositionAttribute = gl.getAttribLocation(shaderProgram, aVertexPosition

gl.enableVertexAttribArray(vertexPositionAttribute);

textureCoordAttribute = gl.getAttribLocation(shaderProgram, aTextureCoord

gl.enableVertexAttribArray(textureCoordAttribute);

vertexNormalAttribute = gl.getAttribLocation(shaderProgram, aVertexNormal

gl.enableVertexAttribArray(vertexNormalAttribute);

}

//

// getShader

//

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

// looking for a script with the specified ID.

//

function getShader(gl, id) {

var shaderScript = document.getElementById(id);

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

if (!shaderScript) {

return null;

}

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

// shader source string.

var theSource = ;

var currentChild = shaderScript.firstChild;

while(currentChild) {

if (currentChild.nodeType == 3) {

theSource += currentChild.textContent;

}

currentChildcurrentChild = currentChild.nextSibling;

}

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

// based on its MIME type.

var shader;

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

shader = gl.createShader(gl.FRAGMENT_SHADER);

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

shader = gl.createShader(gl.VERTEX_SHADER);

} else {

return null; // Unknown shader type

}

// Send the source to the shader object

gl.shaderSource(shader, theSource);

// Compile the shader program

pileShader(shader);

// See if it compiled successfully

if (!gl.getShaderParameter(shader, PILE_STATUS)) {

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

return null;

}

return shader;

}

//

// Matrix utility functions

//

function loadIdentity() {

mvMatrix = Matrix.I(4);

}

function multMatrix(m) {

mvMatrixmvMatrix = mvMatrix.x(m);

}

function mvTranslate(v) {

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

}

function setMatrixUniforms() {

var pUniform = gl.getUniformLocation(shaderProgram, uPMatrix

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

var mvUniform = gl.getUniformLocation(shaderProgram, uMVMatrix

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

var normalMatrix = mvMatrix.inverse();

normalMatrixnormalMatrix = normalMatrix.transpose();

var nUniform = gl.getUniformLocation(shaderProgram, uNormalMatrix

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

}

var mvMatrixStack = [];

function mvPushMatrix(m) {

if (m) {

mvMatrixStack.push(m.dup());

mmvMatrix = m.dup();

} else {

mvMatrixStack.push(mvMatrix.dup());

}

}

function mvPopMatrix() {

if (!mvMatrixStack.length) {

throw(Can't pop from an empty matrix stack.

}

mvMatrix = mvMatrixStack.pop();

return mvMatrix;

}

function mvRotate(angle, v) {

var inRadians = angle * Math.PI / 180.0;

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

multMatrix(m);

}

【在支持HTML5的浏览器上运行WebGL程序的方法】相关文章:

尼康COOLPIX A支持打印吗

在Dreamweaver里面添加音乐播放器背景音乐的方法

索尼A7S II有屏幕吗?

厨房柜子用什么材料更好

HTML标签中title 属性换行显示的方法

相机教你用低配变大神

尼康AW1的ISO是多少

欧式装修风格吊顶设计方法

松下GF6支持HDR吗?

简约风格儿童房装修效果图

精品推荐
分类导航