{"id":270,"date":"2022-03-04T23:48:09","date_gmt":"2022-03-04T15:48:09","guid":{"rendered":"https:\/\/blog.indeex.club\/?p=270"},"modified":"2022-03-30T21:12:32","modified_gmt":"2022-03-30T13:12:32","slug":"webgpu%e5%9f%ba%e7%a1%80%ef%bc%88%e4%b8%89%ef%bc%89-%e5%9c%ba%e6%99%af%e5%92%8c%e7%9b%b8%e6%9c%ba","status":"publish","type":"post","link":"https:\/\/blog.indeex.club\/index.php\/2022\/03\/04\/webgpu%e5%9f%ba%e7%a1%80%ef%bc%88%e4%b8%89%ef%bc%89-%e5%9c%ba%e6%99%af%e5%92%8c%e7%9b%b8%e6%9c%ba\/","title":{"rendered":"WebGPU\u57fa\u7840\uff08\u4e09\uff09-\u573a\u666f\u548c\u76f8\u673a"},"content":{"rendered":"<h2>\u7269\u4f53<\/h2>\n<p>\u5728\u5f15\u64ce\u5f00\u53d1\u4e2d\uff0c\u6211\u4eec\u4f1a\u6dfb\u52a0\u4e00\u4e2a\u4e00\u4e2a\u7684\u573a\u666f\uff0c\u7136\u540e\u4f7f\u7528\u4e0d\u540c\u7684\u76f8\u673a\u67e5\u770b\u4e0d\u540c\u7684\u7269\u4f53\u3002<\/p>\n<p>\u9996\u5148\u7269\u4f53\u7684\u751f\u6210\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\nimport { mat4, vec3 } from &#039;gl-matrix&#039;;\nimport fragShaderCode from &#039;.\/shaders\/triangle.frag.wgsl?raw&#039;;\nimport vertexShadowCode from &#039;.\/shaders\/triangle.vert.wgsl?raw&#039;;\n\n\/\/...\n\nconstructor(device: GPUDevice, verticesArray: Float32Array, vertexCount: number, parameter?: RenderObjectParameter) {\n    this.vertexCount = vertexCount;\n    this.renderPipeline = device.createRenderPipeline({\n        vertex: {\n            module: device.createShaderModule({\n                code: wgslShaders.vertex,\n            }),\n            entryPoint: &#039;main&#039;,\n            buffers: [\n                {\n                    arrayStride: vertexSize,\n                    attributes: [\n                        {\n                            shaderLocation: 0,\n                            offset: positionOffset,\n                            format: &#039;float32x4&#039;,\n                        },\n                        {\n                            shaderLocation: 1,\n                            offset: colorOffset,\n                            format: &#039;float32x4&#039;,\n                        },\n                    ],\n                } as GPUVertexBufferLayout,\n            ],\n        },\n        fragment: {\n            module: device.createShaderModule({\n                code: wgslShaders.fragment,\n            }),\n            entryPoint: &#039;main&#039;,\n            targets: [\n                {\n                    format: &#039;bgra8unorm&#039; as GPUTextureFormat,\n                },\n            ],\n        },\n        primitive: {\n            topology: &#039;triangle-list&#039;,\n            cullMode: &#039;back&#039;,\n        },\n        depthStencil: {\n            depthWriteEnabled: true,\n            depthCompare: &#039;less&#039;,\n            format: &#039;depth24plus-stencil8&#039;,\n        },\n    });\n\n    this.uniformBuffer = device.createBuffer({\n        size: this.uniformBufferSize,\n        usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n    });\n\n    this.uniformBindGroup = device.createBindGroup({\n        layout: this.renderPipeline.getBindGroupLayout(0),\n        entries: [\n            {\n                binding: 0,\n                resource: {\n                    buffer: this.uniformBuffer,\n                    offset: 0,\n                    size: this.matrixSize,\n                },\n            },\n        ],\n    });\n\n    this.verticesBuffer = device.createBuffer({\n        size: verticesArray.byteLength,\n        usage: GPUBufferUsage.VERTEX,\n        mappedAtCreation: true,\n    });\n    new Float32Array(this.verticesBuffer.getMappedRange()).set(verticesArray);\n    this.verticesBuffer.unmap();\n\n    this.setTransformation(parameter);\n}\n\n\/\/...<\/code><\/pre>\n<p>\u7136\u540e\u662f\u7269\u4f53\u7684\u4f4d\u7f6e\u548c\u89d2\u5ea6\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\nprivate setTransformation(parameter?: RenderObjectParameter) {\n    if (parameter == null) {\n        return;\n    }\n\n    this.x = parameter.x ? parameter.x : 0;\n    this.y = parameter.y ? parameter.y : 0;\n    this.z = parameter.z ? parameter.z : 0;\n\n    this.rotX = parameter.rotX ? parameter.rotX : 0;\n    this.rotY = parameter.rotY ? parameter.rotY : 0;\n    this.rotZ = parameter.rotZ ? parameter.rotZ : 0;\n}\n\n\/\/...<\/code><\/pre>\n<p>\u63a5\u7740\u662f\u7269\u4f53\u7684\u7ed8\u5236\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\nthis.updateTransformationMatrix(camera.getCameraViewProjMatrix())\n\npassEncoder.setPipeline(this.renderPipeline);\ndevice.queue.writeBuffer(\n    this.uniformBuffer,\n    0,\n    this.modelViewProjectionMatrix.buffer,\n    this.modelViewProjectionMatrix.byteOffset,\n    this.modelViewProjectionMatrix.byteLength\n);\npassEncoder.setVertexBuffer(0, this.verticesBuffer);\npassEncoder.setBindGroup(0, this.uniformBindGroup);\npassEncoder.draw(this.vertexCount, 1, 0, 0);\n\n\/\/...<\/code><\/pre>\n<p>\u63a5\u7740\u662f\u7269\u4f53\u7684\u66f4\u65b0\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\nconst modelMatrix = mat4.create();\nmat4.translate(modelMatrix, modelMatrix, vec3.fromValues(this.x, this.y, this.z))\nmat4.rotateX(modelMatrix, modelMatrix, this.rotX);\nmat4.rotateY(modelMatrix, modelMatrix, this.rotY);\nmat4.rotateZ(modelMatrix, modelMatrix, this.rotZ);\n\nmat4.multiply(this.modelViewProjectionMatrix, cameraProjectionMatrix, modelMatrix);\n\n\/\/...<\/code><\/pre>\n<p>\u63a5\u7740\u5c31\u53ef\u4ee5\u751f\u6210\u7269\u4f53\u4e86\ud83d\ude04\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\npublic static cube(parameter?: RenderObjectParameter): IObject {\n    return new IObject(device, cubeVertexArray, cubeVertexCount, parameter)\n}\n\npublic static pyramid(parameter?: RenderObjectParameter): IObject {\n    return new IObject(device, triangleVertexArray, triangleVertexCount, parameter)\n}\n\n\/\/...<\/code><\/pre>\n<p>\u8fd9\u91cc\u9700\u8981\u7528\u5230<strong>device<\/strong>\uff0c\u521b\u5efa\u4e00\u4e2acommon\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/*\n * @Author: indeex\n * @Date: 2021-03-01 19:58:41\n * @Email: indeex@qq.com\n *\/\nexport let device:GPUDevice;\nexport function setDevice(_device: GPUDevice) {\n    device = _device;\n}<\/code><\/pre>\n<p>\u5728engine\u4e2d\u8bbe\u7f6e\u540e\uff0c\u5c31\u53ef\u4ee5\u5728\u5176\u4ed6\u5730\u65b9\u4f7f\u7528\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\nlet _device = await this.adapter.requestDevice();\nsetDevice(_device);\n\n\/\/...<\/code><\/pre>\n<p>\u8fd8\u6709Shader\uff0c\u8fd9\u91cc\u4f7f\u7528<strong>WGSL<\/strong>\uff1a<\/p>\n<p>\u9876\u70b9\u7740\u8272\u5668vert:<\/p>\n<pre><code class=\"language-javascript\">struct Uniforms {\n    modelViewProjectionMatrix : mat4x4&lt;f32&gt;;\n  };\n\n  @binding(0) @group(0) var&lt;uniform&gt; uniforms : Uniforms;\n\n  struct VertexOutput {\n    @builtin(position) Position : vec4&lt;f32&gt;;\n    @location(0) fragColor : vec4&lt;f32&gt;;\n  };\n\n  @stage(vertex)\n  fn main(@location(0) position : vec4&lt;f32&gt;,\n          @location(1) color : vec4&lt;f32&gt;) -&gt; VertexOutput {\n    return VertexOutput(uniforms.modelViewProjectionMatrix * position, color);\n  }<\/code><\/pre>\n<p>\u7247\u6bb5\u7740\u8272\u5668\uff08\u50cf\u7d20\u7740\u8272\u5668\uff09frag:<\/p>\n<pre><code class=\"language-javascript\">@stage(fragment)\n  fn main(@location(0) fragColor : vec4&lt;f32&gt;) -&gt; @location(0) vec4&lt;f32&gt; {\n    return fragColor;\n  }<\/code><\/pre>\n<h2>\u76f8\u673a<\/h2>\n<p>\u7136\u540e\u662f\u76f8\u673a\u7684\u8bbe\u7f6e\uff0c\u76f8\u673a\u662f\u8ddf\u968f\u7269\u4f53\u7684\uff0c\u6240\u4ee5\u8ddf\u7269\u4f53\u662f\u76f8\u5bf9\u7684\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/*\n * @Author: indeex\n * @Date: 2021-03-01 19:14:17\n * @Email: indeex@qq.com\n *\/\nimport { mat4, vec3 } from &#039;gl-matrix&#039;;\n\nexport class Camera {\n\n    public x: number = 0;\n    public y: number = 0;\n    public z: number = 0;\n\n    public rotX: number = 0;\n    public rotY: number = 0;\n    public rotZ: number = 0;\n\n    public fovy: number = (2 * Math.PI) \/ 5;\n    public aspect: number = 16 \/ 9;\n\n    public near: number = 1;\n    public far: number = 1000;\n\n    constructor (aspect: number) {\n        this.aspect = aspect;\n    }\n\n    public getViewMatrix () : mat4 {\n        let viewMatrix = mat4.create();\n\n        mat4.lookAt(viewMatrix, vec3.fromValues(this.x, this.y, this.z), vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));\n\n        mat4.rotateX(viewMatrix, viewMatrix, this.rotX);\n        mat4.rotateY(viewMatrix, viewMatrix, this.rotY);\n        mat4.rotateZ(viewMatrix, viewMatrix, this.rotZ);\n        return viewMatrix;\n    }\n\n    public getProjectionMatrix () : mat4 {\n        let projectionMatrix = mat4.create();\n        mat4.perspective(projectionMatrix, this.fovy, this.aspect, this.near, this.far);\n        return projectionMatrix;\n    }\n\n    public getCameraViewProjMatrix () : mat4 {\n        const viewProjMatrix = mat4.create();\n        const view = this.getViewMatrix();\n        const proj = this.getProjectionMatrix();\n        mat4.multiply(viewProjMatrix, proj, view);\n        return viewProjMatrix;\n    }\n}<\/code><\/pre>\n<h2>\u573a\u666f<\/h2>\n<p>\u573a\u666f\u53ef\u4ee5\u7406\u89e3\u4e3a\u88c5\u7269\u4f53\u7684\u4e00\u95f4\u95f4\u65e0\u9650\u5927\u7684\u5c4b\u5b50\uff0c\u4e5f\u53ef\u4ee5\u5728\u521d\u59cb\u65f6\u89c4\u5b9a\u5c4b\u5b50\u7684\u5927\u5c0f\uff0c\u5728\u4ee5\u524d\u7684Flash\u65f6\u4ee3\u4e0d\u7ba1\u662f2D\u8fd8\u662f3D\uff0c\u573a\u666f\u90fd\u662f\u6700\u5e38\u7528\u7684\uff0c\u6bd4\u5982\u6700\u5e38\u7528\u7684Sprit\uff0c\u8fd8\u6709\u88c5\u4e86\u65e0\u6570\u5c0fSprit\u7684Moveclip\u7ec4\u6210\u7684\u753b\u9762\u7b49\uff1a<\/p>\n<pre><code class=\"language-typescript\">\/\/...\n\nexport class Scene {\n\n    private objects: IObject[] = [];\n\n    public add (object: IObject) {\n        this.objects.push(object);\n    }\n\n    public getObjects () : IObject[] {\n        return this.objects;\n    }\n}\n\n\/\/...<\/code><\/pre>\n<h2>Engine<\/h2>\n<p>\u628a\u4e4b\u524d\u7684\u4ee3\u7801\u5c01\u88c5\u6210Engine\uff0c\u5f15\u64ce\u8d1f\u8d23\u66f4\u65b0\u6e32\u67d3\u6bcf\u4e00\u5e27\uff1a<\/p>\n<pre><code class=\"language-typescript\">export default class Engine {\n    constructor() {}\n\n    \/\/...\n\n    update() {\n        (this.renderPassDescriptor!.depthStencilAttachment as GPURenderPassDepthStencilAttachment).view = this.depthTextureView();\n    }\n\n    frame(camera: Camera, scene: Scene) {\n        (this.renderPassDescriptor!.colorAttachments as [GPURenderPassColorAttachment])[0].view = this.context!\n            .getCurrentTexture()\n            .createView();\n\n        const commandEncoder = device!.createCommandEncoder();\n        const passEncoder = commandEncoder.beginRenderPass((this.renderPassDescriptor as any));\n\n        for (let object of scene.getObjects()) {\n            object.draw(passEncoder, (device as any), camera)\n        }\n\n        passEncoder.end();\n        device!.queue.submit([commandEncoder.finish()]);\n    }\n\n    \/\/...\n}<\/code><\/pre>\n<h2>\u63a7\u5236<\/h2>\n<p>\u7136\u540e\u901a\u8fc7\u952e\u76d8\u3001\u624b\u52bf\u3001\u9f20\u6807\u7b49\u63a7\u5236\uff1a<\/p>\n<pre><code class=\"language-typescript\">canvas.onwheel = (e: WheelEvent) =&gt; {\n    camera.z += e.deltaY \/ 100\n}\n\nvar mouseDown = false;\ncanvas.onmousedown = (e: MouseEvent) =&gt; {\n    if (e.button !== 0) return;\n    mouseDown = true;\n\n    lastMouseX = e.pageX;\n    lastMouseY = e.pageY;\n}\ncanvas.onmouseup = (e: MouseEvent) =&gt; {\n    mouseDown = false;\n}\nvar lastMouseX = -1;\nvar lastMouseY = -1;\ncanvas.onmousemove = (e: MouseEvent) =&gt; {\n    if (!mouseDown) {\n    return;\n    }\n\n    var mousex = e.pageX;\n    var mousey = e.pageY;\n\n    if (lastMouseX &gt; 0 &amp;&amp; lastMouseY &gt; 0) {\n    const roty = mousex - lastMouseX;\n    const rotx = mousey - lastMouseY;\n\n    camera.rotY += roty \/ 100;\n    camera.rotX += rotx \/ 100;\n    }\n\n    lastMouseX = mousex;\n    lastMouseY = mousey;\n}<\/code><\/pre>\n<p>\u8fd9\u91cc\u4f8b\u5b50\u53ea\u7528\u5230\u4e86\u7acb\u65b9\u4f53\u548c\u9525\u4f53\uff0c\u8fd8\u6709\u5f88\u591a\u5176\u4ed6\u7684\u7269\u4f53\uff0c\u53ef\u4ee5\u53c2\u8003W3C\u7684<a href=\"https:\/\/www.w3.org\/TR\/webgpu\/\">\u5b98\u65b9\u6587\u6863<\/a>\u81ea\u884c\u8bbe\u7f6e\u3002<\/p>\n<p>\u6548\u679c\u9884\u89c8\u5730\u5740\uff1a<\/p>\n<p><a href=\"https:\/\/hungking.org\/webgpu-wgsl-example\/#\/part9\">\u573a\u666f\u548c\u76f8\u673a<\/a><\/p>\n<p><img src=\"https:\/\/hungking.cc\/assets\/imgs\/indeex.cc\/WebGPUWGSLbase2.gif\" alt=\"\u573a\u666f\u548c\u76f8\u673a\" \/><\/p>\n<p>code enjoy! \ud83e\udd96\ud83e\udd96\ud83e\udd96<\/p>\n<p>\u4f5c\u8005\uff1aindeex  <\/p>\n<p>\u94fe\u63a5\uff1a<a 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","protected":false},"excerpt":{"rendered":"<p>\u7269\u4f53 \u5728\u5f15\u64ce\u5f00\u53d1\u4e2d\uff0c\u6211\u4eec\u4f1a\u6dfb\u52a0\u4e00\u4e2a\u4e00\u4e2a\u7684\u573a\u666f\uff0c\u7136\u540e\u4f7f\u7528\u4e0d\u540c\u7684\u76f8\u673a\u67e5\u770b\u4e0d\u540c\u7684\u7269\u4f53\u3002 \u9996\u5148\u7269\u4f53\u7684\u751f\u6210\uff1a <a href=\"https:\/\/blog.indeex.club\/index.php\/2022\/03\/04\/webgpu%e5%9f%ba%e7%a1%80%ef%bc%88%e4%b8%89%ef%bc%89-%e5%9c%ba%e6%99%af%e5%92%8c%e7%9b%b8%e6%9c%ba\/\" 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":[10],"tags":[15],"_links":{"self":[{"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts\/270"}],"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=270"}],"version-history":[{"count":3,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts\/270\/revisions"}],"predecessor-version":[{"id":282,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/posts\/270\/revisions\/282"}],"wp:attachment":[{"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/media?parent=270"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/categories?post=270"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.indeex.club\/index.php\/wp-json\/wp\/v2\/tags?post=270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}