regl-project / regl

👑 Functional WebGL
https://regl-project.github.io/
MIT License
5.23k stars 323 forks source link

Investigate WebGPU support #558

Open fuzhenn opened 4 years ago

fuzhenn commented 4 years ago

WebGPU is coming, although it's still in a early stage and needs years for wide supports, for sure now is the right time to do some investigations.

IMHO, with a simple and low level design, regl has the potential to migrate to WebGPU in a smooth way with few backward compatible API changes. And that would be a great news for all the regl users.

References:

fr-an-k commented 1 year ago

Looks like someone already made a WebGPU version of REGL: https://github.com/stackgpu/Simple-GPU

ruofeng618 commented 1 year ago

You can pay attention to GEngine, the engine provides a Model class that can be used for basic rendering packaging, very flexible and easy to use

example:

        <script type="module">
            import { Model, Context, Texture, RenderTarget, Attachment, Sampler } from "../../dist/index.js";
            import { mat4, vec3 } from "../lib/esm/index.js";
            import { cubeVertexArray, cubeVertexCount, uvs, colors, positions } from "../asset/cude.js";
            const init = async () => {
                const context = new Context({
                    canvas: null,
                    container: document.getElementById("app"),
                    pixelRatio: 1
                });
                const { canvas, presentationFormat } = context;
                await context.init();
                const { width, height, depth } = context.presentationSize;
                const colorAttachment = new Attachment(
                    { r: 0.0, g: 0.0, b: 0.0, a: 0 },
                    {
                        textureView: () => {
                            return context.context.getCurrentTexture().createView();
                        }
                    }
                );
                const response = await fetch(new URL("../textures/Di-3d.png", import.meta.url).toString());
                const imageBitmap = await createImageBitmap(await response.blob());
                const depthTexture = new Texture({
                    label: "resolveDepth",
                    size: { width, height, depth },
                    format: "depth24plus",
                    usage: GPUTextureUsage.RENDER_ATTACHMENT
                });
                const texture = new Texture({
                    size: {
                        width: imageBitmap.width,
                        height: imageBitmap.height,
                        depth: 1
                    },
                    format: "rgba8unorm",
                    usage:
                        GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
                    data: {
                        source: imageBitmap,
                        width: imageBitmap.width,
                        height: imageBitmap.height
                    }
                });
                const sampler = new Sampler({
                    magFilter: "linear",
                    minFilter: "linear"
                    // addressModeU: "repeat",
                    // addressModeV: "repeat"
                });
                const depthAttachment = new Attachment(1.0, { texture: depthTexture });
                const canvasRenderTarget = new RenderTarget("render", [colorAttachment], depthAttachment);
                const aspect = canvas.width / canvas.height;
                const projectionMatrix = mat4.perspective([], (2 * Math.PI) / 5, aspect, 1, 100.0);
                const modelViewProjectionMatrix = mat4.create();
                const model = new Model({
                    shaderId: "model",
                    frag: `
              @group(0) @binding(2) var mySampler: sampler;
              @group(0) @binding(1) var myTexture: texture_2d<f32>;

              @fragment
              fn main(
                @location(0) fragUV: vec2<f32>,
                @location(1) fragPosition: vec4<f32>
              ) -> @location(0) vec4<f32> {
                   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
              }
              `,
                    vert: `
            struct Uniforms {
              modelViewProjectionMatrix : mat4x4<f32>,
            }
            @binding(0) @group(0) var<uniform> uniforms : Uniforms;

            struct VertexOutput {
              @builtin(position) Position : vec4<f32>,
              @location(0) fragUV : vec2<f32>,
              @location(1) fragPosition: vec4<f32>,
            }

            @vertex
            fn main(
              @location(0) position : vec4<f32>,
              @location(1) color : vec4<f32>,
              @location(2) uv : vec2<f32>
            ) -> VertexOutput {
              var output : VertexOutput;
              output.Position = uniforms.modelViewProjectionMatrix * position;
              output.fragUV = uv;
              output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));
              return output;
            }
               `,
                    vertexBuffers: [
                        {
                            stepMode: "vertex",
                            uid: "vertAttr",
                            attributes: {
                                interleaved: {
                                    names: ["position", "color", "uv"],
                                    value: cubeVertexArray,
                                    itemSizes: [4, 4, 2]
                                } //interleaved buffer
                            }
                        }
                    ],
                    uniformBuffers: [
                        {
                            type: "uniform",
                            uid: "systemMatrix",
                            uniforms: {
                                modelViewProjectionMatrix: {
                                    type: "mat4x4<f32>",
                                    value: () => {
                                        let viewMatrix = mat4.identity([]);
                                        mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, 0, -4));
                                        const now = Date.now() / 1000;
                                        mat4.rotate(
                                            viewMatrix,
                                            viewMatrix,
                                            1,
                                            vec3.fromValues(Math.sin(now), Math.cos(now), 0)
                                        );
                                        mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);
                                        return modelViewProjectionMatrix;
                                    }
                                }
                            }
                        }
                    ],
                    uniformTextureAndSampler: {
                        myTexture: { type: "texture", value: texture },
                        mySampler: { type: "sampler", value: sampler }
                    },
                    renderState: {
                        targets: [
                            {
                                format: presentationFormat
                            }
                        ],
                        primitive: {
                            topology: "triangle-list",
                            cullMode: "back"
                        },
                        depthStencil: {
                            depthWriteEnabled: true,
                            depthCompare: "less",
                            format: "depth24plus"
                        }
                    },
                    draw: {
                        count: 36,
                        instanceCount: 1
                    }
                });
                const model1 = new Model({
                    shaderId: "model",
                    frag: `
              @group(0) @binding(2) var mySampler: sampler;
              @group(0) @binding(1) var myTexture: texture_2d<f32>;

              @fragment
              fn main(
                @location(0) fragUV: vec2<f32>,
                @location(1) fragPosition: vec4<f32>
              ) -> @location(0) vec4<f32> {
                   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
              }
              `,
                    vert: `
            struct Uniforms {
              modelViewProjectionMatrix : mat4x4<f32>,
            }
            @binding(0) @group(0) var<uniform> uniforms : Uniforms;

            struct VertexOutput {
              @builtin(position) Position : vec4<f32>,
              @location(0) fragUV : vec2<f32>,
              @location(1) fragPosition: vec4<f32>,
            }

            @vertex
            fn main(
              @location(0) position : vec4<f32>,
              @location(1) color : vec4<f32>,
              @location(2) uv : vec2<f32>
            ) -> VertexOutput {
              var output : VertexOutput;
              output.Position = uniforms.modelViewProjectionMatrix * position;
              output.fragUV = uv;
              output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));
              return output;
            }
               `,
                    vertexBuffers: [
                        {
                            stepMode: "vertex",
                            uid: "vertAttr",
                            attributes: {
                                interleaved: {
                                    names: ["position", "color", "uv"],
                                    value: cubeVertexArray,
                                    itemSizes: [4, 4, 2]
                                } //interleaved buffer
                            }
                        }
                    ],
                    uniformBuffers: [
                        {
                            type: "uniform",
                            uid: "systemMatrix",
                            uniforms: {
                                modelViewProjectionMatrix: {
                                    type: "mat4x4<f32>",
                                    value: () => {
                                        let viewMatrix = mat4.identity([]);
                                        mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, -4, -8));
                                        const now = Date.now() / 1000;
                                        mat4.rotate(
                                            viewMatrix,
                                            viewMatrix,
                                            1,
                                            vec3.fromValues(Math.sin(now), Math.cos(now), 0)
                                        );
                                        mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);
                                        return modelViewProjectionMatrix;
                                    }
                                }
                            }
                        }
                    ],
                    uniformTextureAndSampler: {
                        myTexture: { type: "texture", value: texture },
                        mySampler: { type: "sampler", value: sampler }
                    },
                    renderState: {
                        targets: [
                            {
                                format: presentationFormat
                            }
                        ],
                        primitive: {
                            topology: "triangle-list",
                            cullMode: "back"
                        },
                        depthStencil: {
                            depthWriteEnabled: true,
                            depthCompare: "less",
                            format: "depth24plus"
                        }
                    },
                    draw: {
                        count: 36,
                        instanceCount: 1
                    }
                });

                function animate() {
                    requestAnimationFrame(animate);
                    const passEncoder = canvasRenderTarget.beginRenderPass(context.device);
                    model.render({ device: context.device, passEncoder });
                    model1.render({ device: context.device, passEncoder });
                    canvasRenderTarget.endRenderPass();
                }
                animate();
            };
            init();
        </script>