{"id":233,"date":"2021-07-22T23:56:43","date_gmt":"2021-07-22T15:56:43","guid":{"rendered":"https:\/\/blog.indeex.club\/?p=233"},"modified":"2021-10-13T10:02:47","modified_gmt":"2021-10-13T02:02:47","slug":"webgl%e5%9f%ba%e7%a1%80","status":"publish","type":"post","link":"https:\/\/blog.indeex.club\/index.php\/2021\/07\/22\/webgl%e5%9f%ba%e7%a1%80\/","title":{"rendered":"WebGL\u57fa\u7840"},"content":{"rendered":"<hr \/>\n<p>\u7531\u4e8eWebGl\u6280\u672f\u8f83\u4e3a\u6210\u719f\uff0c\u8fd9\u91cc\u4e0d\u518d\u8d58\u8ff0\u3002<\/p>\n<h3>\u8d44\u6e90\u521d\u59cb\u5316<\/h3>\n<pre><code class=\"language-javascript line-numbers\">let canvas: HTMLCanvasElement = document.getElementById('webgl') as HTMLCanvasElement;\n\nlet gl: WebGLRenderingContext = canvas.getContext('webgl');\nif (!gl) {\n\n    throw new Error('WebGL failed to initialize.');\n}\n\ngl.clearColor(0.0, 0.0, 0.0, 0.0);\n\ngl.colorMask(true, true, true, true)\n\ngl.enable(gl.DEPTH_TEST);\n\ngl.depthFunc(gl.LEQUAL);\n\ngl.cullFace(gl.BACK);\n\ngl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n<\/code><\/pre>\n<h3>Vertex Buffer Object\u9876\u70b9\u7f13\u51b2\u5bf9\u8c61<\/h3>\n<p>Vertex Buffer Object\u662f\u5305\u542b\u9876\u70b9\u6570\u636e\u7684\u5185\u5b58\u5757\u3002<\/p>\n<pre><code class=\"language-javascript line-numbers\">const positions = new Float32Array([\n    1.0, -1.0, 0.0,\n   -1.0, -1.0, 0.0,\n    0.0, 1.0, 0.0\n]);\n\nconst colors = new Float32Array([\n    1.0, 0.0, 0.0, \/\/ \ud83d\udd34\n    0.0, 1.0, 0.0, \/\/ \ud83d\udfe2\n    0.0, 0.0, 1.0  \/\/ \ud83d\udd35\n]);\n\nlet positionBuffer: WebGLBuffer = null;\nlet colorBuffer: WebGLBuffer = null;\n\nlet createBuffer = (arr) =&gt; {\n    let buf = gl.createBuffer();\n    let bufType =\n        arr instanceof Uint16Array || arr instanceof Uint32Array ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;\n\n    gl.bindBuffer(bufType, buf);\n\n    gl.bufferData(bufType, arr, gl.STATIC_DRAW);\n    return buf;\n};\n\npositionBuffer = createBuffer(positions);\ncolorBuffer = createBuffer(colors);\n<\/code><\/pre>\n<h3>Index Buffer Object\u7d22\u5f15\u7f13\u51b2\u533a\u5bf9\u8c61<\/h3>\n<p>\u7d22\u5f15\u7f13\u51b2\u533a\u5bf9\u8c61 (IBO) \u7528\u4e8e\u5236\u4f5c\u4e09\u89d2\u5f62\u3001\u76f4\u7ebf\u6216\u70b9\u7684\u9876\u70b9\u7d22\u5f15\u5217\u8868\u3002\u5728\u6e32\u67d3\u4e00\u7ec4\u4e09\u89d2\u5f62\u65f6\uff0c\u7d22\u5f15\u7f13\u51b2\u533a\u5141\u8bb8\u5c06\u7ed9\u5b9a\u7684\u9876\u70b9\u91cd\u7528\u4e8e\u4e0d\u540c\u7684\u4e09\u89d2\u5f62\u3002<\/p>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/webgpubase4.png\" alt=\"Webgpu\u57fa\u7840\" \/><\/p>\n<pre><code class=\"language-javascript line-numbers\">const indices = new Uint16Array([ 0, 1, 2 ]);\n\nlet indexBuffer: WebGLBuffer = null;\n\nindexBuffer = createBuffer(indices);\n<\/code><\/pre>\n<p>\u6ce8\u610f16\u4f4dUint16Array\u6bd432\u4f4dUint32Array\u5feb\u3002<\/p>\n<h3>Vertex Shader\u9876\u70b9\u7740\u8272\u5668<\/h3>\n<p>\u9876\u70b9\u7740\u8272\u5668\u662f\u4e00\u4e2a GPU \u7a0b\u5e8f\uff0c\u5728\u7ed8\u5236\u7684\u6bcf\u4e2a\u9876\u70b9\u4e0a\u6267\u884c\u3002<\/p>\n<pre><code class=\"language-javascript line-numbers\">attribute vec3 inPosition;\nattribute vec3 inColor;\nvarying vec3 vColor;\nvoid main()\n{\n    vColor = inColor;\n    gl_Position = vec4(inPosition, 1.0);\n}\n<\/code><\/pre>\n<p>\u521b\u5efa\u9876\u70b9\u7740\u8272\u5668\uff1a<\/p>\n<pre><code class=\"language-javascript line-numbers\">let vertModule: WebGLShader = null;\n\nconst vertShaderCode = `\nattribute vec3 inPosition;\nattribute vec3 inColor;\nvarying vec3 vColor;\nvoid main()\n{\n    vColor = inColor;\n    gl_Position = vec4(inPosition, 1.0);\n}\n`;\n\nlet createShader = (source: string, stage) =&gt; {\n\n    let s = gl.createShader(stage);\n\n    gl.shaderSource(s, source);\n\n    gl.compileShader(s);\n\n    if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {\n        console.error('An error occurred compiling the shader: ' + gl.getShaderInfoLog(s));\n    }\n    return s;\n};\nvertModule = createShader(vertShaderCode, gl.VERTEX_SHADER);\n<\/code><\/pre>\n<h3>Fragment Shader\u7247\u6bb5\u7740\u8272\u5668<\/h3>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/webgpubase5.png\" alt=\"Webgpu\u57fa\u7840\" \/><\/p>\n<pre><code class=\"language-javascript line-numbers\">precision mediump float;\nvarying highp vec3 vColor;\nvoid main()\n{\n    gl_FragColor = vec4(vColor, 1.0);\n}\n<\/code><\/pre>\n<p>\u521b\u5efa\u7247\u6bb5\u7740\u8272\u5668\uff1a<\/p>\n<pre><code class=\"language-javascript line-numbers\">let fragModule: WebGLShader = null;\n\nconst fragShaderCode = `\nprecision mediump float;\nvarying highp vec3 vColor;\nvoid main()\n{\n    gl_FragColor = vec4(vColor, 1.0);\n}\n`;\n\nfragModule = createShader(fragShaderCode, gl.FRAGMENT_SHADER);\n<\/code><\/pre>\n<p>\u7740\u8272\u5668\u6709\u5f88\u591a\u79cd\uff0c\u53ef\u4ee5\u67e5\u770b<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/alain.xyz\/blog\/a-review-of-shader-languages\">\u8fd9\u91cc<\/a><\/p>\n<h3>Shader Program\u7740\u8272\u5668\u7a0b\u5e8f<\/h3>\n<p>Shader Program\u5c06\u9876\u70b9\u7740\u8272\u5668\u548c\u7247\u6bb5\u7740\u8272\u5668\u7ed1\u5b9a\u5728\u4e00\u8d77\uff0c\u5e76\u5c06\u5b83\u4eec\u8bbe\u7f6e\u5728 WebGL \u72b6\u6001\u673a\u4e2d\u4f7f\u7528\u3002<\/p>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/webglbase3.png\" alt=\"Webgpu\u57fa\u7840\" \/><\/p>\n<pre><code class=\"language-javascript line-numbers\">let program: WebGLProgram = null;\n\nlet createProgram = (stages: WebGLShader[]) =&gt; {\n    let p = gl.createProgram();\n    for (let stage of stages) {\n        gl.attachShader(p, stage);\n    }\n    gl.linkProgram(p);\n    return p;\n};\nprogram = createProgram([vertModule, fragModule]);\n<\/code><\/pre>\n<h3>Uniforms\u8054\u5408\u7a0b\u5e8f<\/h3>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/webglbase2.png\" alt=\"Webgpu\u57fa\u7840\" \/><\/p>\n<p>Uniform\u662f\u8fde\u901aCPU\u548cGPU\u7684\u6865\u6881\uff0c\u9700\u8981\u5728\u7740\u8272\u5668\u4e2d\u58f0\u660e\uff1a<\/p>\n<pre><code class=\"language-javascript line-numbers\">uniform vec4 uColor;\n<\/code><\/pre>\n<p>\u5e76\u6267\u884c\u4ee5\u4e0b\u64cd\u4f5c\u5c06\u8bf7\u6c42\u7684\u6570\u636e\u53d1\u9001\u5230\u7740\u8272\u5668\uff1a<\/p>\n<pre><code class=\"language-javascript line-numbers\">let color = new Float32Array([0.5, 0.5, 0.5, 1.0]);\n\nlet uniformLocation = gl.getUniformLocation(program, 'uColor');\n\ngl.uniform4v(uniformLocation, color);\n<\/code><\/pre>\n<h3>Textures\u7eb9\u7406<\/h3>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/webglbase1.png\" alt=\"Webgpu\u57fa\u7840\" \/><\/p>\n<pre><code class=\"language-javascript line-numbers\">function loadTexture(url: string) {\n    let tex = gl.createTexture();\n    gl.bindTexture(gl.TEXTURE_2D, tex);\n    const pixel = new Uint8Array([ 255, 255, 255, 255 ]);\n    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixel);\n    let img = new Image();\n    img.src = url;\n    img.onload = () =&gt; {\n        gl.bindTexture(gl.TEXTURE_2D, tex);\n        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\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    };\n    return tex;\n}\n<\/code><\/pre>\n<p>\u521b\u5efa\u540e\u624d\u53ef\u8bbf\u95ee<\/p>\n<pre><code class=\"language-javascript line-numbers\">uniform sampler2D tAlbedo;\n<\/code><\/pre>\n<p>\u5e76\u53d1\u9001\u5230\u7740\u8272\u5668\uff1a<\/p>\n<pre><code class=\"language-javascript line-numbers\">let fragAlbedoUniform: number = -1;\n\nfragAlbedoUniform =\n    gl.getUniformLocation(program, \"tAlbedo\");\n\ngl.activeTexture(gl.TEXTURE0);\n\ngl.bindTexture(gl.TEXTURE_2D, tAlbedo);\n\ngl.uniform1i(fragAlbedoUniform, 0);\n<\/code><\/pre>\n<h3>Rendering\u6e32\u67d3<\/h3>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/webgpubase11.gif\" alt=\"Webgpu\u57fa\u7840\" \/><\/p>\n<pre><code class=\"language-javascript line-numbers\">let animationHandler: number = 0;\n\nconst render = () =&gt; {\n\n    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\n    gl.useProgram(program);\n    gl.viewport(0, 0, canvas.width, canvas.height);\n    gl.scissor(0, 0, canvas.width, canvas.height);\n\n    let setVertexBuffer = (buf: WebGLBuffer, name: string) =&gt; {\n        gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n        let loc = gl.getAttribLocation(program, name);\n        gl.vertexAttribPointer(loc, 3, gl.FLOAT, false, 4 * 3, 0);\n        gl.enableVertexAttribArray(loc);\n    };\n    setVertexBuffer(positionBuffer, 'inPosition');\n    setVertexBuffer(colorBuffer, 'inColor');\n    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n    gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0);\n\n    animationHandler = requestAnimationFrame(render);\n};\n\ninitializeAPI();\ninitializeResources();\nrender();\n<\/code><\/pre>\n<h3>Destroy\u9500\u6bc1<\/h3>\n<p>\u867d\u7136\u6d4f\u89c8\u5668\u91cc\u7684JS\u6709GC\u673a\u5236\uff0c\u4f46\u662f\u3002\u3002\u3002<\/p>\n<pre><code class=\"language-javascript line-numbers\">function destroyResources()\n{\n  gl.deleteBuffer(positionBuffer);\n  gl.deleteBuffer(colorBuffer);\n  gl.deleteBuffer(indexBuffer);\n  gl.deleteShader(vertModule);\n  gl.deleteShader(fragModule);\n  gl.deleteProgram(program);\n}\n<\/code><\/pre>\n<p>code enjoy! \ud83d\udc3e\ud83d\udc3e\ud83d\udc3e\ud83d\udc3e\ud83d\udc3e\ud83d\udc3e\ud83d\udc3e\ud83d\udc3e\ud83d\udc0c\ud83d\udc1d<\/p>\n<p>\u4f5c\u8005\uff1aindeex<\/p>\n<p>\u94fe\u63a5\uff1a<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/indeex.club\/\">https:\/\/indeex.club<\/a><\/p>\n<p>\u8457\u4f5c\u6743\u5f52\u4f5c\u8005\u6240\u6709\u3002\u5546\u4e1a\u8f6c\u8f7d\u8bf7\u8054\u7cfb\u4f5c\u8005\u83b7\u5f97\u6388\u6743\uff0c\u975e\u5546\u4e1a\u8f6c\u8f7d\u8bf7\u6ce8\u660e\u51fa\u5904\u3002<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>\u7531\u4e8eWebGl\u6280\u672f\u8f83\u4e3a\u6210\u719f\uff0c\u8fd9\u91cc\u4e0d\u518d\u8d58\u8ff0\u3002 \u8d44\u6e90\u521d\u59cb\u5316 let canvas: HTMLCanvas<a href=\"https:\/\/blog.indeex.club\/index.php\/2021\/07\/22\/webgl%e5%9f%ba%e7%a1%80\/\" class=\"read-more\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts\/233"}],"collection":[{"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/comments?post=233"}],"version-history":[{"count":1,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts\/233\/revisions"}],"predecessor-version":[{"id":234,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts\/233\/revisions\/234"}],"wp:attachment":[{"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/media?parent=233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/categories?post=233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/tags?post=233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}