• 轻量封装WebGPU渲染系统示例<19>- 使用GPU Compute材质多pass实现元胞自动机之生命游戏(源码)


    当前示例源码github地址:

    https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/GameOfLifeMultiMaterialPass.ts

    系统特性:

    1. 用户态与系统态隔离。

             细节请见:引擎系统设计思路 - 用户态与系统态隔离-CSDN博客

    2. 基于算力驱动的系统设计。

    3. 高频调用与低频调用隔离。

    4. 面向用户的易用性封装。

    5. 渲染数据(内外部相关资源)和渲染机制分离。

    6. 用户操作和渲染系统调度并行机制。

    7. 数据/语义驱动。

    8. 异步并行的场景/模型载入。

    9. 保持computing与rendering机制一致性。

             1). 构造一致性。

             2). 使用一致性。

             3). 自动兼容materialmulti-pass、material graph、pass(pass node) graph机制。

    当前示例运行效果:

    此示例基于此渲染系统实现,当前示例TypeScript源码如下:

    1. const gridSize = 64;
    2. const shdWorkGroupSize = 8;
    3. const compShdCode = `
    4. @group(0) @binding(0) var grid: vec2f;
    5. @group(0) @binding(1) var cellStateIn: array;
    6. @group(0) @binding(2) var cellStateOut: array;
    7. fn cellIndex(cell: vec2u) -> u32 {
    8. return (cell.y % u32(grid.y)) * u32(grid.x) +
    9. (cell.x % u32(grid.x));
    10. }
    11. fn cellActive(x: u32, y: u32) -> u32 {
    12. return cellStateIn[cellIndex(vec2(x, y))];
    13. }
    14. @compute @workgroup_size(${shdWorkGroupSize}, ${shdWorkGroupSize})
    15. fn compMain(@builtin(global_invocation_id) cell: vec3u) {
    16. // Determine how many active neighbors this cell has.
    17. let activeNeighbors = cellActive(cell.x+1, cell.y+1) +
    18. cellActive(cell.x+1, cell.y) +
    19. cellActive(cell.x+1, cell.y-1) +
    20. cellActive(cell.x, cell.y-1) +
    21. cellActive(cell.x-1, cell.y-1) +
    22. cellActive(cell.x-1, cell.y) +
    23. cellActive(cell.x-1, cell.y+1) +
    24. cellActive(cell.x, cell.y+1);
    25. let i = cellIndex(cell.xy);
    26. // Conway's game of life rules:
    27. switch activeNeighbors {
    28. case 2: { // Active cells with 2 neighbors stay active.
    29. cellStateOut[i] = cellStateIn[i];
    30. }
    31. case 3: { // Cells with 3 neighbors become or stay active.
    32. cellStateOut[i] = 1;
    33. }
    34. default: { // Cells with < 2 or > 3 neighbors become inactive.
    35. cellStateOut[i] = 0;
    36. }
    37. }
    38. }`;
    39. export class GameOfLifeMultiMaterialPass {
    40. private mRscene = new RendererScene();
    41. initialize(): void {
    42. console.log("GameOfLifeMultiMaterialPass::initialize() ...");
    43. this.initScene();
    44. }
    45. private createUniformValues(): { ufvs0: WGRBufferData[]; ufvs1: WGRBufferData[] }[] {
    46. const gridsSizesArray = new Float32Array([gridSize, gridSize]);
    47. const cellStateArray0 = new Uint32Array(gridSize * gridSize);
    48. for (let i = 0; i < cellStateArray0.length; i++) {
    49. cellStateArray0[i] = Math.random() > 0.6 ? 1 : 0;
    50. }
    51. const cellStateArray1 = new Uint32Array(gridSize * gridSize);
    52. for (let i = 0; i < cellStateArray1.length; i++) {
    53. cellStateArray1[i] = i % 2;
    54. }
    55. let shared = true;
    56. let sharedData0 = { data: cellStateArray0, shared };
    57. let sharedData1 = { data: cellStateArray1, shared };
    58. const v0 = { data: gridsSizesArray, stride: 2, shared, layout: { visibility: 'all' } };
    59. // build rendering uniforms
    60. const va1 = { storage: { bufData: sharedData0, stride: 1, shared }, layout: { visibility: 'vert_comp' } };
    61. const vb1 = { storage: { bufData: sharedData1, stride: 1, shared }, layout: { visibility: 'vert_comp' } };
    62. // build computing uniforms
    63. const compva1 = { storage: { bufData: sharedData0, stride: 1, shared }, layout: { visibility: 'vert_comp' } };
    64. const compva2 = { storage: { bufData: sharedData1, stride: 1, shared }, layout: { visibility: 'comp', access: "read_write" } };
    65. const compvb1 = { storage: { bufData: sharedData1, stride: 1, shared }, layout: { visibility: 'vert_comp' } };
    66. const compvb2 = { storage: { bufData: sharedData0, stride: 1, shared, layout: { visibility: 'comp', access: "read_write" } } };
    67. return [
    68. { ufvs0: [v0, va1], ufvs1: [v0, vb1] },
    69. { ufvs0: [v0, compva1, compva2], ufvs1: [v0, compvb1, compvb2] }
    70. ];
    71. }
    72. private mEntity: FixScreenPlaneEntity;
    73. private mStep = 0;
    74. private createMaterial(shaderCodeSrc: WGRShderSrcType, uniformValues: WGRBufferData[], shadinguuid: string, instanceCount: number): WGMaterial {
    75. return new WGMaterial({
    76. shadinguuid,
    77. shaderCodeSrc,
    78. instanceCount,
    79. uniformValues
    80. });
    81. }
    82. private createCompMaterial(shaderCodeSrc: WGRShderSrcType, uniformValues: WGRBufferData[], shadinguuid: string, workgroupCount = 2): WGCompMaterial {
    83. return new WGCompMaterial({
    84. shadinguuid,
    85. shaderCodeSrc,
    86. uniformValues
    87. }).setWorkcounts(workgroupCount, workgroupCount);
    88. }
    89. private initScene(): void {
    90. const rc = this.mRscene;
    91. const ufvsObjs = this.createUniformValues();
    92. const instanceCount = gridSize * gridSize;
    93. const workgroupCount = Math.ceil(gridSize / shdWorkGroupSize);
    94. let shaderSrc = {
    95. code: shaderWGSL,
    96. uuid: "shader-shading",
    97. };
    98. let compShaderSrc = {
    99. code: compShdCode,
    100. uuid: "shader-computing"
    101. };
    102. const materials: WGMaterial[] = [
    103. // build ping-pong rendering process
    104. this.createMaterial(shaderSrc, ufvsObjs[0].ufvs0, "rshd0", instanceCount),
    105. this.createMaterial(shaderSrc, ufvsObjs[0].ufvs1, "rshd1", instanceCount),
    106. // build ping-pong computing process
    107. this.createCompMaterial(compShaderSrc, ufvsObjs[1].ufvs1, "compshd0", workgroupCount),
    108. this.createCompMaterial(compShaderSrc, ufvsObjs[1].ufvs0, "compshd1", workgroupCount),
    109. ];
    110. let entity = new FixScreenPlaneEntity({
    111. extent: [-0.8, -0.8, 1.6, 1.6],
    112. materials
    113. });
    114. rc.addEntity(entity);
    115. this.mEntity = entity;
    116. }
    117. private mFrameDelay = 3;
    118. run(): void {
    119. let rendering = this.mEntity.isRendering();
    120. if (rendering) {
    121. if (this.mFrameDelay > 0) {
    122. this.mFrameDelay--;
    123. return;
    124. }
    125. this.mFrameDelay = 3;
    126. const ms = this.mEntity.materials;
    127. for (let i = 0; i < ms.length; i++) {
    128. ms[i].visible = (this.mStep % 2 + i) % 2 == 0;
    129. }
    130. this.mStep++;
    131. }
    132. this.mRscene.run(rendering);
    133. }
    134. }

  • 相关阅读:
    自定义View绘制流程
    DJYOS开源往事二:DJYOS开源工作室时期
    Python算法——树的序列化与反序列化
    安装pangolin问题解决|找不到makefile
    达人评测i7 12700kf和i9 12900kf选哪个好
    网页加载有哪些事件
    【网页前端】CSS样式表入门概述以及基本语法格式和选择器
    SAP MM 关于事务代码VL04的一个测试 II
    设计模式总结
    mysql主从复制与读写分离
  • 原文地址:https://blog.csdn.net/vily_lei/article/details/134255424