WebGPU实现一个三角形

471 阅读3分钟

首先 不要过分依赖AI 就把AI当做一个高级一点的搜索引擎

ok,AI是能提高效率,但是并不能保证给出的答案一定正确,所以如果各位有这样的想法(以后所有的活都交给AI来干,我干嘛要动脑?)就大错特错了,AI给你一段代码,如果你不清楚整个流程,每个模块的作用是干什么的,即使AI给你注释了,控制台报错了你依然不会怎么改怎么办? 话不多说直接进入正题:

首先让AI用webgl来生成一个三角形

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{box-sizing: border-box;}
        body{margin:0;padding:0}
        canvas{width:100%;height:100%}
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>

    <script>
        const canvas = document.getElementById('canvas');
        canvas.width = window.innerWidth
        canvas.height = window.innerHeight
        const gl = canvas.getContext('webgl');

        // define the vertex shader
        const vertexShaderSrc = `
            attribute vec4 a_Position;
            void main() {
                gl_Position = a_Position;
            }
        `;
        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertexShaderSrc);
        gl.compileShader(vertexShader);

        // check if shader compiled successfully
        if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
            console.error(`Error compiling vertex shader: ${gl.getShaderInfoLog(vertexShader)}`);
        }

        // define the fragment shader
        const fragmentShaderSrc = `
            precision mediump float;
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        `;
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, fragmentShaderSrc);
        gl.compileShader(fragmentShader);

        // check if shader compiled successfully
        if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
            console.error(`Error compiling fragment shader: ${gl.getShaderInfoLog(fragmentShader)}`);
        }

        // create the shader program
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);

        // check if program linked successfully
        if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
            console.error(`Error linking program: ${gl.getProgramInfoLog(program)}`);
        }

        // get the location of the vertex position attribute
        const vertexPositionAttributeLocation = gl.getAttribLocation(program, 'a_Position');

        // create the vertex buffer
        const vertexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

        // define the vertices of the triangle
        const vertices = [
            0.0, 0.5,
            -0.5, -0.5,
            0.5, -0.5,
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

        // enable the vertex position attribute
        gl.enableVertexAttribArray(vertexPositionAttributeLocation);

        // tell webgl how to read the vertex buffer
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.vertexAttribPointer(vertexPositionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

        // set the background color
        gl.clearColor(0.0, 0.0, 0.0, 1.0);

        // clear the canvas
        gl.clear(gl.COLOR_BUFFER_BIT);

        // use the shader program
        gl.useProgram(program);

        // draw the triangle
        gl.drawArrays(gl.TRIANGLES, 0, 3);
    </script>
</body>
</html>

ok,经测试,确实生成了一个三角形,并且没有报错,有兴趣的童鞋可以研究webgl渲染的流程,顶点着色器 片元着色器等概念。

接下来 让AI用webgpu来生成一个三角形

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{box-sizing: border-box;}
        body{margin:0;padding:0}
        canvas{width:100%;height:100%}
    </style>
</head>
<body>
    <canvas id="canvas"></canvas>

    <script>
        async function init() {
            // get the canvas element and the GPU adapter
            const canvas = document.getElementById('canvas');
            canvas.width = window.innerWidth
            canvas.height = window.innerHeight

            // 获取webgpu的上下文
            let context = canvas.getContext("webgpu")

            const adapter = await navigator.gpu.requestAdapter();
            const device = await adapter.requestDevice();


            let format = navigator.gpu.getPreferredCanvasFormat()
            // 配置上下文
            context.configure({
                device:device,
                format:format,
                alphaMode:"opaque"
            })

            
             // define the vertex and fragment shaders
            const vertexShaderModule = /*GLSL*/`
            @vertex
            fn main(
                @builtin(vertex_index) vertexIndex: u32,
                ) -> @builtin(position) vec4<f32> {
                    var pos = array<vec2<f32>, 3>(
                        vec2(0.0,0.5),
                        vec2(-0.5,-0.5),
                        vec2(0.5,-0.5),
                    );
                    return vec4<f32>(pos[vertexIndex],0.0,1.0);
                }
            `;

            const fragmentShaderModule = /*GLSL*/`
            @fragment
            fn main() -> @location(0) vec4<f32> {
                return vec4(1.0, 0.0, 0.0, 1.0);
            }
            `;

             // create the render pipeline
            const renderPipeline = device.createRenderPipeline({
                layout: "auto",
                vertex: {
                    module: device.createShaderModule({
                        code: vertexShaderModule,
                    }),
                    entryPoint: 'main',
                },
                fragment: {
                    module: device.createShaderModule({
                        code: fragmentShaderModule,
                    }),
                    entryPoint: 'main',
                    targets: [{
                        format: format,
                    }],
                },
                primitive: {
                    topology: 'triangle-list',
                }
            });
             // create the command encoder and render pass descriptor
            const commandEncoder = device.createCommandEncoder();
            const renderPassDescriptor = {
                colorAttachments: [{
                    view: context.getCurrentTexture().createView(),
                    clearValue: { r: 0, g: 0, b: 0, a: 1 },
                    loadOp:"clear",
                    storeOp: 'store',
                }],
            };
             // create the render pass and draw the triangle
            const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor);
            renderPass.setPipeline(renderPipeline);
            renderPass.draw(3, 1, 0, 0);
            renderPass.end();
            device.queue.submit([commandEncoder.finish()]);
        }
        init();
    </script>
    
</body>
</html>

好,经测试,确实能生成一个三角形,但是!注意这里但是!,这并不完全是由AI生成的代码,由AI生成的代码一开始是报错的,而且报错很多,但是它生成代码的大体思路是没有问题的,只是细节方面需要调整(这里参考了老陈打码的课程)

行,所以重点来了,AI给你的代码报错了你要知道在哪,并且要知道怎么改,不要妄想AI会帮你找出一切问题,它可能会给你一个模糊的提示,并不会给你精准的把bug修复,就像下面的提示: Without seeing the code in question, it is difficult to provide a specific solution. However, this error typically occurs when trying to access a member that has not been defined.

To fix this error, make sure that the required member is properly defined and accessible in your code. Double-check variable names, function declarations, and import statements to ensure that everything is spelled correctly and in the correct scope.

If you are still having trouble, consider posting your code and a more detailed description of the error message to a developer forum or seeking help from a more experienced developer.

所以,如果你不了解各个模块的作用,流程是怎样,只是看上面的提示,报错依然不知道怎么修复,好了,之前借助AI来学习算法,今天我们借助AI对GPU渲染也有了一个初步的认识,大伙也明显能看到,仅仅是实现一个三角形,就要cv这么多代码,显然实际开发中是不合适的,所以会有一些three等库来帮我们封装这样的代码,以简化我们的开发,但是了解一些偏底层的知识,对于整体的认知还是能稍微有个提升的。

当然我不希望有童鞋来杠我,要了解底层你怎么不从实现一个芯片开始?在下不才,但是这种大佬肯定是有很多的,所以我们只是尽我们所能去涨点姿势,以提升水平。

总结

最后,还是回到我写文章的初衷是授人渔,我希望大伙无论学习什么框架,什么技术,不要死记硬背,毕竟新知识是学不完的,要了解 理解一个整体的流程和思想,古代武功最高境界不是忘掉所有招式吗,hh,希望各位能忘掉所有API,但是要记得怎么灵活运用。