mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-12-01 19:23:38 +00:00
6035b07b78
Fixes #1745: Support out-of-order module scope declarations in WGSL Fixes #1044: Forbid local variable shadowing in WGSL Fixes #2076: [wgsl-in] no error for duplicated type definition Fixes #2071: Global item does not support 'const' Fixes #2105: [wgsl-in] Type aliases for a vecN<T> doesn't work when constructing vec from a single argument Fixes #1775: Referencing a function without a return type yields an unknown identifier error. Fixes #2089: Error span reported on the declaration of a variable instead of its use Fixes #1996: [wgsl-in] Confusing error: "expected unsigned/signed integer literal, found '1'" Separate parsing from lowering by generating an AST, which desugars as much as possible down to something like Naga IR. The AST is then used to resolve identifiers while lowering to Naga IR. Co-authored-by: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Co-authored-by: Jim Blandy <jimb@red-bean.com>
118 lines
3.7 KiB
WebGPU Shading Language
118 lines
3.7 KiB
WebGPU Shading Language
struct Globals {
|
|
view_proj: mat4x4<f32>,
|
|
num_lights: vec4<u32>,
|
|
}
|
|
|
|
@group(0)
|
|
@binding(0)
|
|
var<uniform> u_globals: Globals;
|
|
|
|
struct Entity {
|
|
world: mat4x4<f32>,
|
|
color: vec4<f32>,
|
|
}
|
|
|
|
@group(1)
|
|
@binding(0)
|
|
var<uniform> u_entity: Entity;
|
|
|
|
/* Not useful for testing
|
|
@vertex
|
|
fn vs_bake(@location(0) position: vec4<i32>) -> @builtin(position) vec4<f32> {
|
|
return u_globals.view_proj * u_entity.world * vec4<f32>(position);
|
|
}
|
|
*/
|
|
|
|
struct VertexOutput {
|
|
@builtin(position) proj_position: vec4<f32>,
|
|
@location(0) world_normal: vec3<f32>,
|
|
@location(1) world_position: vec4<f32>,
|
|
}
|
|
|
|
@vertex
|
|
fn vs_main(
|
|
@location(0) position: vec4<i32>,
|
|
@location(1) normal: vec4<i32>,
|
|
) -> VertexOutput {
|
|
let w = u_entity.world;
|
|
let world_pos = u_entity.world * vec4<f32>(position);
|
|
var out: VertexOutput;
|
|
out.world_normal = mat3x3<f32>(w.x.xyz, w.y.xyz, w.z.xyz) * vec3<f32>(normal.xyz);
|
|
out.world_position = world_pos;
|
|
out.proj_position = u_globals.view_proj * world_pos;
|
|
return out;
|
|
}
|
|
|
|
// fragment shader
|
|
|
|
struct Light {
|
|
proj: mat4x4<f32>,
|
|
pos: vec4<f32>,
|
|
color: vec4<f32>,
|
|
}
|
|
|
|
@group(0)
|
|
@binding(1)
|
|
var<storage, read> s_lights: array<Light>;
|
|
@group(0)
|
|
@binding(1)
|
|
var<uniform> u_lights: array<Light, 10>; // Used when storage types are not supported
|
|
@group(0)
|
|
@binding(2)
|
|
var t_shadow: texture_depth_2d_array;
|
|
@group(0)
|
|
@binding(3)
|
|
var sampler_shadow: sampler_comparison;
|
|
|
|
fn fetch_shadow(light_id: u32, homogeneous_coords: vec4<f32>) -> f32 {
|
|
if (homogeneous_coords.w <= 0.0) {
|
|
return 1.0;
|
|
}
|
|
// compensate for the Y-flip difference between the NDC and texture coordinates
|
|
let flip_correction = vec2<f32>(0.5, -0.5);
|
|
// compute texture coordinates for shadow lookup
|
|
let proj_correction = 1.0 / homogeneous_coords.w;
|
|
let light_local = homogeneous_coords.xy * flip_correction * proj_correction + vec2<f32>(0.5, 0.5);
|
|
// do the lookup, using HW PCF and comparison
|
|
return textureSampleCompareLevel(t_shadow, sampler_shadow, light_local, i32(light_id), homogeneous_coords.z * proj_correction);
|
|
}
|
|
|
|
const c_ambient: vec3<f32> = vec3<f32>(0.05, 0.05, 0.05);
|
|
const c_max_lights: u32 = 10u;
|
|
|
|
@fragment
|
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|
let normal = normalize(in.world_normal);
|
|
// accumulate color
|
|
var color: vec3<f32> = c_ambient;
|
|
for(var i = 0u; i < min(u_globals.num_lights.x, c_max_lights); i++) {
|
|
let light = s_lights[i];
|
|
// project into the light space
|
|
let shadow = fetch_shadow(i, light.proj * in.world_position);
|
|
// compute Lambertian diffuse term
|
|
let light_dir = normalize(light.pos.xyz - in.world_position.xyz);
|
|
let diffuse = max(0.0, dot(normal, light_dir));
|
|
// add light contribution
|
|
color += shadow * diffuse * light.color.xyz;
|
|
}
|
|
// multiply the light by material color
|
|
return vec4<f32>(color, 1.0) * u_entity.color;
|
|
}
|
|
|
|
// The fragment entrypoint used when storage buffers are not available for the lights
|
|
@fragment
|
|
fn fs_main_without_storage(in: VertexOutput) -> @location(0) vec4<f32> {
|
|
let normal = normalize(in.world_normal);
|
|
var color: vec3<f32> = c_ambient;
|
|
for(var i = 0u; i < min(u_globals.num_lights.x, c_max_lights); i++) {
|
|
// This line is the only difference from the entrypoint above. It uses the lights
|
|
// uniform instead of the lights storage buffer
|
|
let light = u_lights[i];
|
|
let shadow = fetch_shadow(i, light.proj * in.world_position);
|
|
let light_dir = normalize(light.pos.xyz - in.world_position.xyz);
|
|
let diffuse = max(0.0, dot(normal, light_dir));
|
|
color += shadow * diffuse * light.color.xyz;
|
|
}
|
|
return vec4<f32>(color, 1.0) * u_entity.color;
|
|
}
|