Skip to content

Add RTX Raytracing #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
375 changes: 215 additions & 160 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ env_logger = "0.8.2"
log = "0.4.14"
thiserror = "1.0.23"
anyhow = "1.0.40"
ash = "0.31.0"
ash-window = "0.5.0"
vk-mem = { git = "https://github.com/gwihlidal/vk-mem-rs", version = "0.2.3" }
ash = "0.33.0"
ash-window = "0.7.0"
gpu-allocator = { git="https://github.com/Traverse-Research/gpu-allocator" }
winit = "0.24.0"
image = "0.23.13"
crystal = { path = "crystal" }
Expand Down
3 changes: 2 additions & 1 deletion crystal/src/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ impl<T, const R: usize, const C: usize> Matrix<T, R, C> {
(R, C)
}

#[allow(clippy::uninit_assumed_init)]
pub(crate) unsafe fn uninitialized() -> Matrix<T, R, C> {
Self::from_data(std::mem::MaybeUninit::uninit().assume_init())
Self::from_data(std::mem::MaybeUninit::uninit().assume_init()) // TODO: undefined behavior
}

pub fn get<I>(&self, index: I) -> Option<&I::Output>
Expand Down
5 changes: 5 additions & 0 deletions examples/brdf/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ fn setup(engine: &mut Engine) {
mesh_data_sphere_smooth,
(*engine.vulkan_manager.allocator).clone(),
&mut engine.vulkan_manager.uploader,
engine
.vulkan_manager
.rtx_data
.as_ref()
.map(|rtx_data| rtx_data.acc_ext.clone()),
)
.unwrap();

Expand Down
5 changes: 5 additions & 0 deletions examples/mesh/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ fn setup(engine: &mut Engine) {
mesh_data,
(*engine.vulkan_manager.allocator).clone(),
&mut engine.vulkan_manager.uploader,
engine
.vulkan_manager
.rtx_data
.as_ref()
.map(|rtx_data| rtx_data.acc_ext.clone()),
)
.expect("Error baking mesh!");

Expand Down
5 changes: 5 additions & 0 deletions examples/minimal/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ fn setup(engine: &mut Engine) {
mesh_data,
(*engine.vulkan_manager.allocator).clone(),
&mut engine.vulkan_manager.uploader,
engine
.vulkan_manager
.rtx_data
.as_ref()
.map(|rtx_data| rtx_data.acc_ext.clone()),
)
.unwrap();

Expand Down
8 changes: 6 additions & 2 deletions examples/textured_material/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ fn setup(engine: &mut Engine) {
(*engine.vulkan_manager.allocator).clone(),
&mut engine.vulkan_manager.uploader,
engine.vulkan_manager.device.clone(),
)
.unwrap();
);

let material0 = pipeline.create_material().unwrap();
material0.set_float("metallic", 0.0).unwrap();
Expand Down Expand Up @@ -147,6 +146,11 @@ fn setup(engine: &mut Engine) {
mesh_data,
(*engine.vulkan_manager.allocator).clone(),
&mut engine.vulkan_manager.uploader,
engine
.vulkan_manager
.rtx_data
.as_ref()
.map(|rtx_data| rtx_data.acc_ext.clone()),
)
.unwrap();

Expand Down
63 changes: 63 additions & 0 deletions shaders/brdf.hlslh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@


static const float PI = 3.1415926535897932384626433832795;

// Schlicks approximation (approximates r_0 = ((n_1 - n_2)/(n_1 + n_2))^2)
float3 schlick(float3 r0, float cosTheta) {
// we could use pow, but then it do all the float checks - which we don't need
return r0 + (1.0 - r0) * (1.0 - cosTheta) * (1.0 - cosTheta) * (1.0 - cosTheta) * (1.0 - cosTheta) * (1.0 - cosTheta);
}

// normal distribution function: Trowbridge-Reitz GGX
float distributionGGX(float3 normal, float3 halfVector, float roughness) {
float a = roughness * roughness; // rougness apparently looks more "correct", when beeing squared (according to Disney)
float a2 = a * a;
float nDotH = max(dot(normal, halfVector), 0.0);
float nDotH2 = nDotH * nDotH;

float denom = (nDotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;

return a2 / denom;
}

// geometry function: Schlick-GGX
float geometrySchlickGGX(float vec, float roughness) {
float r = roughness + 1.0;
float k = (r * r) / 8.0;

float denom = vec * (1.0 - k) + k;

return vec / denom;
}

// approximate geometry: account for view dir and light dir: Smith's method
float geometrySmith(float nDotV, float nDotL, float roughness) {
return geometrySchlickGGX(nDotL, roughness) * geometrySchlickGGX(nDotV, roughness);
}

float3 computeRadiance(float3 irradiance, float3 lightDirection, float3 normal, float3 cameraDirection, float3 surfaceColor, float metallic, float roughness) {
// utils
float3 halfVector = normalize(cameraDirection + lightDirection);
float nDotH = max(dot(normal, halfVector), 0.0);
float nDotL = max(dot(normal, lightDirection), 0.0);
float hDotV = max(dot(halfVector, cameraDirection), 0.0);
float nDotV = max(dot(normal, cameraDirection), 0.0);

float3 f0 = lerp(float3(0.04), surfaceColor, float3(metallic)); // base relectivity: use 0.04 for non-metallic/dialectic materials else use the surface color
float3 f = schlick(f0, hDotV);

float ndf = distributionGGX(normal, halfVector, roughness);
float geometry = geometrySmith(nDotV, nDotL, roughness);

// Cook-Torrance BRDF
float3 numerator = ndf * geometry * f;
float denominator = 4.0 * nDotV * nDotL;
float3 specular = numerator / max(denominator, 0.001);

float3 kS = f; // energy of light that gets reflected
float3 kD = float3(1.0) - kS; // remaining light that gets refracted
kD *= 1.0 - metallic; // metalls don't refract, so set it to 0 if it's a metal

return (kD * surfaceColor / PI + specular) * irradiance * nDotL;
}
25 changes: 25 additions & 0 deletions shaders/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

for src in *.hlsl; do
echo Compiling Vulkan HLSL shader $src
glslc.exe --target-env=vulkan1.2 -fauto-combined-image-sampler -fshader-stage=vert -fentry-point=vert $src -o ../assets/shaders/$(basename $src .hlsl)-vert.spv
glslc.exe --target-env=vulkan1.2 -fauto-combined-image-sampler -fshader-stage=frag -fentry-point=frag $src -o ../assets/shaders/$(basename $src .hlsl)-frag.spv
done

for src in *.rgen.glsl; do
[ -f "$src" ] || continue
echo Compiling Raygen shader $src
glslc.exe --target-env=vulkan1.2 -fshader-stage=rgen $src -o ../assets/shaders/$(basename $src .glsl).spv
done

for src in *.rchit.glsl; do
[ -f "$src" ] || continue
echo Compiling Ray closest-hit shader $src
glslc.exe --target-env=vulkan1.2 -fshader-stage=rchit $src -o ../assets/shaders/$(basename $src .glsl).spv
done

for src in *.rmiss.glsl; do
[ -f "$src" ] || continue
echo Compiling Ray miss shader $src
glslc.exe --target-env=vulkan1.2 -fshader-stage=rmiss $src -o ../assets/shaders/$(basename $src .glsl).spv
done
10 changes: 10 additions & 0 deletions shaders/common.hlslh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

struct Cam {
float4x4 viewMatrix;
float4x4 projMatrix;
float4x4 invViewMatrix;
float4x4 invProjMatrix;
float3 position;
};

#define CAM_BINDING [[vk::binding(0, 0)]]
40 changes: 40 additions & 0 deletions shaders/deferred_directional_brdf.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "resolve.hlslh"
#include "brdf.hlslh"

struct Frag {
float4 color : SV_TARGET0;
};

DEFAULT_VERTEX_SHADER

GBUF0_BINDING SubpassInput in_AlbedoRoughness;
GBUF1_BINDING SubpassInput in_NormalMetallic;
GBUF_DEPTH_BINDING SubpassInput in_Depth;

CAM_BINDING ConstantBuffer<Cam> u_Cam;
LIGHT_BINDING ConstantBuffer<DirLight> u_Light;

Frag frag(V2F fIn) {
Frag res;

float4 albedoRoughness = in_AlbedoRoughness.SubpassLoad();
float4 normalMetallic = in_NormalMetallic.SubpassLoad();
float depth = in_Depth.SubpassLoad().r;

float3 albedo = albedoRoughness.rgb;
float roughness = albedoRoughness.a;
float3 worldNormal = normalize(normalMetallic.rgb);
float metallic = normalMetallic.a;

CALC_WORLD_POS(fIn.uv, depth, u_Cam.invProjMatrix, u_Cam.invViewMatrix);

float3 dirToCam = normalize(u_Cam.position - worldPos);

float3 dirToLight = u_Light.directionToLight.xyz;
float3 irradiance = u_Light.irradiance.rgb;

float3 radiance = computeRadiance(irradiance, normalize(dirToLight), worldNormal, dirToCam, albedo, metallic, roughness);
res.color = float4(radiance, 1.0);

return res;
}
41 changes: 41 additions & 0 deletions shaders/deferred_point_brdf.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "resolve.hlslh"
#include "brdf.hlslh"

struct Frag {
float4 color : SV_TARGET0;
};

DEFAULT_VERTEX_SHADER

GBUF0_BINDING SubpassInput in_AlbedoRoughness;
GBUF1_BINDING SubpassInput in_NormalMetallic;
GBUF_DEPTH_BINDING SubpassInput in_Depth;

CAM_BINDING ConstantBuffer<Cam> u_Cam;
LIGHT_BINDING ConstantBuffer<PointLight> u_Light;

Frag frag(V2F fIn) {
Frag res;

float4 albedoRoughness = in_AlbedoRoughness.SubpassLoad();
float4 normalMetallic = in_NormalMetallic.SubpassLoad();
float depth = in_Depth.SubpassLoad().r;

float3 albedo = albedoRoughness.rgb;
float roughness = albedoRoughness.a;
float3 worldNormal = normalize(normalMetallic.rgb);
float metallic = normalMetallic.a;

CALC_WORLD_POS(fIn.uv, depth, u_Cam.invProjMatrix, u_Cam.invViewMatrix);

float3 dirToCam = normalize(u_Cam.position - worldPos);

float3 dirToLight = normalize(u_Light.position.xyz - worldPos);
float d = length(worldPos - u_Light.position);
float3 irradiance = u_Light.luminousFlux.rgb / (4.0 * PI * d * d);

float3 radiance = computeRadiance(irradiance, dirToLight, worldNormal, dirToCam, albedo, metallic, roughness);

res.color = float4(radiance, 1.0);
return res;
}
25 changes: 25 additions & 0 deletions shaders/deferred_unlit.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "resolve.hlslh"

struct Frag {
float4 color : SV_TARGET0;
};

CAM_BINDING ConstantBuffer<Cam> u_Cam;
GBUF0_BINDING SubpassInput in_AlbedoRoughness;
GBUF1_BINDING SubpassInput in_NormalMetallic;
GBUF_DEPTH_BINDING SubpassInput in_Depth;

DEFAULT_VERTEX_SHADER

Frag frag(V2F fIn) {
Frag res;

float4 albedoRoughness = in_AlbedoRoughness.SubpassLoad();
float4 normalMetallic = in_NormalMetallic.SubpassLoad();
float depth = in_Depth.SubpassLoad().r;

float3 albedo = albedoRoughness.rgb;
res.color = float4(albedo, 1.0);

return res;
}
18 changes: 18 additions & 0 deletions shaders/gpass.hlslh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

#include "common.hlslh"

struct Vert {
float3 position;
float3 color;
float3 normal;
float2 uv;
};

struct Transform {
float4x4 modelMatrix;
float4x4 invModelMatrix;
};

#define TRANSFORM_BINDING [[vk::push_constant]]

#define MATERIAL_BINDING(bind) [[vk::binding(bind, 1)]]
46 changes: 46 additions & 0 deletions shaders/material_albedo_tex.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "gpass.hlslh"

CAM_BINDING ConstantBuffer<Cam> u_Cam;
TRANSFORM_BINDING ConstantBuffer<Transform> u_Transform;

struct V2F {
float4 position : SV_POSITION;
float3 worldNormal;
float2 uv;
};

struct Frag {
float4 albedoRoughness : SV_TARGET0;
float4 normalMetallic : SV_TARGET1;
};

struct MaterialData {
float metallic;
float roughness;
};

MATERIAL_BINDING(0) ConstantBuffer<MaterialData> u_Material;
MATERIAL_BINDING(1) Texture2D u_AlbedoTex;

SamplerState s;

V2F vert(Vert vIn) {
V2F vOut;

vOut.position = float4(vIn.position, 1.0) * u_Transform.modelMatrix * u_Cam.viewMatrix * u_Cam.projMatrix;
vOut.worldNormal = (float4(vIn.normal, 0.0) * transpose(u_Transform.invModelMatrix)).xyz;
vOut.uv = vIn.uv;

return vOut;
}

Frag frag(V2F fIn) {
Frag fOut;

float3 albedo = u_AlbedoTex.Sample(s, fIn.uv).rgb;

fOut.albedoRoughness = float4(albedo, u_Material.roughness);
fOut.normalMetallic = float4(fIn.worldNormal, u_Material.metallic);

return fOut;
}
40 changes: 40 additions & 0 deletions shaders/material_solid_color.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "gpass.hlslh"

CAM_BINDING ConstantBuffer<Cam> u_Cam;
TRANSFORM_BINDING ConstantBuffer<Transform> u_Transform;

struct V2F {
float4 position : SV_POSITION;
float3 worldNormal;
};

struct Frag {
float4 albedoRoughness : SV_TARGET0;
float4 normalMetallic : SV_TARGET1;
};

struct MaterialData {
float4 albedo;
float metallic;
float roughness;
};

MATERIAL_BINDING(0) ConstantBuffer<MaterialData> u_Material;

V2F vert(Vert vIn) {
V2F vOut;

vOut.position = float4(vIn.position, 1.0) * u_Transform.modelMatrix * u_Cam.viewMatrix * u_Cam.projMatrix;
vOut.worldNormal = (float4(vIn.normal, 0.0) * transpose(u_Transform.invModelMatrix)).xyz;

return vOut;
}

Frag frag(V2F fIn) {
Frag fOut;

fOut.albedoRoughness = float4(u_Material.albedo.rgb, u_Material.roughness);
fOut.normalMetallic = float4(fIn.worldNormal, u_Material.metallic);

return fOut;
}
Loading