Last active
April 3, 2022 13:06
-
-
Save bellbind/a46bfb1c6c76246dcbe4f64a132dbb61 to your computer and use it in GitHub Desktop.
[WebGPU] render with no vertex buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<!-- IMPORTANT: The current Chrome requires some origin-trial token in <meta>. | |
To register origins at the last "WebGPU REGISTER" in https://developer.chrome.com/origintrials/ | |
This token is for a Web Origin "http://localhost:8000" (maybe expired at Mar 31, 2022) | |
--> | |
<meta http-equiv="origin-trial" | |
content="AkIL+/THBoi1QEsWbX5SOuMpL6+KGAXKrZE5Bz6yHTuijzvKz2MznuLqE+MH4YSqRi/v1fDK/6JyFzgibTTeNAsAAABJeyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwMDAiLCJmZWF0dXJlIjoiV2ViR1BVIiwiZXhwaXJ5IjoxNjUyODMxOTk5fQ==" /> | |
<meta http-equiv="origin-trial" | |
content="Akv07qcAop5MFaZYxJtHHjUuM8eV3GpbHkTeuhZo/4wsNjYnQ7GSGJyo7hRVZvpvyjYwilbJ8KbFVchI4O1DpA0AAABQeyJvcmlnaW4iOiJodHRwczovL2dpc3QuZ2l0aGFjay5jb206NDQzIiwiZmVhdHVyZSI6IldlYkdQVSIsImV4cGlyeSI6MTY1MjgzMTk5OX0=" /> | |
<script src="./main.js" type="module"></script> | |
<style>@media(prefers-color-scheme: dark){:root {color-scheme: dark;}}</style> | |
<link rel="icon" href="data:image/x-icon;," /> | |
</head> | |
<body> | |
<h1>(Notice: The origin-trial token in this page will be expired at May 15, 2022)</h1> | |
<canvas style="width: 80vmin; height: 80vmin; border: solid;" id="canvas"></canvas> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simple example for WebGPU API: https://www.w3.org/TR/webgpu/ | |
const adapter = await navigator.gpu.requestAdapter(); | |
const device = await adapter.requestDevice(); | |
// WGSL shaders: https://www.w3.org/TR/WGSL/ | |
const wgsl = ` | |
struct Uniforms { | |
t: u32; | |
corners: u32; | |
}; | |
@group(0) @binding(0) var<uniform> uniforms: Uniforms; | |
struct IO { | |
@builtin(position) pos: vec4<f32>; | |
@location(0) hsv: vec2<f32>; | |
}; | |
@stage(vertex) fn vmain(@builtin(vertex_index) i: u32) -> IO { | |
let vid = i % 3u; | |
let tid = (i - vid) / 3u; | |
let cid = (uniforms.t + tid) % uniforms.corners; | |
let a = 360.0 / f32(uniforms.corners); | |
if (vid == 0u) {return IO(vec4<f32>(0.0, 0.0, 0.0, 1.0), vec2<f32>(f32(cid) * a, 0.0));} | |
let t = radians(f32(tid + vid - 1u) * a); | |
return IO(vec4<f32>(-sin(t), cos(t), 0.0, 1.0), vec2<f32>(f32(cid + vid - 1u) * a, 1.0)); | |
} | |
fn hsv2rgb(h: f32, s: f32, v: f32, a: f32) -> vec4<f32> { | |
let h_ = (h % 360.0) / 60.0; | |
let f = modf(h_).fract; | |
let m = v * (1.0 - s); | |
let n = v * (1.0 - s * f); | |
let k = v * (1.0 - s * (1.0 - f)); | |
if (h_ < 1.0) {return vec4<f32>(v, k, m, a);} | |
if (h_ < 2.0) {return vec4<f32>(n, v, m, a);} | |
if (h_ < 3.0) {return vec4<f32>(m, v, k, a);} | |
if (h_ < 4.0) {return vec4<f32>(m, n, v, a);} | |
if (h_ < 5.0) {return vec4<f32>(k, m, v, a);} | |
if (h_ < 6.0) {return vec4<f32>(v, m, n, a);} | |
return vec4<f32>(0.0, 0.0, 0.0, a); | |
} | |
@stage(fragment) fn fmain(io: IO) -> @location(0) vec4<f32> { | |
return hsv2rgb(io.hsv.x, io.hsv.y, 0.75, 1.0); | |
} | |
`; | |
const shader = device.createShaderModule({code: wgsl}); | |
// gpu config for canvas | |
const canvas = document.getElementById("canvas"); | |
const gpu = canvas.getContext("webgpu"); | |
const format = gpu.getPreferredFormat(adapter); | |
gpu.configure({device, format, size: [canvas.width, canvas.height]}); | |
// pipeline | |
const pipeline = device.createRenderPipeline({ | |
primitive: {topology: "triangle-list", cullMode: "back"}, | |
vertex: {module: shader, entryPoint: "vmain", buffers: []}, | |
fragment: {module: shader, entryPoint: "fmain", targets: [{format}]}, | |
}); | |
// bind group | |
const uniforms = new Uint32Array([0, 3]); | |
const uniformsBuffer = device.createBuffer({usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, size: uniforms.byteLength}); | |
const bindGroup = device.createBindGroup({ | |
layout: pipeline.getBindGroupLayout(0), | |
entries: [{binding: 0, resource: {buffer: uniformsBuffer}}], | |
}); | |
// render with no vertex buffer | |
const corners = 64; | |
const render = (t) => { | |
const c = 3 + Math.round((corners - 3) / 2 * (-Math.cos(t / 80) + 1)); | |
[uniforms[0], uniforms[1]] = [t / 10, c]; | |
device.queue.writeBuffer(uniformsBuffer, 0, uniforms.buffer); | |
const view = gpu.getCurrentTexture().createView(); | |
const clearValue = {r: 0, g: 0, b: 0, a: 1}; | |
const renderPass = {colorAttachments: [{view, loadOp: "clear", clearValue, loadValue: clearValue, storeOp: "store"}]}; //[chrome-99] loadValue | |
const commandEncoder = device.createCommandEncoder(); | |
const passEncoder = commandEncoder.beginRenderPass(renderPass); | |
passEncoder.setPipeline(pipeline); | |
passEncoder.setBindGroup(0, bindGroup); | |
passEncoder.draw(3 * c, 1); | |
(passEncoder.end ?? passEncoder.endPass).call(passEncoder); //[chrome-99] endPass | |
device.queue.submit([commandEncoder.finish()]); | |
}; | |
(function loop(t) { | |
render(t); | |
requestAnimationFrame(() => loop(t + 1)); | |
})(0); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
demo: https://gist.githack.com/bellbind/a46bfb1c6c76246dcbe4f64a132dbb61/raw/index.html