I want to create a WebGPU version of Shadertoy, but I can't to prepare the code correctly.
How to draw in @fragment shader for SDF in WebGPU ?
I clipped space [-1,1, 1,1, -1,-1, 1,-1] of canvas but what I need to do next ?
<!DOCTYPE html>
<title>SDF-WebGPU</title>
<canvas></canvas><script>'use strict';
const canvas = document.body.firstChild;
canvas.style = `
display: block;
image-rendering: pixelated;
background-color: #ccc;
user-select: none;
touch-action: none;
width: ${ canvas.width = 480 * devicePixelRatio, 480 }px;
height: ${ canvas.height = 360 * devicePixelRatio, 360 }px;
`;
const init = async function(){
const
context = canvas.getContext(`webgpu`),
format = navigator.gpu.getPreferredCanvasFormat(),
adapter = await navigator.gpu.requestAdapter(),
device = await adapter.requestDevice(),
Q = device.queue,
{VERTEX, COPY_DST} = GPUBufferUsage,
SPACE_B = new Float32Array([-1,1, 1,1, -1,-1, 1,-1]),
B = device.createBuffer({
label: `SPACE`,
size: SPACE_B.byteLength,
usage: VERTEX | COPY_DST
}),
P = device.createRenderPipeline({
layout: `auto`,
vertex: {
module: device.createShaderModule({
code: `@vertex
fn vSh(@location(0) p:vec2<f32>) -> @builtin(position) vec4<f32>{
return vec4<f32>(p,0,1); // (p[x,y],z,w)
}`
}),
entryPoint: `vSh`,
buffers: [{
arrayStride: 8, // 2*4 = 2 floats x 4 bytes
attributes: [{
shaderLocation: 0,
offset: 0,
format: `float32x2`
}]
}], // buffers
},
fragment: {
module: device.createShaderModule({
code: `@fragment
fn fSh() -> @location(0) vec4<f32>{
return vec4<f32>(.082,.263,.455,1);
}`
}),
entryPoint: `fSh`,
targets: [ {format} ]
},
primitive:{
topology: `triangle-strip`
}
}), // Pipeline
frame=()=>{
const
C = device.createCommandEncoder(),
R = C.beginRenderPass({
colorAttachments:[{
view: context.getCurrentTexture().createView(),
loadOp: `clear`,
storeOp: `store`
}]
});
R.setPipeline(P);
R.setVertexBuffer(0,B);
R.draw(4);
R.end();
Q.submit([ C.finish() ])
}; // frame
context.configure({ device, format, alphaMode: `opaque` });
Q.writeBuffer(B,0, SPACE_B);
frame()
}() // init
</script>
I was only able to create a version without SDF.
If you know any references about WebGPU SDF, please share with me. Thanks !
Shaders in WebGPU are written in WGSL instead of GLSL but nearly every concept in GLSL has a similar feature in WGSL
You'll either have to read the spec or look at examples to figure out how to translate from GLSL to WGSL but it's not that hard :P
Here's a GLSL SDF shader
Here it translated to WGSL
I can't write all the differences but a few easy to explain things
In GLSL a function is
returnType name(type1 arg1, type2 arg2) { ... }
In WGSL a function is
fn name(arg1: type1, arg2: type2) -> returnType { ... }
In GLSL a variable is
type nameOfVar
In WGSL a variable is
var nameOfVar: type
except that in WGSL you don't have to specify the type if WGSL can figure it out.In other words, these are the same
Note: confusingly,
var
is likelet
in JavaScript. You can reassign it.let
is likeconst
in JavaScript. You can't change it after assignment.GLSL has the
?
operator as inv = condition ? t : f
WGSL has
select
as inv = select(f, t, condition)
types
One more issue, in WebGL
gl_FragCoord.y
goes from 0 at the bottom to height of canvas at the top. WebGPU's equivalent@builtin(position)
goes from 0 at the top to height of canvas at the bottom.Here's a live version of that SDF shader. Drag the mouse on the image