-
简介
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
WebGL是什么?WebGL是一项利用JavaScript API呈现3D计算机图形的技术,有别于过往需加装浏览器插件,通过WebGL的技术,只需要编写网页代码即可实现3D图像的展示。
在详细了解WebGL之前,先看看WebGL为我们带来的3D视觉震撼吧。
- Lights 在 Lights 中,黄色的“闪光线”会随着鼠标的左右点击而左右摆动,当“气泡”出现时,点击它们会出现焰火般的炫丽景象。而其背景音乐是英国歌手 Ellie Goulding 制作的一个互动音乐体验,同时随着音乐节拍界面会有呼吸状的闪光。
- 经典鱼缸测试这是一个经典的网页速度测试,电脑网速越快,鱼游的速度就越快,另外有多个场景可以切换,鱼的数量也可以设置。
- WebGL Water展示了使用WebGL模拟水的效果,可以通过操作水中的球体来感受水体的变化。
要看到上面这些绚烂的效果,你需要确保你的浏览器支持WebGL,目前支持WebGL的浏览器众多,包括:
- Mozilla Firefox ─ 从4.0开始支持默认激活。
- Google Chrome ─ 从9.0开始支持默认激活。
- Internet Explorer ─ 从11开始支持。较旧的版本可以安装第三方插件来支持,如IEWebGL.
- Safari ─ 在 Mac OS X Snow Leopard上的Safari 5.1、 OS X Mountain Lion, Mac OS X Lion上的Safari6.0或较新版本开始支持WebGL,默认情况下禁用。
- Opera (需自行激活)
-
开发环境搭建
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
开发WebGL的环境十分简单,你甚至只需要支持WebGL的浏览器和文本编辑器就可以了。通过我的简单测试,推荐使用Google的Chrome浏览器进行开发和调试。WebGL属于3D开发,因此有以下的编程基础可能对你熟练掌握WebGL大有裨益,包括:
- OpenGL的相关知识,WebGL是基于OpenGL ES 2.0作为技术蓝本的,而OpenGL ES 2.0又是以OpenGL 2.0为基础。
Fig 1 OpenGL和WebGL - Shader尤其是GLSL的编程经验。
推荐的GLSL学习材料:
- LightHouse GLSL Tutorial (国内局域网有时候可能访问不了,o(╯□╰)o)
- OpenGL Shading Language(橙宝书,目前到第三版,网上很容易找到电子版)
- racehorse的CSDN Blog(lighthouse3d的翻译版)
- JavaScript相关编程经验
-
Hello,WebGL
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在学习一门新的技术时,如果可以有一个完整的框架,不需要每次都从头开始,对初学者是非常有益的。本文以下部分提供一个完整的WebGL程序,并通过对该程序的解读让读者对如何使用WebGL开发有一个完整的认识。相关内容来自WebGL Programming Guide一书。
- 首先创建我们的WebGL第一个示例的Html文件,在任意文件夹中建立名为HelloWebGL.html的文件,用文本编辑器打开,键入以下Html
可以看到WebGL绘图的区域是在浏览器中canvas标签之下进行的,canvas标签是Html5引入的一个新的标签,可以在canvas区域绘制2D和3D图形。为了代码的清晰,将WebGL代码的编写部分放在了HelloWebGL.js文件中,也可以将WebGL的代码放在Html中。<!DOCTYPE html> <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio"> <TITLE>Hello WebGL!</TITLE> </HEAD> <BODY οnlοad="main()"> <canvas id="webgl" width="400" height="400"> Your Browser doesn't support WebGL </canvas> <script src="HelloWebGL.js"></script> </BODY> </HTML>
- 在同一文件夹中建立HelloWebGL.js的文件,开始在其中编写WebGL相关代码
首先我们需要在代码中写一些GLSL的代码,关于GLSL的编写参看以上GLSL的推荐材料,一般来说GLSL分为两种类型,顶点Shader和片元Shader。在写好Shader之后需要将Shader进行如C语言一样的编译、链接、运行的过程。流程如下:
Fig 2 Shader使用过程
var VSHADER_SOURCE = 'void main() {\n' + ' gl_Position = vec4(0.0, 0.0, 0.0, 1.0); \n' + ' gl_PointSize = 10.0;\n' + '}\n'; var FSHADER_SOURCE = 'void main() {\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + '}\n';
以上就是我们写好的Shader,十分的简单,设置顶点位置在(0.0, 0.0, 0.0)处,顶点的大小为10.0,顶点栅格化之后的像素颜色是红色(1.0,0.0,0.0)
写好Shader之后我们开始写Html中提到加载需要的main函数,代码如下
function main() { //获取画布 var canvas = document.getElementById('webgl'); //得到WebGL渲染的上下文 var gl = canvas.getContext('experimental-webgl'); if (!gl) { console.log("Failed to initialize WebGL Context"); return; } //初始化Shader initializeShader(gl); //设置清除背景颜色(此处是黑色) gl.clearColor(0.0, 0.0, 0.0, 1.0); //清除背景 gl.clear(gl.COLOR_BUFFER_BIT); //绘制点(GL_POINTS) gl.drawArrays(gl.POINTS, 0, 1); }
在main函数中我们通过得到canvas的图形渲染上下文gl,之后所有的WebGL调用都是在gl上下文中进行的,main函数中调用的初始化shader的函数如下:
function initializeShader(gl) { //创建一个顶点Shader var vertexShader = gl.createShader(gl.VERTEX_SHADER); if (!vertexShader) { console.log("Unable to create Vertex Shader"); return; } //读入顶点Shader的内容 gl.shaderSource(vertexShader, VSHADER_SOURCE); //编译顶点Shader gl.compileShader(vertexShader); var compiledVertexShader = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS); if (!compiledVertexShader) { var error = gl.getShaderInfoLog(vertexShader); console.log('Failed to compile vertex shader: ' + error); gl.deleteShader(vertexShader); return; } //创建一个片元Shader var fragShader = gl.createShader(gl.FRAGMENT_SHADER); if (!fragShader) { console.log("Unable to create Fragment Shader"); return; } //读入片元Shader的内容 gl.shaderSource(fragShader, FSHADER_SOURCE); //编译片元Shader gl.compileShader(fragShader); var compiledFragmentShader = gl.getShaderParameter(fragShader, gl.COMPILE_STATUS); if (!compiledFragmentShader) { var error = gl.getShaderInfoLog(fragShader); console.log('Failed to compile fragment shader: ' + error); gl.deleteShader(fragShader); return; } //创建Program var program = gl.createProgram(); if (!program) { return; } //将编译好的顶点Shader和片元Shader链接到Program之中 gl.attachShader(program, vertexShader); gl.attachShader(program, fragShader); gl.linkProgram(program); var linked = gl.getProgramParameter(program, gl.LINK_STATUS); if (!linked) { var error = gl.getProgramInfoLog(program); console.log('Failed to link program: ' + error); gl.deleteProgram(program); gl.deleteShader(fragShader); gl.deleteShader(vertexShader); return; } //使用(运行)Program gl.useProgram(program); }
这一过程还是十分清晰的,流程就是参考了Fig2中的描述。以上就完成了所有的代码 - 用Chrome浏览器打开HelloWebGL.html,可以看到
使用WebGL绘制的一个红色的像素点
由于每一个WebGL的程序都需要initializeShader这一步骤,因此本文提供一个js文件,使用其中的initShaders函数,传入顶点和片元Shader字符实现shader的初始化过程。
// cuon-utils.js (c) 2012 kanda and matsuda /** * Create a program object and make current * @param gl GL context * @param vshader a vertex shader program (string) * @param fshader a fragment shader program (string) * @return true, if the program object was created and successfully made current */ function initShaders(gl, vshader, fshader) { var program = createProgram(gl, vshader, fshader); if (!program) { console.log('Failed to create program'); return false; } gl.useProgram(program); gl.program = program; return true; } /** * Create the linked program object * @param gl GL context * @param vshader a vertex shader program (string) * @param fshader a fragment shader program (string) * @return created program object, or null if the creation has failed */ function createProgram(gl, vshader, fshader) { // Create shader object var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader); var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader); if (!vertexShader || !fragmentShader) { return null; } // Create a program object var program = gl.createProgram(); if (!program) { return null; } // Attach the shader objects gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); // Link the program object gl.linkProgram(program); // Check the result of linking var linked = gl.getProgramParameter(program, gl.LINK_STATUS); if (!linked) { var error = gl.getProgramInfoLog(program); console.log('Failed to link program: ' + error); gl.deleteProgram(program); gl.deleteShader(fragmentShader); gl.deleteShader(vertexShader); return null; } return program; } /** * Create a shader object * @param gl GL context * @param type the type of the shader object to be created * @param source shader program (string) * @return created shader object, or null if the creation has failed. */ function loadShader(gl, type, source) { // Create shader object var shader = gl.createShader(type); if (shader == null) { console.log('unable to create shader'); return null; } // Set the shader program gl.shaderSource(shader, source); // Compile the shader gl.compileShader(shader); // Check the result of compilation var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!compiled) { var error = gl.getShaderInfoLog(shader); console.log('Failed to compile shader: ' + error); gl.deleteShader(shader); return null; } return shader; } /** * Initialize and get the rendering for WebGL * @param canvas <cavnas> element * @param opt_debug flag to initialize the context for debugging * @return the rendering context for WebGL */ function getWebGLContext(canvas, opt_debug) { // Get the rendering context for WebGL var gl = WebGLUtils.setupWebGL(canvas); if (!gl) return null; // if opt_debug is explicitly false, create the context for debugging if (arguments.length < 2 || opt_debug) { gl = WebGLDebugUtils.makeDebugContext(gl); } return gl; }