Skip to content

Commit

Permalink
Merge pull request #305 from RagnarokResearchLab/wgsl-shader-format
Browse files Browse the repository at this point in the history
Clean up the WGSL shader code (by reformatting and reordering)
  • Loading branch information
rdw-software authored Jan 19, 2024
2 parents bc52c37 + a5995b0 commit 03f66e6
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 102 deletions.
87 changes: 44 additions & 43 deletions Core/NativeClient/Shaders/BasicTriangleShader.wgsl
Original file line number Diff line number Diff line change
@@ -1,55 +1,56 @@
struct VertexInput {
@location(0) position: vec3f,
@location(1) color: vec3f,
@location(2) diffuseTextureCoords: vec2f,
};

struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) color: vec3f,
@location(1) diffuseTextureCoords: vec2f,
};

// CameraBindGroup: Updated once per frame
struct PerSceneData {
view: mat4x4f,
perspectiveProjection: mat4x4f,
color: vec4f,
view: mat4x4f,
perspectiveProjection: mat4x4f,
color: vec4f,
viewportWidth: f32,
viewportHeight: f32,
};

@group(0) @binding(0) var<uniform> uPerSceneData: PerSceneData;

// MaterialBindGroup: Updated once per unique mesh material
@group(1) @binding(0) var diffuseTexture: texture_2d<f32>;
@group(1) @binding(1) var diffuseTextureSampler: sampler;

struct VertexInput {
@location(0) position: vec3f,
@location(1) color: vec3f,
@location(2) diffuseTextureCoords: vec2f,
};

struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) color: vec3f,
@location(1) diffuseTextureCoords: vec2f,
};
// InstanceBindGroup: Updated once per mesh instance
// NYI (only for RML UI widgets)

const MATH_PI = 3.14159266;
const DEBUG_ALPHA_OFFSET = 0.0; // Set to non-zero value (e.g., 0.2) to make transparent background pixels visible

fn deg2rad(angleInDegrees: f32) -> f32 {
return angleInDegrees * MATH_PI / 180.0;
}

@vertex
fn vs_main(in: VertexInput) -> VertexOutput {
var position = in.position;

// Scale the object
let scale = vec3f(1.0, 1.0, 1.0);
let S = transpose(mat4x4<f32>(
scale.x, 0.0, 0.0, 0.0,
0.0, scale.y, 0.0, 0.0,
0.0, 0.0, scale.z, 0.0,
0.0, 0.0, 0.0, 1.0,
scale.x, 0.0, 0.0, 0.0,
0.0, scale.y, 0.0, 0.0,
0.0, 0.0, scale.z, 0.0,
0.0, 0.0, 0.0, 1.0,
));

// Translate the object
let translation = vec3f(0.0, 0.0, 0.0);
let T1 = transpose(mat4x4<f32>(
1.0, 0.0, 0.0, translation.x,
0.0, 1.0, 0.0, translation.y,
0.0, 0.0, 1.0, translation.z,
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, translation.x,
0.0, 1.0, 0.0, translation.y,
0.0, 0.0, 1.0, translation.z,
0.0, 0.0, 0.0, 1.0,
));

// Rotate the object
Expand All @@ -69,26 +70,26 @@ fn vs_main(in: VertexInput) -> VertexOutput {
let s2 = sin(angle2);
let R2 = transpose(mat4x4<f32>(
1.0, 0.0, 0.0, 0.0,
0.0, c2, s2, 0.0,
0.0, -s2, c2, 0.0,
0.0, c2, s2, 0.0,
0.0, -s2, c2, 0.0,
0.0, 0.0, 0.0, 1.0,
));

// Move the view point
let focalPoint = vec3<f32>(0.0, 0.0, -10.0); // Actually, camera position?
let T2 = transpose(mat4x4<f32>(
1.0, 0.0, 0.0, -focalPoint.x,
0.0, 1.0, 0.0, -focalPoint.y,
0.0, 0.0, 1.0, -focalPoint.z,
0.0, 0.0, 0.0, 1.0,
1.0, 0.0, 0.0, -focalPoint.x,
0.0, 1.0, 0.0, -focalPoint.y,
0.0, 0.0, 1.0, -focalPoint.z,
0.0, 0.0, 0.0, 1.0,
));

var out: VertexOutput;
var homogeneous_position = vec4<f32>(in.position, 1.0);
var homogeneousPosition = vec4<f32>(in.position, 1.0);

let projectionMatrix = transpose(uPerSceneData.perspectiveProjection);
let viewMatrix = transpose(uPerSceneData.view);
out.position = projectionMatrix * viewMatrix * T1 * S * homogeneous_position;
out.position = projectionMatrix * viewMatrix * T1 * S * homogeneousPosition;

out.color = in.color;
out.diffuseTextureCoords = in.diffuseTextureCoords;
Expand All @@ -97,13 +98,13 @@ fn vs_main(in: VertexInput) -> VertexOutput {

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
let textureCoords = in.diffuseTextureCoords;
let diffuseTextureColor = textureSample(diffuseTexture, diffuseTextureSampler, textureCoords);
let finalColor = in.color * diffuseTextureColor.rgb * uPerSceneData.color.rgb;

// WebGPU assumes that the colors output by the fragment shader are given in linear space
// When setting the surface format to BGRA8UnormSrgb it performs a linear to sRGB conversion.
// Gamma-correction
let corrected_color = pow(finalColor.rgb, vec3f(2.2));
return vec4f(corrected_color, uPerSceneData.color.a * diffuseTextureColor.a + DEBUG_ALPHA_OFFSET);
let textureCoords = in.diffuseTextureCoords;
let diffuseTextureColor = textureSample(diffuseTexture, diffuseTextureSampler, textureCoords);
let finalColor = in.color * diffuseTextureColor.rgb * uPerSceneData.color.rgb;

// Gamma-correction:
// WebGPU assumes that the colors output by the fragment shader are given in linear space
// When setting the surface format to BGRA8UnormSrgb it performs a linear to sRGB conversion
let gammaCorrectedColor = pow(finalColor.rgb, vec3f(2.2));
return vec4f(gammaCorrectedColor, uPerSceneData.color.a * diffuseTextureColor.a + DEBUG_ALPHA_OFFSET);
}
127 changes: 68 additions & 59 deletions Core/NativeClient/Shaders/UserInterfaceShader.wgsl
Original file line number Diff line number Diff line change
@@ -1,71 +1,80 @@
struct PerSceneData {
view: mat4x4f,
perspectiveProjection: mat4x4f,
color: vec4f,
viewportWidth: f32,
viewportHeight: f32,
};

const UI_SCALE_FACTOR = 1.0; // Should likely be moved to the uniforms?
struct VertexInput {
@location(0) position: vec2f,
@location(1) color: u32,
@location(2) diffuseTextureCoords: vec2f,
};

struct WidgetTransform {
transform: vec2f, // 16 (z and w are padding, too)
padding: vec4f, // 32
};
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) color: vec4f,
@location(1) diffuseTextureCoords: vec2f,
};

@group(0) @binding(0) var<uniform> uPerSceneData: PerSceneData;
// CameraBindGroup: Updated once per frame
struct PerSceneData {
view: mat4x4f,
perspectiveProjection: mat4x4f,
color: vec4f,
viewportWidth: f32,
viewportHeight: f32,
};

@group(1) @binding(0) var diffuseTexture: texture_2d<f32>;
@group(1) @binding(1) var diffuseTextureSampler: sampler;
@group(0) @binding(0)
var<uniform> uPerSceneData: PerSceneData;

@group(2) @binding(0) var<uniform> uWidgetTransformData: WidgetTransform;

struct VertexInput {
@location(0) position: vec2f,
@location(1) color: u32,
@location(2) diffuseTextureCoords: vec2f,
};
// MaterialBindGroup: Updated once per unique mesh material
@group(1) @binding(0)
var diffuseTexture: texture_2d<f32>;
@group(1) @binding(1)
var diffuseTextureSampler: sampler;

struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) color: vec4f,
@location(1) diffuseTextureCoords: vec2f,
};

// Should use unpack4xU8 instead, but it's not working in wgpu
fn unpackColorABGR(color: u32) -> vec4<f32> {
let alpha = f32((color >> 24u) & 0xFFu) / 255.0;
let blue = f32((color >> 16u) & 0xFFu) / 255.0;
let green = f32((color >> 8u) & 0xFFu) / 255.0;
let red = f32(color & 0xFFu) / 255.0;
return vec4<f32>(red, green, blue, alpha);
}
// InstanceBindGroup: Updated once per mesh instance
struct WidgetTransform {
transform: vec2f, // 16 (z and w are padding, too)
padding: vec4f, // 32
};

@vertex
fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;
@group(2) @binding(0)
var<uniform> uWidgetTransformData: WidgetTransform;

// Pixel coordinates to NDC
let normalizedX = UI_SCALE_FACTOR * ((in.position.x + uWidgetTransformData.transform.x) / uPerSceneData.viewportWidth) * 2.0 - 1.0;
let normalizedY = -1.0 * UI_SCALE_FACTOR * ((in.position.y + uWidgetTransformData.transform.y) / uPerSceneData.viewportHeight) * 2.0 + 1.0;
out.position = vec4<f32>(normalizedX, normalizedY, 0.0, 1.0);
const UI_SCALE_FACTOR = 1.0; // Should likely be moved to the uniforms?

// WGSL doesn't support u8 colors, so they're packed inside the u32 here
var unpackedColor = unpackColorABGR(in.color);
out.color = vec4f(unpackedColor.x, unpackedColor.y, unpackedColor.z, unpackedColor.w);
// Should use unpack4xU8 instead, but it's not working in wgpu
fn unpackColorABGR(color: u32) -> vec4<f32> {
let alpha = f32((color >> 24u) & 0xFFu) / 255.0;
let blue = f32((color >> 16u) & 0xFFu) / 255.0;
let green = f32((color >> 8u) & 0xFFu) / 255.0;
let red = f32(color & 0xFFu) / 255.0;
return vec4<f32>(red, green, blue, alpha);
}

out.diffuseTextureCoords = in.diffuseTextureCoords;
@vertex
fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput;

return out;
}
// Pixel coordinates to NDC
let normalizedX = UI_SCALE_FACTOR * ((in.position.x + uWidgetTransformData.transform.x) / uPerSceneData.viewportWidth) * 2.0 - 1.0;
let normalizedY = -1.0 * UI_SCALE_FACTOR * ((in.position.y + uWidgetTransformData.transform.y) / uPerSceneData.viewportHeight) * 2.0 + 1.0;
out.position = vec4<f32>(normalizedX, normalizedY, 0.0, 1.0);

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
let textureCoords = in.diffuseTextureCoords;
let diffuseTextureColor = textureSample(diffuseTexture, diffuseTextureSampler, textureCoords);
let finalColor = in.color * diffuseTextureColor;
// WGSL doesn't support u8 colors, so they're packed inside the u32 here
var unpackedColor = unpackColorABGR(in.color);
out.color = vec4f(unpackedColor.x, unpackedColor.y, unpackedColor.z, unpackedColor.w);

// Gamma-correction
let corrected_color = vec4f(pow(finalColor.rgb, vec3f(2.2)), finalColor.w);
return vec4f(corrected_color);
}
out.diffuseTextureCoords = in.diffuseTextureCoords;

return out;
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
let textureCoords = in.diffuseTextureCoords;
let diffuseTextureColor = textureSample(diffuseTexture, diffuseTextureSampler, textureCoords);
let finalColor = in.color * diffuseTextureColor;

// Gamma-correction:
// WebGPU assumes that the colors output by the fragment shader are given in linear space
// When setting the surface format to BGRA8UnormSrgb it performs a linear to sRGB conversion
let gammaCorrectedColor = vec4f(pow(finalColor.rgb, vec3f(2.2)), finalColor.w);
return vec4f(gammaCorrectedColor);
}

0 comments on commit 03f66e6

Please sign in to comment.