{
  "version": "https://jsonfeed.org/version/1", 
  "title": "WebGL", 
  "description": "WebGL (Web Graphics Library) is a JavaScript API for rendering interactive 3D graphics and 2D graphics within any compatible web browser without the use of plug-ins.", 
  "home_page_url": "https://www.v2ex.com/go/webgl", 
  "feed_url": "https://www.v2ex.com/feed/webgl.json", 
  "icon": "https://cdn.v2ex.com/navatar/e0ec/453e/831_large.png?m=1420946106", 
  "favicon": "https://cdn.v2ex.com/navatar/e0ec/453e/831_normal.png?m=1420946106", 
  "items": [
    {
      "author": {
        "url": "https://www.v2ex.com/member/nashaofu", 
        "name": "nashaofu", 
        "avatar": "https://cdn.v2ex.com/avatar/8903/7228/471582_large.png?m=1644234668"
      }, 
      "url": "https://www.v2ex.com/t/934770", 
      "title": "\u8bf7\u6559\u4e00\u4e2a webgl \u95ee\u9898\uff0c\u4f8b\u5b50\u91cc\u9762\u7684\u4ee3\u7801\u5728 windows \u4e0e Linux \u4e0a\u8868\u73b0\u6b63\u5e38\uff0c mac \u4e0a\u63d0\u793a Vertex buffer is not big enough for the draw call", 
      "id": "https://www.v2ex.com/t/934770", 
      "date_published": "2023-04-23T06:09:03+00:00", 
      "content_html": "<p>\u4ee3\u7801\u5730\u5740\uff1a <a href=\"https://codesandbox.io/s/admiring-hill-rrpb3o?file=/index.html\" rel=\"nofollow\">https://codesandbox.io/s/admiring-hill-rrpb3o?file=/index.html</a></p>\n<p>mac \u4e0a\u62a5\u9519\u4fe1\u606f\uff1a</p>\n<pre><code>[WebGL-0x118003e4700] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call\n</code></pre>\n<p>\u671f\u671b\u80fd\u7ed8\u5236\u4e00\u4e2a\u7ea2\u8272\u4e09\u89d2\u5f62\u4e0e\u4e00\u4e2a\u84dd\u8272\u4e09\u89d2\u5f62\uff0c\u84dd\u8272\u4e09\u89d2\u5f62\u7a7f\u8fc7\u7ea2\u8272\u4e09\u89d2\u5f62\u3002</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/jiyinyiyong", 
        "name": "jiyinyiyong", 
        "avatar": "https://cdn.v2ex.com/avatar/f880/d0d6/7892_large.png?m=1457332042"
      }, 
      "url": "https://www.v2ex.com/t/788073", 
      "date_modified": "2021-07-07T06:09:41+00:00", 
      "content_html": "\u770b\u5230 Twitter \u4e0a\u6709\u4eba\u73a9\u4e8e\u662f\u773c\u998b\u4e86, <br />\u4e0d\u8fc7 Hopf \u5185\u5bb9\u6bd4\u8f83\u6df1, \u6211\u6ca1\u80fd\u5b8c\u6574\u505a\u51c6\u786e\u7684\u7248\u672c\u51fa\u6765 <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Hopf_fibration\" rel=\"nofollow noopener\">https://en.wikipedia.org/wiki/Hopf_fibration</a><br />\u53ea\u662f\u4e3a\u4e86\u751f\u6210\u56fe\u5f62\u7684\u8bdd, \u6309\u7167\u4e00\u4e9b\u7279\u6027\u7b80\u5316\u76f4\u63a5\u7b97\u4e86, \u6548\u679c\u8fd1\u4f3c\u7684.<br /><br />\u6512\u4e86\u4e24\u4e2a\u6f14\u793a\u89c6\u9891:<br /><br />* \u4eff Hopf \u7ea4\u7ef4\u4e1b\u751f\u6210 3D \u56fe\u5f62  <a target=\"_blank\" href=\"https://www.bilibili.com/video/BV18L411p7x1/\" rel=\"nofollow noopener\">https://www.bilibili.com/video/BV18L411p7x1/</a><br />* Quatrefoil \u5f00\u53d1\u8bb0\u5f55\uff1a\u87ba\u7ebf\u63a7\u5236 Hopf \u7ea4\u7ef4\u4e1b\uff0c\u7b49 <a target=\"_blank\" href=\"https://www.bilibili.com/video/BV1if4y1b7cg/\" rel=\"nofollow noopener\">https://www.bilibili.com/video/BV1if4y1b7cg/</a><br /><br />\u751f\u6210\u7684\u4e00\u4e9b\u56fe\u7247<br /><br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs8cl0ol5dj21z418g4qt.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs8cl96zorj21z418gkjm.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs8clej1vvj21z418gu10.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs8cllp7apj21z418gqv9.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs8cloq3a7j21z418gkjo.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs624o18uuj21z418gqv6.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs624r11aej21z418ge85.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs624u8ngij21z418ghdv.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs624xd9haj21z418g7wk.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><br />\u8fd8\u6709\u4e00\u5f20\u56fe.. \u662f\u4e2d\u95f4\u4ee3\u7801\u5199\u9519 Bug \u4e86\u7684. (\u5c45\u7136\u8fd8\u633a\u597d\u770b...)<br /><br /><img src=\"https://wx1.sinaimg.cn/mw2000/62752320gy1gs8cm6dcj1j21z418ge86.jpg\" class=\"embedded_image\" rel=\"noreferrer\" referrerpolicy=\"no-referrer\"> <br /><br />\u867d\u7136\u5927\u6982\u770b\u4e0d\u61c2, \u4f46\u662f\u5410\u8fc7\u6709\u4eba\u60f3\u770b\u4ee3\u7801\u7684\u8bdd<br /><a target=\"_blank\" href=\"https://github.com/Quamolit/quatrefoil.calcit\" rel=\"nofollow noopener\">https://github.com/Quamolit/quatrefoil.calcit</a>", 
      "date_published": "2021-07-07T06:06:18+00:00", 
      "title": "\u505a\u4e86\u4e00\u4e9b\u4eff Hopf \u7ea4\u7ef4\u4e1b\u7684\u56fe", 
      "id": "https://www.v2ex.com/t/788073"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/zoule", 
        "name": "zoule", 
        "avatar": "https://cdn.v2ex.com/avatar/0d45/28a0/371019_large.png?m=1604471674"
      }, 
      "url": "https://www.v2ex.com/t/741509", 
      "title": "WebGL \u5b9e\u73b0\u7b80\u5355\u6ee4\u955c", 
      "id": "https://www.v2ex.com/t/741509", 
      "date_published": "2021-01-04T06:36:39+00:00", 
      "content_html": "<h1>1. WebGL \u4ecb\u7ecd</h1>\n<p>WebGL \uff08\u5168\u5199 Web Graphics Library \uff09\u662f\u4e00\u79cd 3D \u7ed8\u56fe\u534f\u8bae\uff0c\u8fd9\u79cd\u7ed8\u56fe\u6280\u672f\u6807\u51c6\u5141\u8bb8\u628a JavaScript \u548c OpenGL ES 2.0 \u7ed3\u5408\u5728\u4e00\u8d77\uff0c\u901a\u8fc7\u589e\u52a0 OpenGL ES 2.0 \u7684\u4e00\u4e2a JavaScript \u7ed1\u5b9a\u3002</p>\n<h1>2. WebGL \u3001OpenGL \u3001OpenGL ES \u4e09\u8005\u7684\u5173\u7cfb</h1>\n<p><img alt=\"\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://upload-images.jianshu.io/upload_images/5432902-b5fc4031a468d6ff?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240\"/></p>\n<h1>3. WebGL \u57fa\u7840\u4ecb\u7ecd</h1>\n<pre><code>const webgl = document.getElementById(\"webGl-layer\").getContext(\"webgl\");\n\n</code></pre>\n<h1>4. \u57fa\u672c\u539f\u7406</h1>\n<ul>\n<li>\u9996\u5148\u4f7f\u7528 webgl \u7eb9\u7406\u7ed8\u5236\u56fe\u7247</li>\n</ul>\n<p>\u8fd9\u91cc\u5982\u679c\u53c2\u7167 <a href=\"https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-cors-permission.html\" rel=\"nofollow\">https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-cors-permission.html</a></p>\n<ul>\n<li>\u7ed8\u5236\u8fc7\u7a0b\u4e2d\u4f7f\u7528\u7247\u6bb5\u505a\u7740\u8272\u5668\u5bf9\u5176 rgb \u503c\u8fdb\u884c\u4fee\u6539</li>\n</ul>\n<h1>5. \u5177\u4f53\u5b9e\u73b0</h1>\n<p><img alt=\"\" class=\"embedded_image\" loading=\"lazy\" referrerpolicy=\"no-referrer\" rel=\"noreferrer\" src=\"https://upload-images.jianshu.io/upload_images/5432902-95ed80ff7d404ec1?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240\"/></p>\n<pre><code>&lt;!DOCTYPE html&gt;\n&lt;html lang=\"ch\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"UTF-8\"&gt;\n    &lt;title&gt;VertexBuffer&lt;/title&gt;\n&lt;/head&gt;\n&lt;body&gt;\n&lt;canvas id=\"webGl-layer\"  width=\"532\" height=\"300\"&gt;&lt;/canvas&gt;\n&lt;div&gt;\n    &lt;label for=\"r1\"&gt;\u9971\u548c\u5ea6:&lt;/label&gt;&lt;input type=\"range\" id=\"r1\" value=\"0\"/&gt;\n&lt;/div&gt;\n\n&lt;div&gt;\n    &lt;label for=\"r2\"&gt;R:&lt;/label&gt;&lt;input type=\"range\" id=\"r2\" value=\"0\"/&gt;\n&lt;/div&gt;\n\n&lt;div&gt;\n    &lt;label for=\"r3\"&gt;G:&lt;/label&gt;&lt;input type=\"range\" id=\"r3\" value=\"0\"/&gt;\n&lt;/div&gt;\n\n&lt;div&gt;\n    &lt;label for=\"r4\"&gt;B:&lt;/label&gt;&lt;input type=\"range\" id=\"r4\" value=\"0\"/&gt;\n&lt;/div&gt;\n\n&lt;script&gt;\n    const webgl = document.getElementById(\"webGl-layer\").getContext(\"webgl\");\n    const range1 = document.getElementById(\"r1\"),\n        range2 = document.getElementById(\"r2\"),\n        range3 = document.getElementById(\"r3\"),\n        range4 = document.getElementById(\"r4\");\n\n    webgl.viewport(0, 0, 532, 300);\n\n    const vertexShader2D = `\n        precision mediump float;\n        attribute vec4 position;\n        attribute vec4 inputTextureCoordinate;\n        varying vec2 textureCoordinate;\n\n        void main() {\n            gl_Position = position;\n            textureCoordinate = vec2((position.x+1.0)/2.0, 1.0-(position.y+1.0)/2.0);\n        }\n    `;\n\n    const fragmentShader2D = `\n        precision mediump float;\n        varying vec2 textureCoordinate;\n        uniform sampler2D inputImageTexture;\n        uniform float size;\n        uniform float saturation;\n        uniform float r;\n        uniform float g;\n        uniform float b;\n        uniform float a;\n\n        void main() {\n            vec4 texture = texture2D(inputImageTexture, textureCoordinate);\n            texture.r += r; // \u56fe\u7247\u6574\u4f53 r \u503c\n            texture.g += g; // \u56fe\u7247\u6574\u4f53 g \u503c\n            texture.b += b; // \u56fe\u7247\u6574\u4f53 b \u503c\n            // texture.a = 0.5; // \u56fe\u7247\u6574\u4f53 a \u503c\n\n            //\u5185\u9634\u5f71\n            // float dist = distance(textureCoordinate, vec2(0.5, 0.5));\n            // texture.rgb *= smoothstep(0.8, size * 0.799, dist * (1.0 + size));\n\n            //\u9971\u548c\u5ea6\n            float average = (texture.r + texture.g + texture.b) / 3.0;\n            if (saturation &gt; 0.0) {\n                texture.rgb += (average - texture.rgb) * (1.0 - 1.0 / (1.001 - saturation));\n            } else {\n                texture.rgb += (average - texture.rgb) * (-saturation);\n            }\n\n            gl_FragColor = texture;\n\n        }\n    `;\n\n    function createShader(gl, type, source) {\n        const shader = gl.createShader(type);\n        gl.shaderSource(shader, source);\n        gl.compileShader(shader);\n        if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n            return shader;\n        }\n        console.log(gl.getShaderInfoLog(shader));\n        gl.deleteShader(shader);\n    }\n\n    function createProgram(gl, vertexShader, fragmentShader) {\n        const program = gl.createProgram();\n        gl.attachShader(program, vertexShader);\n        gl.attachShader(program, fragmentShader);\n        gl.linkProgram(program);\n        if (gl.getProgramParameter(program, gl.LINK_STATUS)) {\n            webgl.useProgram(program);\n            return program;\n        }\n        console.error(gl.getProgramInfoLog(program));\n        gl.deleteProgram(program);\n    }\n\n    function createTextureByImageObject(gl, imgObject) {\n        gl.activeTexture(gl.TEXTURE0);\n        const textureObject = gl.createTexture();\n        gl.bindTexture(gl.TEXTURE_2D, textureObject);\n        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgObject);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)\n        return textureObject;\n    }\n\n    const vertices = [\n        1.0, 1.0,\n        1.0, -1.0,\n        -1.0, 1.0,\n        -1.0, -1.0\n    ];\n\n    const vertexShader = createShader(webgl, webgl.VERTEX_SHADER, vertexShader2D),\n        fragmentShader = createShader(webgl, webgl.FRAGMENT_SHADER, fragmentShader2D),\n        program = createProgram(webgl, vertexShader, fragmentShader),\n        buffer = webgl.createBuffer();\n\n    webgl.bindBuffer(webgl.ARRAY_BUFFER, buffer);\n    webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(vertices), webgl.STATIC_DRAW);\n\n    let v4PositionIndex = webgl.getAttribLocation(program, \"position\");\n    webgl.enableVertexAttribArray(v4PositionIndex);\n    webgl.vertexAttribPointer(v4PositionIndex, 2, webgl.FLOAT, false, 0, 0);\n\n    let img = new Image();\n    img.crossOrigin = \"anonymous\";\n    img.src = \"http://static.atvideo.cc/2021/01/04/09/47/1609724837(1).jpg\";\n    img.onload = function () {\n        document.body.append(img);\n        createTextureByImageObject(webgl, img);\n        let saturationUniform = webgl.getUniformLocation(program, \"saturation\");\n        let rUniform = webgl.getUniformLocation(program, \"r\");\n        let gUniform = webgl.getUniformLocation(program, \"g\");\n        let bUniform = webgl.getUniformLocation(program, \"b\");\n\n        // let sizeUniform = webgl.getUniformLocation(program, \"size\");\n        // webgl.uniform1f(sizeUniform, 2.0);\n\n        const uniform = webgl.getUniformLocation(program, \"inputImageTexture\");\n        webgl.uniform1i(uniform, 0);\n        webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);\n\n        range1.addEventListener(\"change\", function () {\n            const val = Number(range1.value) / 100;\n            webgl.uniform1f(saturationUniform, val);\n            webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);\n        });\n\n        range2.addEventListener(\"change\", function () {\n            const val = Number(range2.value) / 100;\n            webgl.uniform1f(rUniform, val);\n            webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);\n        });\n\n        range3.addEventListener(\"change\", function () {\n            const val = Number(range3.value) / 100;\n            webgl.uniform1f(gUniform, val);\n            webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);\n        });\n\n        range4.addEventListener(\"change\", function () {\n            const val = Number(range4.value) / 100;\n            webgl.uniform1f(bUniform, val);\n            webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);\n        });\n    }\n\n&lt;/script&gt;\n\n&lt;/body&gt;\n&lt;/html&gt;\n\n</code></pre>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/wotemelon", 
        "name": "wotemelon", 
        "avatar": "https://cdn.v2ex.com/avatar/143e/3398/222030_large.png?m=1705629499"
      }, 
      "url": "https://www.v2ex.com/t/695284", 
      "title": "\u6c42 webgl\uff08threejs\uff09\u6210\u4f53\u7cfb\u7684\u6559\u7a0b", 
      "id": "https://www.v2ex.com/t/695284", 
      "date_published": "2020-08-03T08:25:42+00:00", 
      "content_html": "<p>\u641c\u4e86\u5f88\u591a\u6559\u7a0b\uff0c\u611f\u89c9\u90fd\u6ca1\u6709\u6210\u4f53\u7cfb\uff0c\u6bd4\u8f83\u7247\u6bb5\uff0c\u8dea\u6c42\u6559\u7a0b\u6216\u6c42\u6307\u5bfc</p>\n"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/orangutan92", 
        "name": "orangutan92", 
        "avatar": "https://cdn.v2ex.com/avatar/d937/19f1/217568_large.png?m=1658931304"
      }, 
      "url": "https://www.v2ex.com/t/393018", 
      "date_modified": "2017-09-23T04:58:07+00:00", 
      "content_html": "<p>\u6700\u8fd1\u82b1\u4e86\u5c06\u8fd1\u4e00\u4e2a\u6708\u7684\u65f6\u95f4\u6574\u51fa\u4e86\u4e00\u4e2a\u7528 three.js \u7684 3D \u591a\u4eba\u5728\u7ebf\u7f51\u6e38\u7684\u9879\u76ee\uff0c\u60f3\u8981\u6df1\u5165\u5b66\u4e60\uff0c\u51c6\u5907\u4e70\u672c\u300a THREE.JS \u5f00\u53d1\u6307\u5357\u300b\u3002\u6211\u770b\u4e86\u4e0b\u300a WebGL \u7f16\u7a0b\u6307\u5357\u300b\u91cc\u9762\u6709\u6d89\u53ca\u5230\u77e9\u9635\u8fd0\u7b97\uff0c\u6211\u60f3\u77e5\u9053\u7684\u662f\uff0c\u5b66\u4e60 WebGL \u548c OpenGL \u8fd8\u9700\u8981\u54ea\u4e9b\u6570\u5b66\u77e5\u8bc6\u554a\uff1f\u611f\u89c9\u8fd9\u4e2a\u5b66\u4e60\u6210\u672c\u4f1a\u6bd4\u8f83\u9ad8\u3002\u3002\u3002\u6211\u770b\u7f51\u4e0a\u7684\u6559\u7a0b\u5f88\u591a\u90fd\u6bd4\u8f83\u8001\uff0c\u76f8\u5173\u7684\u4e66\u7c4d\u4e5f\u5c31\u90a3\u4e48\u51e0\u672c\u3002\u5927\u5bb6\u6709\u4ec0\u4e48\u597d\u7684\u5efa\u8bae\u5417\uff1f</p>\n", 
      "date_published": "2017-09-23T03:26:00+00:00", 
      "title": "\u6c42 WebGL \u548c three.js \u5b66\u4e60\u8def\u7ebf", 
      "id": "https://www.v2ex.com/t/393018"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/huangyang", 
        "name": "huangyang", 
        "avatar": "https://cdn.v2ex.com/avatar/64c6/e872/44719_large.png?m=1435543768"
      }, 
      "url": "https://www.v2ex.com/t/162935", 
      "date_modified": "2015-01-17T03:44:19+00:00", 
      "content_html": "<p><a target=\"_blank\" rel=\"nofollow\" href=\"http://threejs.org/examples/#webgl_materials_bumpmap_skin\">http://threejs.org/examples/#webgl_materials_bumpmap_skin</a></p>\n\n<p>\u5404\u79cd\u7ec6\u8282\u554a\uff0c\u752827\u5bf8Mac\u663e\u793a\u5668\u6253\u5f00\u7684\uff0c\u5dee\u70b9\u5413\u5230</p>\n", 
      "date_published": "2015-01-17T03:38:06+00:00", 
      "title": "\u8fd9\u4e2a WebGL 3D \u6e32\u67d3\u6548\u679c\u592a\u7f8e\u4e0d\u6562\u770b", 
      "id": "https://www.v2ex.com/t/162935"
    }, 
    {
      "author": {
        "url": "https://www.v2ex.com/member/Kai", 
        "name": "Kai", 
        "avatar": "https://cdn.v2ex.com/avatar/021b/bc7e/1024_large.png?m=1657391813"
      }, 
      "url": "https://www.v2ex.com/t/161056", 
      "title": "WebGL Water Simulator", 
      "id": "https://www.v2ex.com/t/161056", 
      "date_published": "2015-01-11T03:11:06+00:00", 
      "content_html": "<iframe id=\"ytplayer\" type=\"text/html\" width=\"660\" height=\"420\" src=\"//www.youtube.com/embed/R0O_9bp3EKQ\" frameborder=\"0\" allowfullscreen></iframe><br /><br /><a target=\"_blank\" href=\"http://www.madebyevan.com/webgl-water/\" rel=\"nofollow\">http://www.madebyevan.com/webgl-water/</a>"
    }
  ]
}