aboutsummaryrefslogtreecommitdiff
path: root/assets
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-24 17:07:54 +0200
committerhachem <im@hachem.wtf>2026-08-24 17:07:54 +0200
commit06398a7a176e123506de6e8851866a8bec0b3427 (patch)
tree7167ef4818f2c224840122961882efb5ec26c80b /assets
parent1c85c2ecaa826afd8bf80f93741cf1b2deba5798 (diff)
[chore]: cleanup shaders
Diffstat (limited to 'assets')
-rw-r--r--assets/shaders/blur.slang60
-rw-r--r--assets/shaders/equirect_to_cubemap.slang12
-rw-r--r--assets/shaders/geodesic.slang148
-rw-r--r--assets/shaders/grid.slang26
-rw-r--r--assets/shaders/skybox.slang12
-rw-r--r--assets/shaders/sphere.slang60
-rw-r--r--assets/shaders/textured_quad.slang14
-rw-r--r--assets/shaders/vk_pipeline_test.slang10
8 files changed, 137 insertions, 205 deletions
diff --git a/assets/shaders/blur.slang b/assets/shaders/blur.slang
deleted file mode 100644
index 17e4eae..0000000
--- a/assets/shaders/blur.slang
+++ /dev/null
@@ -1,60 +0,0 @@
-struct VSInput
-{
- float2 position : POSITION;
- float2 texCoord : TEXCOORD0;
-};
-
-struct VSOutput
-{
- float4 position : SV_Position;
- float2 texCoord : TEXCOORD0;
-};
-
-[shader("vertex")]
-VSOutput vertexMain(VSInput input)
-{
- VSOutput output;
- output.position = float4(input.position, 0.0, 1.0);
- output.texCoord = input.texCoord;
- return output;
-}
-
-Sampler2D u_ScreenTexture;
-uniform float2 u_Resolution;
-uniform float u_BlurStrength;
-uniform float u_GlowIntensity;
-
-[shader("fragment")]
-float4 fragmentMain(VSOutput input) : SV_Target
-{
- float2 texelSize = 1.0 / u_Resolution;
- float4 centerColor = u_ScreenTexture.Sample(input.texCoord);
-
- float brightness = (centerColor.r + centerColor.g + centerColor.b) / 3.0;
- float glowMask = smoothstep(0.05, 0.3, brightness);
-
- float4 blurredColor = float4(0.0, 0.0, 0.0, 0.0);
- float totalWeight = 0.0;
-
- for (int x = -8; x <= 8; x++)
- {
- for (int y = -8; y <= 8; y++)
- {
- float2 offset = float2(x, y) * texelSize * u_BlurStrength;
- float4 sampleColor = u_ScreenTexture.Sample(input.texCoord + offset);
-
- float weight = exp(-float(x * x + y * y) / (2.0 * 8.0 * 8.0));
- blurredColor += sampleColor * weight;
- totalWeight += weight;
- }
- }
-
- blurredColor /= totalWeight;
-
- float3 emissionColor = float3(1.0, 0.8, 0.6);
- float3 glowColor = emissionColor * glowMask * u_GlowIntensity * 2.0;
- float3 auraColor = blurredColor.rgb * glowMask * u_GlowIntensity * 0.8;
- float3 finalColor = centerColor.rgb + glowColor + auraColor;
-
- return float4(finalColor, centerColor.a);
-}
diff --git a/assets/shaders/equirect_to_cubemap.slang b/assets/shaders/equirect_to_cubemap.slang
index 9b2ea4b..510e6b0 100644
--- a/assets/shaders/equirect_to_cubemap.slang
+++ b/assets/shaders/equirect_to_cubemap.slang
@@ -1,5 +1,11 @@
-uniform float4x4 u_Projection;
-uniform float4x4 u_View;
+// Equirectangular HDRI -> cubemap face projection. NOTE: the OpenGL path uses the
+// hand-written assets/shaders/EquirectToCubemap.glsl instead; this Slang version
+// feeds the Vulkan cubemap bake (vulkan_cubemap.cpp), which binds the view /
+// projection as a $Globals UBO. Kept as loose `uniform` globals (not a
+// ConstantBuffer) so both paths bind them the same way.
+
+uniform float4x4 u_projection;
+uniform float4x4 u_view;
struct VSInput { float3 position : POSITION; };
struct VSOutput { float4 position : SV_Position; float3 worldPos : TEXCOORD0; };
@@ -9,7 +15,7 @@ VSOutput vertexMain(VSInput input)
{
VSOutput output;
output.worldPos = input.position;
- output.position = mul(u_Projection, mul(u_View, float4(input.position, 1.0)));
+ output.position = mul(u_projection, mul(u_view, float4(input.position, 1.0)));
return output;
}
diff --git a/assets/shaders/geodesic.slang b/assets/shaders/geodesic.slang
index eee62da..eb536c9 100644
--- a/assets/shaders/geodesic.slang
+++ b/assets/shaders/geodesic.slang
@@ -1,3 +1,9 @@
+// Ray-traced Schwarzschild black hole: back-traces one null geodesic per pixel
+// through curved spacetime, shading the accretion disk, the lensed HDRI
+// background, and placed objects. Runs as a full-screen fragment pass. Uniforms
+// live in ConstantBuffers (UBOs) driven through the RHI; the HDRI is a cubemap
+// sampler. See docs/physics.md for the maths.
+
struct VSInput { float2 position : POSITION; float2 texCoord : TEXCOORD0; };
struct VSOutput { float4 position : SV_Position; float2 texCoord : TEXCOORD0; };
@@ -12,54 +18,44 @@ VSOutput vertexMain(VSInput input)
struct Camera
{
- float3 camPos; float _pad0;
- float3 camRight; float _pad1;
- float3 camUp; float _pad2;
- float3 camForward; float _pad3;
- float tanHalfFov;
- float aspect;
- bool moving;
- int outputChannel; // 0 = colour; 1 = redshift g; 2 = emission T; 3 = impact parameter
- int rawOutput; // 0 = display (false-colour / tone-mapped); 1 = raw float value
+ float3 u_cam_pos; float _pad0;
+ float3 u_cam_right; float _pad1;
+ float3 u_cam_up; float _pad2;
+ float3 u_cam_forward; float _pad3;
+ float u_tan_half_fov;
+ float u_aspect;
+ bool u_moving;
+ int u_output_channel; // 0 = colour; 1 = redshift g; 2 = emission T; 3 = impact parameter
+ int u_raw_output; // 0 = display (false-colour / tone-mapped); 1 = raw float value
};
-
-// A jet-ish false-colour ramp (blue -> cyan -> green -> yellow -> red) for the
-// observable export channels. t is expected in [0, 1].
-float3 Falsecolor(float t)
-{
- t = clamp(t, 0.0, 1.0);
- return clamp(float3(1.5 - abs(4.0 * t - 3.0),
- 1.5 - abs(4.0 * t - 2.0),
- 1.5 - abs(4.0 * t - 1.0)), 0.0, 1.0);
-}
ConstantBuffer<Camera> cam;
struct Disk
{
- float disk_r1; // inner edge (clamped to the ISCO, 3 r_s, below)
- float disk_r2; // outer edge
- float disk_num; // turbulence strength (0 = smooth physical disk)
- float thickness; // slab half-height (anti-aliases the edge-on disk)
- float disk_density; // disk brightness / exposure
- float temperature; // Kelvin at the flux peak (disk colour)
+ float u_inner_radius; // inner edge (clamped to the ISCO, 3 r_s, below)
+ float u_outer_radius; // outer edge
+ float u_turbulence; // turbulence strength (0 = smooth physical disk)
+ float u_thickness; // slab half-height (anti-aliases the edge-on disk)
+ float u_brightness; // disk brightness / exposure
+ float u_temperature; // Kelvin at the flux peak (disk colour)
};
ConstantBuffer<Disk> disk;
struct Objects
{
- int numObjects;
- float4 objPosRadius[16];
- float4 objColor[16];
- float mass[16];
+ int u_num_objects;
+ float4 u_obj_pos_radius[16];
+ float4 u_obj_color[16];
+ float u_mass[16];
};
ConstantBuffer<Objects> obj;
struct Simulation
{
- int maxStepsMoving;
- int maxStepsStatic;
- float earlyExitDistance;
- float time;
+ int u_max_steps_moving;
+ int u_max_steps_static;
+ float u_early_exit_distance;
+ float u_time;
};
ConstantBuffer<Simulation> sim;
@@ -163,8 +159,8 @@ float3 DiskEmission(float3 P, float3 rayDir, out float outG, out float outTemit)
{
outG = 0.0; outTemit = 0.0;
float rc = length(float2(P.x, P.z)); // cylindrical radius (disk axis = +Y)
- float rin = max(disk.disk_r1, R_ISCO);
- float rout = disk.disk_r2;
+ float rin = max(disk.u_inner_radius, R_ISCO);
+ float rout = disk.u_outer_radius;
if (rc < rin || rc > rout)
return float3(0.0);
@@ -173,7 +169,7 @@ float3 DiskEmission(float3 P, float3 rayDir, out float outG, out float outTemit)
float xr = rc / rin;
float flux = max((1.0 - sqrt(1.0 / xr)) / (xr * xr * xr), 0.0);
float Tn = pow(flux / FLUX_PEAK, 0.25); // normalised temperature, peak ~ 1
- float Temit = disk.temperature * Tn;
+ float Temit = disk.u_temperature * Tn;
// Keplerian orbit (prograde about +Y). Locally-measured orbital speed for a
// Schwarzschild circular geodesic: v = sqrt( M / (r - 2M) ) = 0.5 c at ISCO.
@@ -198,18 +194,18 @@ float3 DiskEmission(float3 P, float3 rayDir, out float outG, out float outTemit)
float edge = smoothstep(rin, rin * 1.12, rc) * (1.0 - smoothstep(rout * 0.88, rout, rc));
bright *= edge;
- // Optional turbulence overlay (disk.disk_num = strength; 0 = smooth).
- if (disk.disk_num > 0.0)
+ // Optional turbulence overlay (disk.u_turbulence = strength; 0 = smooth).
+ if (disk.u_turbulence > 0.0)
{
- float ang = sim.time * 0.3 / sqrt(xr);
+ float ang = sim.u_time * 0.3 / sqrt(xr);
float3 rp = float3(P.x * cos(ang) - P.z * sin(ang),
0.0,
P.x * sin(ang) + P.z * cos(ang)) * 1e-10;
- float turb = 1.0 + disk.disk_num * (fbm(rp * 3.0, 3) - 0.5);
+ float turb = 1.0 + disk.u_turbulence * (fbm(rp * 3.0, 3) - 0.5);
bright *= max(turb, 0.0);
}
- return colour * bright * max(disk.disk_density, 0.0);
+ return colour * bright * max(disk.u_brightness, 0.0);
}
struct Ray
@@ -255,15 +251,15 @@ bool Intercept(Ray ray, float rs) { return ray.r <= rs; }
bool InterceptObject(Ray ray, inout Hit hit)
{
float3 P = float3(ray.x, ray.y, ray.z);
- for (int i = 0; i < obj.numObjects; ++i)
+ for (int i = 0; i < obj.u_num_objects; ++i)
{
- float3 center = obj.objPosRadius[i].xyz;
- float radius = obj.objPosRadius[i].w;
+ float3 center = obj.u_obj_pos_radius[i].xyz;
+ float radius = obj.u_obj_pos_radius[i].w;
float distSq = dot(P - center, P - center);
if (distSq > radius * radius * 4.0) continue;
if (distSq <= radius * radius)
{
- hit.objectColor = obj.objColor[i];
+ hit.objectColor = obj.u_obj_color[i];
hit.hitCenter = center;
hit.hitRadius = radius;
return true;
@@ -317,8 +313,8 @@ float CalculateAdaptiveStepSize(Ray ray, float baseStepSize)
// Slow down when near the disk plane (within its radial extent) so the thin
// slab is never stepped over -- otherwise grazing rays leak through it.
float rc = length(float2(ray.x, ray.z));
- if (rc < disk.disk_r2 * 3.0 && abs(ray.y) < disk.thickness * 8.0)
- step = min(step, disk.thickness);
+ if (rc < disk.u_outer_radius * 3.0 && abs(ray.y) < disk.u_thickness * 8.0)
+ step = min(step, disk.u_thickness);
return clamp(step, MIN_STEP_SIZE, MAX_STEP_SIZE);
}
@@ -328,15 +324,25 @@ float3 ACESFilm(float3 x)
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
}
+// A jet-ish false-colour ramp (blue -> cyan -> green -> yellow -> red) for the
+// observable export channels. t is expected in [0, 1].
+float3 Falsecolor(float t)
+{
+ t = clamp(t, 0.0, 1.0);
+ return clamp(float3(1.5 - abs(4.0 * t - 3.0),
+ 1.5 - abs(4.0 * t - 2.0),
+ 1.5 - abs(4.0 * t - 1.0)), 0.0, 1.0);
+}
+
// Trace one primary ray for the given image UV and return its linear,
// pre-tone-map radiance. Called once per sub-sample by fragmentMain.
float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool outHitDisk)
{
outG = 0.0; outTemit = 0.0; outHitDisk = false;
- float u = (2.0 * texCoord.x - 1.0) * cam.aspect * cam.tanHalfFov;
- float v = (1.0 - 2.0 * texCoord.y) * cam.tanHalfFov;
- float3 dir = normalize(u * cam.camRight - v * cam.camUp + cam.camForward);
- Ray ray = InitRay(cam.camPos, dir);
+ float u = (2.0 * texCoord.x - 1.0) * cam.u_aspect * cam.u_tan_half_fov;
+ float v = (1.0 - 2.0 * texCoord.y) * cam.u_tan_half_fov;
+ float3 dir = normalize(u * cam.u_cam_right - v * cam.u_cam_up + cam.u_cam_forward);
+ Ray ray = InitRay(cam.u_cam_pos, dir);
bool hitBlackHole = false;
bool hitObject = false;
@@ -348,11 +354,11 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool
bool hitDisk = false;
float3 diskColor = float3(0.0); // emission of the first (opaque) disk surface hit
- int maxSteps = cam.moving ? sim.maxStepsMoving : sim.maxStepsStatic;
+ int maxSteps = cam.u_moving ? sim.u_max_steps_moving : sim.u_max_steps_static;
if (maxSteps <= 0)
- maxSteps = cam.moving ? DEFAULT_MAX_STEPS_MOVING : DEFAULT_MAX_STEPS_STATIC;
+ maxSteps = cam.u_moving ? DEFAULT_MAX_STEPS_MOVING : DEFAULT_MAX_STEPS_STATIC;
- float exitDistance = sim.earlyExitDistance > 0.0 ? sim.earlyExitDistance : DEFAULT_EARLY_EXIT_DISTANCE;
+ float exitDistance = sim.u_early_exit_distance > 0.0 ? sim.u_early_exit_distance : DEFAULT_EARLY_EXIT_DISTANCE;
int objectCheckInterval = 5;
for (int i = 0; i < maxSteps; ++i)
@@ -370,7 +376,7 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool
// while grazing along it. Real (nonzero) thickness stops the zero-height
// edge-on "razor" from aliasing into a beam streaking across the frame.
{
- float H = disk.thickness;
+ float H = disk.u_thickness;
bool crossed = prevPos.y * newPos.y < 0.0;
bool inSlab = abs(newPos.y) <= H;
if (crossed || inSlab)
@@ -379,7 +385,7 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool
? lerp(prevPos, newPos, prevPos.y / (prevPos.y - newPos.y))
: newPos;
float rc = length(float2(hitP.x, hitP.z));
- if (rc >= max(disk.disk_r1, R_ISCO) && rc <= disk.disk_r2)
+ if (rc >= max(disk.u_inner_radius, R_ISCO) && rc <= disk.u_outer_radius)
{
diskColor = DiskEmission(hitP, newPos - prevPos, outG, outTemit);
hitDisk = true;
@@ -400,7 +406,7 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool
// Computed UNCONDITIONALLY (before the branch) so ddx/ddy are valid; strongly
// lensed background rays diverge fast, so they read a blurred cubemap mip and
// the starfield stops aliasing into a fan along the equatorial plane.
- float3 rayDir = normalize(float3(ray.x, ray.y, ray.z) - cam.camPos);
+ float3 rayDir = normalize(float3(ray.x, ray.y, ray.z) - cam.u_cam_pos);
float footprint = max(length(ddx(rayDir)), length(ddy(rayDir)));
float envLod = clamp(log2(max(footprint / 0.0015, 1.0)), 0.0, 10.0);
@@ -417,7 +423,7 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool
{
float3 P = float3(ray.x, ray.y, ray.z);
float3 N = normalize(P - hit.hitCenter);
- float3 V = normalize(cam.camPos - P);
+ float3 V = normalize(cam.u_cam_pos - P);
float intensity = 0.1 + 0.9 * max(dot(N, V), 0.0);
shade = hit.objectColor.rgb * intensity;
}
@@ -438,41 +444,41 @@ float4 fragmentMain(VSOutput input) : SV_Target
// ordered grid). Radiance is averaged before tone-mapping; ddx/ddy give the
// resolution-correct per-pixel UV footprint.
// Observable export channels: the chosen scalar quantity, either as a raw
- // float (rawOutput: value in RGB, validity mask in A) or false-coloured.
+ // float (u_raw_output: value in RGB, validity mask in A) or false-coloured.
// Channel 0 is the normal colour image.
- if (cam.outputChannel != 0)
+ if (cam.u_output_channel != 0)
{
float g, Temit; bool hitDisk;
TracePixel(input.texCoord, g, Temit, hitDisk);
float value; float valid = 1.0;
- if (cam.outputChannel == 3) // impact parameter: a per-ray geometric quantity (r_s)
+ if (cam.u_output_channel == 3) // impact parameter: a per-ray geometric quantity (r_s)
{
- float uu = (2.0 * input.texCoord.x - 1.0) * cam.aspect * cam.tanHalfFov;
- float vv = (1.0 - 2.0 * input.texCoord.y) * cam.tanHalfFov;
- float3 dir = normalize(uu * cam.camRight - vv * cam.camUp + cam.camForward);
- value = length(cross(cam.camPos, dir)) / SagA_rs;
+ float uu = (2.0 * input.texCoord.x - 1.0) * cam.u_aspect * cam.u_tan_half_fov;
+ float vv = (1.0 - 2.0 * input.texCoord.y) * cam.u_tan_half_fov;
+ float3 dir = normalize(uu * cam.u_cam_right - vv * cam.u_cam_up + cam.u_cam_forward);
+ value = length(cross(cam.u_cam_pos, dir)) / SagA_rs;
}
else // g / T are disk-only
{
valid = hitDisk ? 1.0 : 0.0;
- value = (cam.outputChannel == 1) ? g : Temit;
+ value = (cam.u_output_channel == 1) ? g : Temit;
}
- if (cam.rawOutput != 0)
+ if (cam.u_raw_output != 0)
return float4(value, value, value, valid); // raw: physical value + validity
if (valid < 0.5) return float4(0.0, 0.0, 0.0, 1.0);
- float norm = (cam.outputChannel == 1) ? value / 1.5
- : (cam.outputChannel == 2) ? value / 15000.0
+ float norm = (cam.u_output_channel == 1) ? value / 1.5
+ : (cam.u_output_channel == 2) ? value / 15000.0
: value / 30.0;
return float4(Falsecolor(norm), 1.0);
}
float _g, _t; bool _hd;
- if (cam.rawOutput != 0) // raw colour: linear pre-tone-map radiance (HDR)
+ if (cam.u_raw_output != 0) // raw colour: linear pre-tone-map radiance (HDR)
return float4(TracePixel(input.texCoord, _g, _t, _hd), 1.0);
- if (cam.moving)
+ if (cam.u_moving)
return float4(ACESFilm(TracePixel(input.texCoord, _g, _t, _hd)), 1.0);
float2 dUV = float2(ddx(input.texCoord.x), ddy(input.texCoord.y));
diff --git a/assets/shaders/grid.slang b/assets/shaders/grid.slang
index f549cb1..8dc4362 100644
--- a/assets/shaders/grid.slang
+++ b/assets/shaders/grid.slang
@@ -1,15 +1,15 @@
// Reference grid on the XZ plane. Uniforms live in a ConstantBuffer (UBO) so both
// backends drive it through the same RHI path (bind a uniform buffer at binding 0).
-struct GridU
+struct Grid
{
- float4x4 u_ViewProjection;
- float4x4 u_Transform;
- float u_GridSize;
- float3 u_GridColor;
- float u_GridAlpha;
- float3 u_CameraPos;
+ float4x4 u_view_projection;
+ float4x4 u_transform;
+ float u_grid_size;
+ float3 u_grid_color;
+ float u_grid_alpha;
+ float3 u_camera_pos;
};
-ConstantBuffer<GridU> gu;
+ConstantBuffer<Grid> gu;
struct VSInput { float3 position : POSITION; };
struct VSOutput { float4 position : SV_Position; };
@@ -18,19 +18,19 @@ struct VSOutput { float4 position : SV_Position; };
VSOutput vertexMain(VSInput input)
{
VSOutput output;
- float3 scaledPosition = input.position * (gu.u_GridSize / 50.0);
- output.position = mul(gu.u_ViewProjection, mul(gu.u_Transform, float4(scaledPosition, 1.0)));
+ float3 scaledPosition = input.position * (gu.u_grid_size / 50.0);
+ output.position = mul(gu.u_view_projection, mul(gu.u_transform, float4(scaledPosition, 1.0)));
return output;
}
[shader("fragment")]
float4 fragmentMain(VSOutput input) : SV_Target
{
- float dist = length(gu.u_CameraPos);
+ float dist = length(gu.u_camera_pos);
float fadeFactor = 1.0 - clamp(dist / 100.0, 0.0, 0.8);
- float3 color = gu.u_GridColor;
- float alpha = gu.u_GridAlpha * fadeFactor;
+ float3 color = gu.u_grid_color;
+ float alpha = gu.u_grid_alpha * fadeFactor;
float gridFade = 1.0 - clamp(dist / 50.0, 0.0, 0.9);
alpha *= gridFade;
diff --git a/assets/shaders/skybox.slang b/assets/shaders/skybox.slang
index 6447bea..f7aeb50 100644
--- a/assets/shaders/skybox.slang
+++ b/assets/shaders/skybox.slang
@@ -1,11 +1,11 @@
-// Fullscreen skybox cube. View/projection in a ConstantBuffer (UBO, binding 0)
+// Full-screen skybox cube. View/projection in a ConstantBuffer (UBO, binding 0)
// so both backends drive it through the RHI; the cubemap is a sampler at binding 1.
-struct SkyboxU
+struct Skybox
{
- float4x4 u_Projection;
- float4x4 u_View;
+ float4x4 u_projection;
+ float4x4 u_view;
};
-ConstantBuffer<SkyboxU> sb;
+ConstantBuffer<Skybox> sb;
struct VSInput { float3 position : POSITION; };
struct VSOutput { float4 position : SV_Position; float3 texCoords : TEXCOORD0; };
@@ -15,7 +15,7 @@ VSOutput vertexMain(VSInput input)
{
VSOutput output;
output.texCoords = input.position;
- float4 pos = mul(sb.u_Projection, mul(sb.u_View, float4(input.position, 1.0)));
+ float4 pos = mul(sb.u_projection, mul(sb.u_view, float4(input.position, 1.0)));
output.position = pos.xyww; // force depth = 1 so the skybox stays behind everything
return output;
}
diff --git a/assets/shaders/sphere.slang b/assets/shaders/sphere.slang
index e37700d..41badde 100644
--- a/assets/shaders/sphere.slang
+++ b/assets/shaders/sphere.slang
@@ -1,42 +1,32 @@
// Lit sphere (Blinn-Phong + HDRI ambient + selection rim). Uniforms in a
// ConstantBuffer (UBO, binding 0) so both backends drive it through the RHI;
// the environment cubemap is a separate sampler at binding 1.
-struct SphereU
+struct Sphere
{
- float4x4 u_ViewProjection;
- float4x4 u_Transform;
- float3 u_Color;
- float u_Specular;
- float u_Emission;
- float3 u_LightPos;
- float3 u_CameraPos;
- int u_IsSelected;
- float3 u_OutlineColor;
- float u_OutlineWidth;
+ float4x4 u_view_projection;
+ float4x4 u_transform;
+ float3 u_color;
+ float u_specular;
+ float u_emission;
+ float3 u_light_pos;
+ float3 u_camera_pos;
+ int u_is_selected;
+ float3 u_outline_color;
+ float u_outline_width;
};
-ConstantBuffer<SphereU> su;
+ConstantBuffer<Sphere> su;
-struct VSInput
-{
- float3 position : POSITION;
- float3 normal : NORMAL;
-};
-
-struct VSOutput
-{
- float4 position : SV_Position;
- float3 normal : TEXCOORD0;
- float3 worldPos : TEXCOORD1;
-};
+struct VSInput { float3 position : POSITION; float3 normal : NORMAL; };
+struct VSOutput { float4 position : SV_Position; float3 normal : TEXCOORD0; float3 worldPos : TEXCOORD1; };
[shader("vertex")]
VSOutput vertexMain(VSInput input)
{
VSOutput output;
- output.worldPos = mul(su.u_Transform, float4(input.position, 1.0)).xyz;
- float3x3 normalMatrix = (float3x3)su.u_Transform;
+ output.worldPos = mul(su.u_transform, float4(input.position, 1.0)).xyz;
+ float3x3 normalMatrix = (float3x3)su.u_transform;
output.normal = mul(normalMatrix, input.normal);
- output.position = mul(su.u_ViewProjection, float4(output.worldPos, 1.0));
+ output.position = mul(su.u_view_projection, float4(output.worldPos, 1.0));
return output;
}
@@ -46,8 +36,8 @@ SamplerCube u_HDRIEnvironment;
float4 fragmentMain(VSOutput input) : SV_Target
{
float3 normal = normalize(input.normal);
- float3 lightDir = normalize(su.u_LightPos - input.worldPos);
- float3 viewDir = normalize(su.u_CameraPos - input.worldPos);
+ float3 lightDir = normalize(su.u_light_pos - input.worldPos);
+ float3 viewDir = normalize(su.u_camera_pos - input.worldPos);
float3 reflectDir = reflect(-lightDir, normal);
float3 hdriLight = u_HDRIEnvironment.Sample(normal).rgb;
@@ -56,18 +46,18 @@ float4 fragmentMain(VSOutput input) : SV_Target
float diff = max(dot(normal, lightDir), 0.0);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
- float3 diffuse = su.u_Color * (diff + hdriIntensity * hdriLight);
- float3 specular = float3(su.u_Specular, su.u_Specular, su.u_Specular) * spec;
- float3 emission = su.u_Color * su.u_Emission;
+ float3 diffuse = su.u_color * (diff + hdriIntensity * hdriLight);
+ float3 specular = float3(su.u_specular, su.u_specular, su.u_specular) * spec;
+ float3 emission = su.u_color * su.u_emission;
float3 result = diffuse + specular + emission;
- if (su.u_IsSelected > 0)
+ if (su.u_is_selected > 0)
{
float ndotv = max(dot(normal, viewDir), 0.0);
float rim = 1.0 - ndotv;
- float outlineMask = step(1.0 - su.u_OutlineWidth, rim);
- result = lerp(result, su.u_OutlineColor, outlineMask);
+ float outlineMask = step(1.0 - su.u_outline_width, rim);
+ result = lerp(result, su.u_outline_color, outlineMask);
}
return float4(result, 1.0);
diff --git a/assets/shaders/textured_quad.slang b/assets/shaders/textured_quad.slang
index 52d46ed..b72db81 100644
--- a/assets/shaders/textured_quad.slang
+++ b/assets/shaders/textured_quad.slang
@@ -1,14 +1,8 @@
-struct VSInput
-{
- float2 position : POSITION;
- float2 texCoord : TEXCOORD0;
-};
+// Full-screen textured quad: samples one 2D texture straight to the target.
+// Used to blit an off-screen colour buffer to the swapchain.
-struct VSOutput
-{
- float4 position : SV_Position;
- float2 texCoord : TEXCOORD0;
-};
+struct VSInput { float2 position : POSITION; float2 texCoord : TEXCOORD0; };
+struct VSOutput { float4 position : SV_Position; float2 texCoord : TEXCOORD0; };
[shader("vertex")]
VSOutput vertexMain(VSInput input)
diff --git a/assets/shaders/vk_pipeline_test.slang b/assets/shaders/vk_pipeline_test.slang
index f4d1897..453fcd3 100644
--- a/assets/shaders/vk_pipeline_test.slang
+++ b/assets/shaders/vk_pipeline_test.slang
@@ -1,12 +1,8 @@
// Minimal shader used only to verify the Vulkan graphics-pipeline path (SPIR-V
-// module -> pipeline -> draw -> read-back). Draws a full-screen gradient
-// triangle from the vertex id, so it needs no vertex buffer, UBO, or sampler.
+// module -> pipeline -> draw -> read-back). Draws a full-screen gradient triangle
+// from the vertex id, so it needs no vertex buffer, UBO, or sampler.
-struct VSOutput
-{
- float4 position : SV_Position;
- float3 color : COLOR0;
-};
+struct VSOutput { float4 position : SV_Position; float3 color : COLOR0; };
[shader("vertex")]
VSOutput vertexMain(uint vid : SV_VertexID)