WebGPU05-Begin-The Pipeline,着色器准备!


Begin | WebGPU

3.The Pipeline-1

译者注:建议在学习本节时打开对应的Github代码库进行对比学习

LearnWgpu项目代码库

  • 什么是Pipeline?

    如果你对 OpenGL 比较熟悉,你可能还记得使用 shader(着色器) 的时候。

    你可以将 pipeline(传递通道)理解为一个更加健壮的 shader(着色器)。一个 传递通道 描述了 显卡 在对一组数据进行操作时将执行的所有操作。

    在这一部分,我们将具体的创建一个RenderPipeline

  • 等等,shader是啥 ? _ ?

    着色器是发送至 GPU 以对数据执行操作的小程序。

    着色器 主要有三种类型:vertex(顶点)、fragment(片段)、compute(计算)。

    当然还有其他类型例如 geometry shader(几何着色器),但它们更加高级,现在我们只需要了解三种主要类型。

  • 那 vertex、fragment 这些是...

    一个 顶点 是3D空间中的一个点(也适用于2D)。然后将这些 顶点 捆绑成 2组以形成线 或 3组以形成三角形。

    顶点

    大多数现代渲染均使用三角形来作所有形状,从 简单形状(如立方体)到 复杂形状(如人)。这些三角形以 顶点 的形式存储起来,这些 顶点 构成了三角形角的点。

    为了将形状转换为我们想要的样子,我们使用 vertex shader(顶点渲染)来操作 顶点。

    之后我们将 顶点 转换为 片段。每一个结果图中的像素都会有至少一个 片段。而每一个 片段 都有一种颜色,该颜色将被复制到其对应的像素。fragment shader(片段着色器)决定了我们的 片段 将会变成什么颜色。

  • WGSL(WebGPU Shading Language)

    WGSL 是 WebGPU 的 shader language(着色器语言)。
    WGSL 的开发重点是让它能够轻松转换成后端对应的着色器语言。
    例如,SPIR-V 用于 Vlukan,MSL 用于 Metal,HLSL 用于 DX12,GLSL 用于 OpenGL。
    转换完成于内部,通常我们无需关注其细节。
    在 wgpu 种,转换由库 naga 所完成。

    注意:在我写下这篇向导的时候,一些 WebGPU 的实现尚且支持 SPIR-V,但这只是向 WGSL 过渡期间的临时举措,它将在不久后被删除。(如果你对 SPIR-V 和 WGSL 背后的剧情感兴趣,请参阅此博文:Horrors of SRIR-V)

    此处不译,与此向导历史版本有关,可考虑查看

    If you've gone through this tutorial before you'll likely notice that I've switched from using GLSL to using WGSL. Given that GLSL support is a secondary concern and that WGSL is the first class language of WGPU, I've elected to convert all the tutorials to use WGSL. Some showcase examples still use GLSL, but the main tutorial and all examples going forward will be using WGSL.

    The WGSL spec and it's inclusion in WGPU is still in development. If you run into trouble using it, you may want the folks at https://app.element.io/#/room/#wgpu:matrix.orgto take a look at your code.

  • 编写着色器

    1. 顶点着色器

      main.rs的同级目录下,新建文件shader.wgsl,将下列代码写入文件shader.wgsl

      // Vertex shader
      
      struct VertexOutput {
          [[builtin(position)]] clip_position: vec4;
      };
      
      [[stage(vertex)]]
      fn vs_main(
          [[builtin(vertex_index)]] in_vertex_index: u32,
      ) -> VertexOutput {
          var out: VertexOutput;
          let x = f32(1 - i32(in_vertex_index)) * 0.5;
          let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
          out.clip_position = vec4(x, y, 0.0, 1.0);
          return out;
      }
      

      在上述代码中,首先我们声明了一个struct用于存储我们的顶点着色器(vertex shader)的输出。

      现在此唯一域的组成是我们顶点的clip_position(剪辑位置)[[builtin(position)]]块告诉 WGPU 这是我们想要用作 顶点剪辑坐标(vertex's clip coordinates) 的值。

      这与 GLSL 的gl_Position变量相似。

      此处不译,但需要查看

      Vector types such as vec4 are generic. Currently, you must specify the type of value the vector will contain. Thus, a 3D vector using 32bit floats would be vec3.

      着色器代码中的下一部分是vs_main函数。

      我们使用[[stage(vertex)]]来标记此函数作为 顶点着色器 的有效入口点。期望一个名为in_vertext_indexu32类型从[[builtin(vertex_index)]]获取它的值。

      之后我们声明一个名为out的变量来使用我们的VertexOutput结构。又创造了两个其他的变量用于一个三角形的xy

      此处不译,但需要查看

      The f32() and i32() bits are examples of casts.

      Variables defined with var can be modified, but must specify their type. Variables created with let can have their types inferred, but their value cannot be changed during the shader.

      现在我们可以将我们的clip_position存入out。之后我们只需返回out,这样就完成了 顶点着色器!

      此处不译,但需要查看

      We technically didn't need a struct for this example, and could have just done something like the following:

      [[stage(vertex)]]
      fn vs_main(
      [[builtin(vertex_index)]] in_vertex_index: u32
      ) -> [[builtin(position)]] vec4 {
      // Vertex shader code...
      }
      
        Copied!
      

      We'll be adding more fields to VertexOutput later, so we might as well start using it now.

    2. 片段着色器

      接下来让我们配置 片段着色器。

      仍然在shader.wgsl中添加下列代码:

      // Fragment shader
      
      [[stage(fragment)]]
      fn fs_main(in: VertexOutput) -> [[location(0)]] vec4 {
          return vec4(0.3, 0.2, 0.1, 1.0);
      }
      

      这会使当前片段的颜色设置为棕色。

      此处不译,注意查看

      Notice that the entry point for the vertex shader was named vs_main and that the entry point for the fragment shader is called fs_main. In earlier versions of wgpu it was ok to both name these functions the same, but newer versions of the WGSL spec (opens new window)require these names to be different. Therefore, the above mentioned naming scheme (which is adopted from the wgpu examples) is used throughout the tutorial.

      [[location(0)]]位 告诉 WGPU 将这个函数返回的vec4值存储在第一个颜色目标中。稍后我们再深入讨论。

该博客由本人个人翻译自Learn Wgpu,因此可能有部分文本不易理解或出现错误,如有发现还望告知,本人必定及时更改。