1. 程式人生 > 其它 >WebGPU圖形程式設計(2):構建一個單色的三角形<學習引自徐博士教程>

WebGPU圖形程式設計(2):構建一個單色的三角形<學習引自徐博士教程>

非常興奮,我堅持了下來,開始更新我的第二篇部落格,還是關於WebGPU的,我在學習過程中,對這項技術非常感興趣,即使它非常抽象,難以理解,因為我看到未來Web3D的發展,WebGPU會成為主流技術,學習這項技術的前景會更加光明。

本節來建立單色三角形,並通過輸入color四元陣列數值對三角形顏色進行改變.

一、使用搭建好的開發環境進行所有軟體包的安裝

使用上一章節搭建好的所有配置檔案,先進行一步所有軟體包的安裝(這是徐博士教程裡的步驟),為的是產生node_modules資料夾內的所有配置檔案,但我又在想,我第一節已經把所有配置好的檔案配置好了,並且已經有node_modules檔案夾了,npm install不是多此一舉麼(可能是我對開發環境的搭建還沒有學習深刻)?

npm install

徐博士執行完上述命令列後,才生成node_modules資料夾,我試著下載它的原始碼,他的原始碼裡面沒有包含node_modules資料夾,我執行npm install後成功配置完所有檔案,這裡我猜測是package.json已經寫入了配置檔案及版本號,install可能是自動進行版本號識別安裝;

二、修改index.html內容

需要你對dist資料夾下的index.html<body>內的程式碼內容進行修改

程式碼如下:

  <div>
       <h1>Create Triangle</h1><br
> <!--主標題--> <label>Color:</label> <!--表單標題--> <input type="text" id="id-color" value="(1.0,1.0,1.0,1.0)"><!--表單的型別及數值--> <button type="button" id="id-btn">Change Color</button><!--button型別及按鍵名稱--> <br><br> <
canvas id="canvas-webgpu" width="640" height="480"></canvas><!--使用canvas畫布來繪製webgpu圖形--> </div>

三、新增管線著色檔案

src資料夾下,新增sharder.ts檔案,用來寫入WGSL著色器,這裡面的著色器用法和宣告,暫時不需要特別理解,徐博士也是簡單了描述了vertex和fragment兩種著色器,webgpu使用四維向量來渲染三維圖形,之後再詳細學習檢視WGSL使用。

程式碼如下:

export const Shaders = (color:string) => {
    const vertex = `
        [[stage(vertex)]]
        fn main([[builtin(vertex_index)]] VertexIndex: u32) -> [[builtin(position)]] vec4<f32> {
            var pos = array<vec2<f32>, 3>(
                vec2<f32>(0.0, 0.5),
                vec2<f32>(-0.5, -0.5),
                vec2<f32>(0.5, -0.5));
            return vec4<f32>(pos[VertexIndex], 0.0, 1.0);   //webgpu使用四維向量來渲染三維圖形
        }
    `;

    const fragment = `
        [[stage(fragment)]]
        fn main() -> [[location(0)]] vec4<f32> {
            return vec4<f32>${color};
        }
    `;
    return {vertex, fragment};
}

export const Shaders1 = (color:string) => {
    const vertex = `
        var pos = array<vec2<f32>, 3>(
            vec2<f32>(0.0, 0.5),
            vec2<f32>(-0.5, -0.5),
            vec2<f32>(0.5, -0.5));

        [[stage(vertex)]]
        fn main([[builtin(vertex_index)]] VertexIndex: u32) -> [[builtin(position)]] vec4<f32> {
            return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
        }
    `;

    const fragment = `
        [[stage(fragment)]]
        fn main() -> [[location(0)]] vec4<f32> {
            return vec4<f32>${color};
        }
    `;
    return {vertex, fragment};
}

export const ShadersOld = (color:string) => {
    const vertex = `
        const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
            vec2<f32>(0.0, 0.5),
            vec2<f32>(-0.5, -0.5),
            vec2<f32>(0.5, -0.5));

        [[builtin(position)]] var<out> Position : vec4<f32>;
        [[builtin(vertex_idx)]] var<in> VertexIndex : i32;

        [[stage(vertex)]]
        fn main() -> void {
            Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
            return;
        }
    `;

    const fragment = `
        [[location(0)]] var<out> outColor : vec4<f32>;

        [[stage(fragment)]]
        fn main() -> void {
            outColor = vec4<f32>${color};
            return;
        }
    `;
    return {vertex, fragment};
}

四、使用typescript來編寫webgpu的控制程式碼去控制命令GPU

開啟src資料夾下的main.ts檔案,進行程式碼編寫,同樣這一大段程式碼我也看不懂,但需要知道檔案用處,具體的API使用方法可以參照API文件https://www.orillusion.com/zh/webgpu.html#security;

程式碼如下:

import $ from 'jquery';
import { CheckWebGPU } from './helper';
import { Shaders } from './sharder';

const CreateTriangle = async (color='(1.0,1.0,1.0,1.0)') => {
    const checkgpu = CheckWebGPU();
    if(checkgpu.includes('Your current browser does not support WebGPU!')){
        console.log(checkgpu);
        throw('Your current browser does not support WebGPU!');
    }

    const canvas = document.getElementById('canvas-webgpu') as HTMLCanvasElement;        
    const adapter = await navigator.gpu?.requestAdapter() as GPUAdapter;       
    const device = await adapter?.requestDevice() as GPUDevice;
    const context = canvas.getContext('webgpu') as unknown as GPUCanvasContext;
    const format = 'bgra8unorm';
    /*const swapChain = context.configureSwapChain({
        device: device,
        format: format,
    });*/    
    context.configure({
        device: device,
        format: format,
    });
    
    const shader = Shaders(color);
    const pipeline = device.createRenderPipeline({
        vertex: {
            module: device.createShaderModule({                    
                code: shader.vertex
            }),
            entryPoint: "main"
        },
        fragment: {
            module: device.createShaderModule({                    
                code: shader.fragment
            }),
            entryPoint: "main",
            targets: [{
                format: format as GPUTextureFormat
            }]
        },
        primitive:{
           topology: "triangle-list",
        }
    });

    const commandEncoder = device.createCommandEncoder();
    const textureView = context.getCurrentTexture().createView();
    const renderPass = commandEncoder.beginRenderPass({
        colorAttachments: [{
            view: textureView,
            loadValue: { r: 0.5, g: 0.5, b: 0.8, a: 1.0 }, //background color
            storeOp: 'store'
        }]
    });
    renderPass.setPipeline(pipeline);
    renderPass.draw(3, 1, 0, 0);
    renderPass.endPass();

    device.queue.submit([commandEncoder.finish()]);
}

CreateTriangle();
$('#id-btn').on('click', ()=>{
    const color = $('#id-color').val() as string;
    CreateTriangle(color);
});

五、到此我們所有程式碼編寫完成

你可以看到以上步驟,我們對index.html檔案寫頁面展示和呼叫介面、再新建我們的管線程式碼sharder.ts編寫渲染管線、再對mian.ts檔案使用typescript讓webgpuAPI對GPU命令指令;

開啟網頁視窗你可以看到建立成功。

需要注意的一點,也是我過程中犯的錯誤,就是在html中“”內的程式碼內容不可以有空格,否則會生成失敗的!