Skip to content

ビューポート解像度を使ったグラデーション(時間変化つき)

import shaderCode from "./shader.wgsl?raw"
const adapter = await navigator.gpu.requestAdapter()
if (!adapter) {
throw new Error("WebGPU cannot be initialized - Adapter not found")
}
const device = await adapter.requestDevice()
device.lost.then(() => {
throw new Error("WebGPU cannot be initialized - Device has been lost")
})
const canvas = document.querySelector("canvas")
const context = canvas!.getContext("webgpu")
if (!context) {
throw new Error("WebGPU cannot be initialized - Canvas does not support WebGPU")
}
const canvasFormat = navigator.gpu.getPreferredCanvasFormat()
context.configure({ device, format: canvasFormat })
// prettier-ignore
const vertices = new Float32Array([
-1.0, 1.0, // 0: 左上
1.0, 1.0, // 1: 右上
-1.0, -1.0, // 2: 左下
1.0, -1.0, // 3: 右下
])
const vertexBuffer = device.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
})
device.queue.writeBuffer(vertexBuffer, 0, vertices)
// prettier-ignore
const indices = new Uint16Array([
0, 1, 2, // 三角形1
1, 3, 2, // 三角形2
]);
const indexBuffer = device.createBuffer({
size: indices.byteLength,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
})
device.queue.writeBuffer(indexBuffer, 0, indices)
const uTime = 0.0
const uResolution = [canvas!.width, canvas!.height]
const uniform = new Float32Array([uTime, 0.0, ...uResolution]) // ゼロパディングが必要
const uniformBuffer = device.createBuffer({
size: uniform.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
})
device.queue.writeBuffer(uniformBuffer, 0, uniform)
const shaderModule = device.createShaderModule({ code: shaderCode })
const renderPipeline = device.createRenderPipeline({
layout: "auto",
vertex: {
module: shaderModule,
entryPoint: "vs_main",
buffers: [
{
arrayStride: vertices.BYTES_PER_ELEMENT * 2,
attributes: [
{
shaderLocation: 0,
offset: 0,
format: "float32x2"
}
]
}
]
},
fragment: {
module: shaderModule,
entryPoint: "fs_main",
targets: [
{
format: canvasFormat
}
]
}
})
const uniformBindGroup = device.createBindGroup({
layout: renderPipeline.getBindGroupLayout(0),
entries: [
{
binding: 0, // @binding(0) in shader
resource: {
buffer: uniformBuffer
}
}
]
})
const startTime = new Date().getTime()
const frame = () => {
const elapsed = new Date().getTime() - startTime
const uTime = elapsed * 0.001 // 秒に変換
const uniform = new Float32Array([uTime, 0.0, ...uResolution]) // ゼロパディングが必要
device.queue.writeBuffer(uniformBuffer, 0, uniform)
const commandEncoder = device.createCommandEncoder()
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [
{
view: context.getCurrentTexture().createView(),
loadOp: "clear",
clearValue: { r: 0.32, g: 0.34, b: 0.36, a: 1 },
storeOp: "store"
}
]
})
renderPass.setPipeline(renderPipeline)
renderPass.setBindGroup(0, uniformBindGroup)
renderPass.setVertexBuffer(0, vertexBuffer)
renderPass.setIndexBuffer(indexBuffer, "uint16")
renderPass.drawIndexed(indices.length)
renderPass.end()
device.queue.submit([commandEncoder.finish()])
requestAnimationFrame(frame)
}
frame()