添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
学习 WebGL 似乎有些难度,因为大多数教程都想一次教完所有东西, 而我会尽量避免这样,在需要合适的时候讲一些小的知识点。

WebGL 复杂的原因之一是需要两个方法,一个顶点着色器和一个片断着色器。 这两个方法是在你的 GPU 上运行,也是高速运行的保障。 所以它们是一种自定义语言,目的是能够在 GPU 上良好运行。 这两个方法需要编译并链接在一起,而这个过程在 99% 的 WbgGL 应用中是一样的。

这是编译着色器的样板代码。

* 创建并编译一个着色器 * @param {!WebGLRenderingContext} gl WebGL上下文。 * @param {string} shaderSource GLSL 格式的着色器代码 * @param {number} shaderType 着色器类型, VERTEX_SHADER 或 * FRAGMENT_SHADER. * @return {!WebGLShader} 着色器。 function compileShader(gl, shaderSource, shaderType) { // 创建着色器程序 var shader = gl.createShader(shaderType); // 设置着色器的源码 gl.shaderSource(shader, shaderSource); // 编译着色器 gl.compileShader(shader); // 检测编译是否成功 var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!success) { // 编译过程出错,获取错误信息。 throw ("could not compile shader:" + gl.getShaderInfoLog(shader)); return shader;

这是链接 2 个着色器到一个着色程序中的代码

* 从 2 个着色器中创建一个程序 * @param {!WebGLRenderingContext) gl WebGL上下文。 * @param {!WebGLShader} vertexShader 一个顶点着色器。 * @param {!WebGLShader} fragmentShader 一个片断着色器。 * @return {!WebGLProgram} 程序 function createProgram(gl, vertexShader, fragmentShader) { // 创建一个程序 var program = gl.createProgram(); // 附上着色器 gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); // 链接到程序 gl.linkProgram(program); // 检查链接是否成功 var success = gl.getProgramParameter(program, gl.LINK_STATUS); if (!success) { // 链接过程出现问题,获取错误信息。 throw ("program failed to link:" + gl.getProgramInfoLog(program)); return program;

处理错误的方式有很多种,抛出错误信息可能是最好的方式。 而且这几行代码在几乎所有的 WebGL 程序中都是相似的。

现在所有现代浏览器都支持多行模板文字,这是我存储着色器的首选方式。我可以做类似的事情

var vertexShaderSource = `#version 300 es
in vec4 a_position;
uniform mat4 u_matrix;
void main() {
   gl_Position = u_matrix * a_position;

这易于编辑着色器。一些较旧的浏览器(如 IE)不支持这个,但首先我使用的是 WebGL,所以我并不真正关心 IE。 如果我确实关心并且有一个非 WebGL 回退,我会使用一些构建步骤比如 Babel 来将上面的代码转换成 IE 可以理解的东西。

过去我喜欢将我的着色器存储在非 javascript <script> 标签中。它也使它们易于编辑,因此我会使用这样的代码。

* 从脚本标签的内容创建一个着色器。 * @param {!WebGLRenderingContext} gl WebGL 上下文。 * @param {string} scriptId script标签的id。 * @param {string} opt_shaderType. 要创建的着色器的类型。 * 如果没有定义,就使用script标签的type属性。 * @return {!WebGLShader} 着色器。 function createShaderFromScript(gl, scriptId, opt_shaderType) { // 通过 id 查找脚本标签。 var shaderScript = document.getElementById(scriptId); if (!shaderScript) { throw("*** Error: unknown script element" + scriptId); // 提取脚本标签的内容。 var shaderSource = shaderScript.text; // 如果我们没有传入类型,就使用标签的 ‘type’ 属性 if (!opt_shaderType) { if (shaderScript.type == "x-shader/x-vertex") { opt_shaderType = gl.VERTEX_SHADER; } else if (shaderScript.type == "x-shader/x-fragment") { opt_shaderType = gl.FRAGMENT_SHADER; } else if (!opt_shaderType) { throw("*** Error: shader type not set"); return compileShader(gl, shaderSource, opt_shaderType);

现在编译着色器只需要

var shader = compileShaderFromScript(gl, "someScriptTagId");

我通常会更进一步,使用一个方法编译两个着色器,附加到程序并链接到程序。

* 通过两个 script 标签创建程序。 * @param {!WebGLRenderingContext} gl WebGL上下文。 * @param {string} vertexShaderId 顶点着色器的标签id。 * @param {string} fragmentShaderId 片断着色器的标签id。 * @return {!WebGLProgram} 程序。 function createProgramFromScripts( gl, vertexShaderId, fragmentShaderId) { var vertexShader = createShaderFromScriptTag(gl, vertexShaderId, gl.VERTEX_SHADER); var fragmentShader = createShaderFromScriptTag(gl, fragmentShaderId, gl.FRAGMENT_SHADER); return createProgram(gl, vertexShader, fragmentShader);

另一几乎在我所有 WebGL 应用中都会使用的代码是重置画布大小。你可以 在这里看看那个方法是如何实现的 .

所有示例中使用的这两个方法都在

<script src="resources/webgl-utils.js"></script>

里,并且像这样使用

var program = webglUtils.createProgramFromScripts(
  gl, [idOfVertexShaderScript, idOfFragmentShaderScript]);
webglUtils.resizeCanvasToMatchDisplaySize(canvas);

这样做就可以剔除大量和示例无关的代码,突出示例想要表达的内容。

多数这些示例中使用的实际样板 API 是

* 从 2 个来源创建一个程序。 * @param {WebGLRenderingContext} gl The WebGLRenderingContext * to use. * @param {string[]} shaderSources 着色器的源数组。 第一个是顶点着色器,第二个是片段着色器。 * @param {string[]} [opt_attribs] 属性名称数组。 * 如果不传入,位置将通过索引分配 * @param {number[]} [opt_locations] 属性的位置。 * opt_attribs 的并行数组,可让您分配位置。 * @param {module:webgl-utils.ErrorCallback} opt_errorCallback 错误回调。 * 默认情况下,它只在错误的时候向控制台打印一个错误 * 你可以通过回调函数来做一些其他事 * 它传递一个错误信息 * @return {WebGLProgram} 创建的程序。 * @memberOf module:webgl-utils function createProgramFromSources(gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback)

shaderSources 是一个包含 GLSL 源码的字符串数组 i。数组中的第一个字符串是顶点着色器源。第二个是片段着色器源。

这是我最小的一套 WebGL 样板代码。 你可以在 webgl-utils.js 中找到源码 . 如果你想要更有组织的代码。可以查看 TWGL.js .

其余的让 WebGL 显得比较复杂的部分就是设置着色器的输入,可以看看是 如何实现的 .

我还建议你看看 码少趣多 TWGL .

请注意,当我们添加它时,出于类似原因还有更多脚本

  • webgl-lessons-ui.js

    这个代码提供了含有数值的滑块,并能够在拖拽时更新数值。 同样的,我只是不想在示例代码中参杂太多不相干代码。

  • lessons-helper.js

    这个代码在 webgl2fundamentals.org 以外不是必须的,它只是能够在在线编辑器中提供合适的错误提示。

  • m3.js

    这是一个二维数学库,在讲到矩阵式需要用到,本来是将它们写在代码中的,但是考虑到无关代码较多, 就整合到一个脚本文件中了。

  • m4.js

    这是一个三维数学库,它们在三维的文章中使用,同样的由于代码较多,为保证示例代码显示明确, 就将它们写在一个文件中了。

  • Prevent the Canvas Being Cleared
  • Get Keyboard Input From a Canvas
  • Use WebGL2 as Background in HTML
  • Cross Platform Issues
  • Questions and Answers
  • Attributes
  • Texture Units
  • Framebuffers
  • readPixels
  • References
  • API帮助文档
  • TWGL,一个轻量级WebGL辅助库
  • GitHub
  •