Skip to content

Instantly share code, notes, and snippets.

@nahkd123
Created March 26, 2024 14:55
Show Gist options
  • Save nahkd123/f9b55ab5aff3cb139ab5b35df7acc96f to your computer and use it in GitHub Desktop.
Save nahkd123/f9b55ab5aff3cb139ab5b35df7acc96f to your computer and use it in GitHub Desktop.
Can we write a better WebGPU Shading Language specification?

Can we write a better WebGPU Shading Language specification?

Yes, maybe...

fragment.wgsl is the example WGSL (WebGPU Shading Language) coed found in the official specification. fragment.nwgsl (NGLSL stands for "Not WebGPU Shading Language") is the exact same fragment shader as fragment.wgsl, except small changes to the language.

// A fragment shader which lights textured geometry with point lights.
// Lights from a storage buffer binding.
struct PointLight {
position: vec3f,
color: vec3f,
}
struct LightStorage {
pointCount: u32,
point: array<PointLight>,
}
@group(0) @binding(0) var<storage> lights: LightStorage;
// Texture and sampler.
@group(1) @binding(0) var baseColorSampler: sampler;
@group(1) @binding(1) var baseColorTexture: texture_2d<f32>;
// Function arguments are values from the vertex shader.
// Instead of putting @location(), you have to order them manually. First arg is @location(0), 2nd is @location(1) and so on...
// The function signature would be "(vec3f, vec3f, vec2f) -> (vec4f)"
// With builtin:
// fragment fragmentMain(foo: [vertex_index]) -> vec4f {}
// fragment fragmentMain() -> [position] {}
fragment fragmentMain(worldPos: vec3f, normal: vec3f, uv: vec2f) -> vec4f {
// Sample the base color of the surface from a texture.
// We use "const" here to specify that it is constant. Who though "let" is a good idea?
// Yeah ok I know this is computed at runtime, but I'm sure the compiler is smart enough to determine this is runtime
// variable, right?
const baseColor = textureSample(baseColorTexture, baseColorSampler, uv);
const N = normalize(normal);
var surfaceColor = vec3f(0);
// Loop over the scene point lights.
for (var i = 0u; i < lights.pointCount; i++) {
const worldToLight = lights.point[i].position - worldPos;
const dist = length(worldToLight);
const dir = normalize(worldToLight);
// Determine the contribution of this light to the surface color.
const radiance = lights.point[i].color * (1 / pow(dist, 2));
const nDotL = max(dot(N, dir), 0);
// Accumulate light contribution to the surface color.
surfaceColor += baseColor.rgb * radiance * nDotL;
}
// Return the accumulated surface color.
return vec4(surfaceColor, baseColor.a);
}
// A fragment shader which lights textured geometry with point lights.
// Lights from a storage buffer binding.
struct PointLight {
position : vec3f,
color : vec3f,
}
struct LightStorage {
pointCount : u32,
point : array<PointLight>,
}
@group(0) @binding(0) var<storage> lights : LightStorage;
// Texture and sampler.
@group(1) @binding(0) var baseColorSampler : sampler;
@group(1) @binding(1) var baseColorTexture : texture_2d<f32>;
// Function arguments are values from the vertex shader.
@fragment
fn fragmentMain(@location(0) worldPos : vec3f,
@location(1) normal : vec3f,
@location(2) uv : vec2f) -> @location(0) vec4f {
// Sample the base color of the surface from a texture.
let baseColor = textureSample(baseColorTexture, baseColorSampler, uv);
let N = normalize(normal);
var surfaceColor = vec3f(0);
// Loop over the scene point lights.
for (var i = 0u; i < lights.pointCount; i++) {
let worldToLight = lights.point[i].position - worldPos;
let dist = length(worldToLight);
let dir = normalize(worldToLight);
// Determine the contribution of this light to the surface color.
let radiance = lights.point[i].color * (1 / pow(dist, 2));
let nDotL = max(dot(N, dir), 0);
// Accumulate light contribution to the surface color.
surfaceColor += baseColor.rgb * radiance * nDotL;
}
// Return the accumulated surface color.
return vec4(surfaceColor, baseColor.a);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment