• Google codelab WebGPU入门教程源码<5> - 使用Storage类型对象给着色器传数据(源码)


    对应的教程文章: 

    https://codelabs.developers.google.com/your-first-webgpu-app?hl=zh-cn#5

    对应的源码执行效果:

    对应的教程源码: 

    此处源码和教程本身提供的部分代码可能存在一点差异。运行的时候,点击画面可以切换效果。

    1. class Color4 {
    2. r: number;
    3. g: number;
    4. b: number;
    5. a: number;
    6. constructor(pr = 1.0, pg = 1.0, pb = 1.0, pa = 1.0) {
    7. this.r = pr;
    8. this.g = pg;
    9. this.b = pb;
    10. this.a = pa;
    11. }
    12. }
    13. export class WGPURStorage2 {
    14. private mRVertices: Float32Array = null;
    15. private mRPipeline: any | null = null;
    16. private mVtxBuffer: any | null = null;
    17. private mCanvasFormat: any | null = null;
    18. private mWGPUDevice: any | null = null;
    19. private mWGPUContext: any | null = null;
    20. private mUniformBindGroups: any | null = null;
    21. private mGridSize = 32;
    22. constructor() {}
    23. initialize(): void {
    24. const canvas = document.createElement("canvas");
    25. canvas.width = 512;
    26. canvas.height = 512;
    27. document.body.appendChild(canvas);
    28. console.log("ready init webgpu ...");
    29. this.initWebGPU(canvas).then(() => {
    30. console.log("webgpu initialization finish ...");
    31. this.updateWGPUCanvas();
    32. });
    33. document.onmousedown = (evt):void => {
    34. this.updateWGPUCanvas( new Color4(0.05, 0.05, 0.1) );
    35. }
    36. }
    37. private mUniformObj: any = {uniformArray: null, uniformBuffer: null};
    38. private createStorage(device: any): any {
    39. // Create an array representing the active state of each cell.
    40. const cellStateArray = new Uint32Array(this.mGridSize * this.mGridSize);
    41. // Create two storage buffers to hold the cell state.
    42. const cellStateStorage = [
    43. device.createBuffer({
    44. label: "Cell State A",
    45. size: cellStateArray.byteLength,
    46. usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
    47. }),
    48. device.createBuffer({
    49. label: "Cell State B",
    50. size: cellStateArray.byteLength,
    51. usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
    52. })
    53. ];
    54. // Mark every third cell of the first grid as active.
    55. for (let i = 0; i < cellStateArray.length; i+=3) {
    56. cellStateArray[i] = 1;
    57. }
    58. device.queue.writeBuffer(cellStateStorage[0], 0, cellStateArray);
    59. // Mark every other cell of the second grid as active.
    60. for (let i = 0; i < cellStateArray.length; i++) {
    61. cellStateArray[i] = i % 2;
    62. }
    63. device.queue.writeBuffer(cellStateStorage[1], 0, cellStateArray);
    64. return cellStateStorage;
    65. }
    66. private createUniform(device: any, pipeline: any): void {
    67. // Create a uniform buffer that describes the grid.
    68. const uniformArray = new Float32Array([this.mGridSize, this.mGridSize]);
    69. const uniformBuffer = device.createBuffer({
    70. label: "Grid Uniforms",
    71. size: uniformArray.byteLength,
    72. usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
    73. });
    74. device.queue.writeBuffer(uniformBuffer, 0, uniformArray);
    75. const cellStateStorage = this.createStorage(device);
    76. const bindGroups = [
    77. device.createBindGroup({
    78. label: "Cell renderer bind group A",
    79. layout: pipeline.getBindGroupLayout(0),
    80. entries: [
    81. {
    82. binding: 0,
    83. resource: { buffer: uniformBuffer }
    84. }, {
    85. binding: 1,
    86. resource: { buffer: cellStateStorage[0] }
    87. }
    88. ],
    89. }),
    90. device.createBindGroup({
    91. label: "Cell renderer bind group B",
    92. layout: pipeline.getBindGroupLayout(0),
    93. entries: [
    94. {
    95. binding: 0,
    96. resource: { buffer: uniformBuffer }
    97. }, {
    98. binding: 1,
    99. resource: { buffer: cellStateStorage[1] }
    100. }
    101. ],
    102. })
    103. ];
    104. this.mUniformBindGroups = bindGroups;
    105. const obj = this.mUniformObj;
    106. obj.uniformArray = uniformArray;
    107. obj.uniformBuffer = uniformBuffer;
    108. }
    109. private mStep = 0;
    110. private createRectGeometryData(device: any, pass: any): void {
    111. let vertices = this.mRVertices;
    112. let vertexBuffer = this.mVtxBuffer;
    113. let cellPipeline = this.mRPipeline;
    114. if(!cellPipeline) {
    115. let hsize = 0.8;
    116. vertices = new Float32Array([
    117. // X, Y,
    118. -hsize, -hsize, // Triangle 1 (Blue)
    119. hsize, -hsize,
    120. hsize, hsize,
    121. -hsize, -hsize, // Triangle 2 (Red)
    122. hsize, hsize,
    123. -hsize, hsize,
    124. ]);
    125. vertexBuffer = device.createBuffer({
    126. label: "Cell vertices",
    127. size: vertices.byteLength,
    128. usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
    129. });
    130. device.queue.writeBuffer(vertexBuffer, /*bufferOffset=*/0, vertices);
    131. const vertexBufferLayout = {
    132. arrayStride: 8,
    133. attributes: [{
    134. format: "float32x2",
    135. offset: 0,
    136. shaderLocation: 0, // Position, see vertex shader
    137. }],
    138. };
    139. const shaderCodes = `
    140. struct VertexInput {
    141. @location(0) pos: vec2f,
    142. @builtin(instance_index) instance: u32,
    143. };
    144. struct VertexOutput {
    145. @builtin(position) pos: vec4f,
    146. @location(0) cell: vec2f,
    147. };
    148. @group(0) @binding(0) var grid: vec2f;
    149. @group(0) @binding(1) var cellState: array;
    150. @vertex
    151. fn vertexMain(input: VertexInput) -> VertexOutput {
    152. let i = f32(input.instance);
    153. let cell = vec2f(i % grid.x, floor(i / grid.x));
    154. let cellOffset = cell / grid * 2;
    155. let state = f32(cellState[input.instance]);
    156. let gridPos = (input.pos * state + 1) / grid - 1 + cellOffset;
    157. var output: VertexOutput;
    158. output.pos = vec4f(gridPos, 0, 1);
    159. output.cell = cell;
    160. return output;
    161. }
    162. @fragment
    163. fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
    164. // return vec4f(input.cell, 0, 1);
    165. let c = input.cell/grid;
    166. return vec4f(c, 1.0 - c.x, 1);
    167. }
    168. `;
    169. const cellShaderModule = device.createShaderModule({
    170. label: "Cell shader",
    171. code: shaderCodes
    172. });
    173. cellPipeline = device.createRenderPipeline({
    174. label: "Cell pipeline",
    175. layout: "auto",
    176. vertex: {
    177. module: cellShaderModule,
    178. entryPoint: "vertexMain",
    179. buffers: [vertexBufferLayout]
    180. },
    181. fragment: {
    182. module: cellShaderModule,
    183. entryPoint: "fragmentMain",
    184. targets: [{
    185. format: this.mCanvasFormat
    186. }]
    187. },
    188. });
    189. this.mRVertices = vertices;
    190. this.mVtxBuffer = vertexBuffer;
    191. this.mRPipeline = cellPipeline;
    192. this.createUniform(device, cellPipeline);
    193. }
    194. pass.setPipeline(cellPipeline);
    195. pass.setVertexBuffer(0, vertexBuffer);
    196. // pass.setBindGroup(0, this.mUniformBindGroup);
    197. pass.setBindGroup(0, this.mUniformBindGroups[this.mStep % 2]);
    198. pass.draw(vertices.length / 2, this.mGridSize * this.mGridSize);
    199. this.mStep ++;
    200. }
    201. private updateWGPUCanvas(clearColor: Color4 = null): void {
    202. clearColor = clearColor ? clearColor : new Color4(0.05, 0.05, 0.1);
    203. const device = this.mWGPUDevice;
    204. const context = this.mWGPUContext;
    205. const rpassParam = {
    206. colorAttachments: [
    207. {
    208. clearValue: clearColor,
    209. // clearValue: [0.3,0.7,0.5,1.0], // yes
    210. view: context.getCurrentTexture().createView(),
    211. loadOp: "clear",
    212. storeOp: "store"
    213. }
    214. ]
    215. };
    216. const encoder = device.createCommandEncoder();
    217. const pass = encoder.beginRenderPass( rpassParam );
    218. this.createRectGeometryData(device, pass);
    219. pass.end();
    220. device.queue.submit([ encoder.finish() ]);
    221. }
    222. private async initWebGPU(canvas: HTMLCanvasElement) {
    223. const gpu = (navigator as any).gpu;
    224. if (gpu) {
    225. console.log("WebGPU supported on this browser.");
    226. const adapter = await gpu.requestAdapter();
    227. if (adapter) {
    228. console.log("Appropriate GPUAdapter found.");
    229. const device = await adapter.requestDevice();
    230. if (device) {
    231. this.mWGPUDevice = device;
    232. console.log("Appropriate GPUDevice found.");
    233. const context = canvas.getContext("webgpu") as any;
    234. const canvasFormat = gpu.getPreferredCanvasFormat();
    235. this.mWGPUContext = context;
    236. this.mCanvasFormat = canvasFormat;
    237. console.log("canvasFormat: ", canvasFormat);
    238. context.configure({
    239. device: device,
    240. format: canvasFormat,
    241. alphaMode: "premultiplied"
    242. });
    243. } else {
    244. throw new Error("No appropriate GPUDevice found.");
    245. }
    246. } else {
    247. throw new Error("No appropriate GPUAdapter found.");
    248. }
    249. } else {
    250. throw new Error("WebGPU not supported on this browser.");
    251. }
    252. }
    253. run(): void {}
    254. }

    切换后的效果:

  • 相关阅读:
    有意思网站合集2
    protobuf使用详解
    常识 | dds通信
    SQL Server 临时对象缓存
    VisionPro学习笔记(3)——BeadInspectTool
    OC-NSArray
    计算机网络-物理层
    【SpringBoot】之自动配置原理分析(源码级别)
    大数据毕设选题 - 生成对抗网络的照片上色动态算法设计与实现(深度学习 opencv python)
    R语言RSTAN MCMC:NUTS采样算法用LASSO 构建贝叶斯线性回归模型分析职业声望数据...
  • 原文地址:https://blog.csdn.net/vily_lei/article/details/134438950