{"id":16385629,"url":"https://github.com/aaaaash/make_webgl_great","last_synced_at":"2025-10-08T03:32:57.051Z","repository":{"id":100795704,"uuid":"114960520","full_name":"Aaaaash/make_webgl_great","owner":"Aaaaash","description":"📚WebGL编程指南学习笔记","archived":false,"fork":false,"pushed_at":"2018-01-02T08:15:43.000Z","size":15036,"stargazers_count":4,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-23T16:50:06.629Z","etag":null,"topics":["webgl"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Aaaaash.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-12-21T03:57:05.000Z","updated_at":"2023-01-07T04:07:27.000Z","dependencies_parsed_at":"2023-06-10T01:03:45.122Z","dependency_job_id":null,"html_url":"https://github.com/Aaaaash/make_webgl_great","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Aaaaash/make_webgl_great","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Fmake_webgl_great","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Fmake_webgl_great/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Fmake_webgl_great/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Fmake_webgl_great/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Aaaaash","download_url":"https://codeload.github.com/Aaaaash/make_webgl_great/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aaaaash%2Fmake_webgl_great/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278885847,"owners_count":26062968,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["webgl"],"created_at":"2024-10-11T04:14:55.221Z","updated_at":"2025-10-08T03:32:57.032Z","avatar_url":"https://github.com/Aaaaash.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebGL tutorial\n\n## Hello WebGL\n\n```javascript\nconst canvas = document.querySelector('#canvas');\n\n// 获取webgl绘图上下文\nconst gl = canvas.getContext('webgl') || .getContext(\"experimental-webgl\");\n\n// 清空颜色 分量 颜色值为0-1  rgba颜色值需转换 (255, 255, 255, 255) 等价于 (1.0,1.0,1.0,1.0)\ngl.clearColor(0.0,0.0,0.0,1.0);\n// 可以调用 gl.getParameter(gl.COLOR_CLEAR_VALUE) 获取当前指定清空的颜色\n// 清空颜色缓冲区\n/*\n * gl.DEPTH_BUFFER_BIT  深度缓冲区\n * gl.STENCIL_BUFFER_BIT 模板缓冲区\n*/\ngl.clear(gl.COLOR_BUFFER_BIT);\n```\n\n## 画一个点\n```javascript\n// 顶点着色器\n/**\n * 描述顶点特性，位置、颜色等的程序\n * 顶点是指二维或三维空间中的一个点，比如二维或三维图形的端点或交点\n */\nconst VSHADER_SOURCE = `\n  void main() {\n    // vec4 表示4个浮点数组成的矢量\n    gl_Position = vec4(0.0,0.0,0.0,1.0); // 设置坐标\n    gl_PointSize = 10.0;  // 设置尺寸\n  }\n`;\n\n// 片元着色器 GLSL ES语言\n/**\n * 进行逐片元处理过程的程序\n * 可以理解为像素， 图像的单元\n */\nconst FSHADER_SOURCE = `\n  void main() {\n    gl_FragColor = vec4(1.0,0.0,0.0,1.0); // 设置颜色\n  }\n`;\n\n// 初始化webgl GLSL ES语言\nconst gl = getWebGLContext(canvas, true);\nif (!gl) {\n  return;\n}\n\n// 初始化着色器程序\nif (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {\n  return;\n}\n\n// 清空画布背景\ngl.clearColor(0.0,0.0,0.0,1.0);\ngl.clear(gl.COLOR_BUFFER_BIT);\n\n// 绘制图形\ngl.drawArrays(gl.POINT, 0, 1);\n```\n\n## 坐标系\nWebGL使用三维坐标系（笛卡尔坐标系），X轴正方向为右边，Y轴正方向为上，Z轴正方向为外（屏幕外）也叫右手坐标系\n![做右手坐标系](https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image\u0026quality=100\u0026size=b4000_4000\u0026sec=1514354164\u0026di=1511f18361094dad5b6183aef1d6e448\u0026src=http://static.oschina.net/uploads/space/2014/1219/150629_NFJt_1443646.jpg)\n\n## 向顶点着色器变量传值\n```javascript\n// 使用attribute变量从外部向顶点着色器内传输数据\nconst VSHADER_SOURCE = `\n  // 接受vec4类型的attribute变量\n  attribute vec4 a_Position;\n  attribute float a_PointSize;\n  void main() {\n    // 将a_Position值赋值给gl_Position 设置顶点坐标\n    gl_Position = a_Position;\n    gl_PointSize = a_PointSize;\n  }\n`;\n\nconst FSHADER_SOURCE = `\n  void main() {\n    gl_FragColor = vec4(0.0,1.0,0.0,1); // 设置颜色\n  }\n`;\n\n\nfunction main() {\n  const canvas = document.querySelector('#canvas');\n\n  const gl = getWebGLContext(canvas, true);\n  if (!gl) {\n    return;\n  }\n\n  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {\n    return;\n  }\n  /**\n   * 获取a_Position变量的存储位置\n   * getAttribLocation方法用于获取指定变量在着色器程序中的存储位置\n   */\n  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');\n\n  // 获取a_PointSize变量的存储位置\n  const a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');\n\n  if (a_Position \u003c 0) {\n    return;\n  }\n  \n  /**\n   * 将顶点位置传递给a_Position 会在着色器程序中被接收\n   * vertexAttrib3f方法指定通用顶点属性的值\n   * https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttrib\n   * 属性值为向量，表示顶点坐标，方法名vertexAttrib3f表示可以传递3个浮点型的分量值\n   * 同族函数中还有vertexAttrib1f以及vertexAttrib2f\n   * 以及vertexAttrib2fv系列函数，是上述方法的矢量版本，名字多了个字母v，接受类型化数组\n   * vertexAttrib1fv系列函数表示接受一个或多个浮点型分量组成的Float32Array类型的数组\n   * 也可以使用vertexAttrib3fv方法\n   * const floatArray = new Float32Array([0.0,0.0,0.0]);\n   * gl.vertexAttrib3fv(a_Position, floatArray);\n   */\n  const floatArray = new Float32Array([0.5,0.0,0.0]);\n  const pointSize = 30.0;\n  // 使用vertexAttrib1f方法将pointSize传递给顶点着色器内的a_PointSize变量\n  gl.vertexAttrib1f(a_PointSize, pointSize);\n  gl.vertexAttrib3fv(a_Position, floatArray);\n  // gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);\n  gl.clearColor(0.0,0.0,0.0,1.0);\n  gl.clear(gl.COLOR_BUFFER_BIT);\n  gl.drawArrays(gl.POINT, 0, 1);\n}\n```\n\n## 向片元着色器变量传值\nattribute只能传递给顶点着色器\n向片元着色器传值需要使用`uniform`变量\n```GLSL\nprecision mediump float; // 设置精度\n// 表示接受vec4类型的uniform变量\nuniform vec4 u_FragColor;\nvoid main() {\n  gl_FragColor = u_FragColor; // 设置颜色\n}\n```\n获取uniform变量的存储位置需要使用`getUniformLocation`函数\n```javascript\n// 获取u_FragColor变量的存储位置\nconst u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');\n```\n向uniform变量赋值需要使用`uniform[1234]f[v]`系列函数，参数与用法和`vertexAttrib[1234]f[v]`很相似\n```javascript\nconst colors = new Float32Array([color[0], color[1], color[2], color[3]]);\ngl.uniform4fv(u_FragColor, colors);\n```\n\n## 缓冲区对象\n缓冲区对象是webgl系统中的一块内存区域，可以一次性的向缓冲区对象中填充大量的顶点数据，将数据保存在其中以供顶点着色器使用\n![buffer](https://raw.githubusercontent.com/SakuraAsh/make_webgl_great/1e57d78a4b5513da585b7749fee5553d0a834b7b/images/buffer.png)\n\n使用缓冲区对象向顶点着色器传入多个顶点的数据，需要遵循以下5个步骤\n\n* 创建缓冲区对象(gl.createBuffer())\n* 绑定缓冲区对象(gl.bindBuffer())\n* 将数据写入缓冲区对象(gl.bufferData())\n* 将缓冲区对象分配给一个attribute变量(gl.vertexAttribPointer)\n* 开启attribute变量(gl.enableVertexAttribArray)\n\n```javascript\nconst vertices = new Float32Array([\n  0.0, 0.5, -0.5, -0.5, 0.5, -0.5\n]);\n\nconst n = 3;\n\nconst vertexBuffer = gl.createBuffer();\nif (!vertexBuffer) {\n  return -1;\n}\n/**\n * 将缓冲区对象绑定到目标\n * bindBuffer函数 第一个参数为绑定的目标 第二个参数为绑定的缓冲区对象\n * ARRAY_BUFFER为目标\n */\ngl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);\n  /**\n   * 向缓冲区对象中写入数据\n   * bufferData函数 第一个对象同为绑定的目标 第二个参数为绑定的数据\n   */\ngl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);\n\nconst a_Position = gl.getAttribLocation(gl.program, 'a_Position');\n// 分配缓冲区对象给变量\ngl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);\n// 连接a_Position变量与分配给它的缓冲区对象\ngl.enableVertexAttribArray(a_Position);\n```\n\n### 类型化数组\n\u003e 为了绘制图形，WebGL通常需要同时处理大量相同类型的数据，例如顶点坐标和颜色数据。为了优化性能，WebGL为美中基本数据类型引入了一种特殊的数据（类型化数组），由于浏览器事先知道数组中的数据类型，所以处理起来也更加有效率\n\nFloat32Array就是一种类型化数组，常用来存储顶点坐标或颜色数据，WebGL中很多操作都需要用到类型化数组，比如gl.bufferData中的第二个参数data\n\n数组类型|每个元素所占字节数|描述（C语言中的数据类型）\n----|---------|-------------\nInt8Array|1|8位整型数\nUInt8Array|1|8位无符号整型数\nInt16Array|2|16位整型数\nUInt16Array|2|16位无符号整型数\nInt32Array|4|32位整型数\nUInt32Array|4|32位无符号整型数\nFloat32Array|4|单精度32位浮点数\nFloat64Array|8|双精度64位浮点数\n\n\u003e 类型化数组不支持push()和pop()方法\n\n## 绘制三角形\n将绘制三个点的代码中`gl.drawArrays(gl.POINT, 0, 3);`修改为`gl.drawArrays(gl.TRIANGLES, 0, 3);`\n\n相当于告诉WebGL，从缓冲区的第一个顶点开始，使顶点着色器执行3次，用这3个点绘制出一个三角形\n![dl.drawArrays](https://github.com/SakuraAsh/make_webgl_great/blob/97027d0604f5c737318363ad968f1418827dac69/images/drawarrays.png?raw=true)\n\n\u003e 从球体到立方体，再到游戏中的三维角色，都可以用小的三角形组成，可以使用这些最基本的图形来绘制出任何东西\n\n## 绘制矩形\n\n```javascript\n// 将绘制三角形代码中的`drawArray`修改为\ngl.drawArrays(gl.TRIANGLE_FAN, 0, n);\n\n// 顶点数据修改为\nconst vertices = new Float32Array([\n  -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5\n]);\n```\n表示绘制一个三角带，实际上矩形由两个三角形构成\n\n## 复杂变换，矩阵\nwebgl中平移、旋转、缩放等变换操作都可以用一个4x4的矩阵来表示，为了简化编程，可以使用矩阵操作函数库来隐藏数学计算的细节，简化与矩阵有关的操作\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaaaash%2Fmake_webgl_great","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faaaaash%2Fmake_webgl_great","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaaaash%2Fmake_webgl_great/lists"}