Skip to content
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

Branchless sky shader #71

Merged
merged 40 commits into from
Oct 21, 2020
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
782faa6
Branchless sky shader
Jasper-Bekkers Oct 19, 2020
413a49a
cargo fmt
Jasper-Bekkers Oct 19, 2020
de95ae3
cargo fmt on shader \o/
Jasper-Bekkers Oct 19, 2020
634de1a
Don't output the input color
Jasper-Bekkers Oct 19, 2020
b26cc93
Fullscreen quad
Jasper-Bekkers Oct 19, 2020
93f966c
Re-enable sky
Jasper-Bekkers Oct 19, 2020
992982d
Uncomment
Jasper-Bekkers Oct 19, 2020
8f5b270
Fixed naming of the fragment shader
VZout Oct 20, 2020
b921e6a
Implement memcpy for single-element items
khyperia Oct 20, 2020
f0bf9b6
Implement static_addr_of via similar system to register_fn_ptr
khyperia Oct 20, 2020
8915209
Fix size and alignment of vectors
khyperia Oct 20, 2020
7edc97e
Fix formatting
khyperia Oct 20, 2020
844cff7
Branchless sky shader
Jasper-Bekkers Oct 19, 2020
aa9040b
Add transform matrix
Jasper-Bekkers Oct 21, 2020
ecd2e3e
Comment
Jasper-Bekkers Oct 21, 2020
df0406d
Fix broken merge
Jasper-Bekkers Oct 21, 2020
ebb131f
Fixed shader
Jasper-Bekkers Oct 21, 2020
f8f4923
Slightly nicer coordinates
Jasper-Bekkers Oct 21, 2020
db0ca8c
Merge branch 'main' into test-sky-shader
Jasper-Bekkers Oct 21, 2020
06a21d0
Format shader
Jasper-Bekkers Oct 21, 2020
6472953
Remove dbg!
Jasper-Bekkers Oct 21, 2020
b55f2e9
Remove some un-needed #[inline]
Jasper-Bekkers Oct 21, 2020
fb5e9de
Add very stripped down version of glam-rs math routines to spirv-std
Jasper-Bekkers Oct 21, 2020
f8830f2
Update example to use math routines in spirv-std
Jasper-Bekkers Oct 21, 2020
ab887d4
Also use lerp from spirv-std
Jasper-Bekkers Oct 21, 2020
14e9abe
cargo fmt shader
Jasper-Bekkers Oct 21, 2020
ca16454
Remove weird cargo.lock file
Jasper-Bekkers Oct 21, 2020
e13baa4
Revert "Remove weird cargo.lock file"
Jasper-Bekkers Oct 21, 2020
75dbf69
The other Cargo.lock file needed to be removed
Jasper-Bekkers Oct 21, 2020
5ea128b
Make cargo fmt not crash again
Jasper-Bekkers Oct 21, 2020
5e48f7e
Cleanup
Jasper-Bekkers Oct 21, 2020
0ed9ab3
clippy
Jasper-Bekkers Oct 21, 2020
7e94ebb
cargo fmt
Jasper-Bekkers Oct 21, 2020
1964d50
Attribution, small cleanups
Jasper-Bekkers Oct 21, 2020
74db1c1
Wrong comment
Jasper-Bekkers Oct 21, 2020
fb23aa6
Remove unused imports
Jasper-Bekkers Oct 21, 2020
3ec5769
Use extension trait for math, much nicer \o/
Jasper-Bekkers Oct 21, 2020
32abfde
Add repi comment
Jasper-Bekkers Oct 21, 2020
95fd7e2
Switch to repr(simd) for the Vec types
Jasper-Bekkers Oct 21, 2020
faf6ab7
Move clamp into MathExt, make MathExt take Self instead of f32
Jasper-Bekkers Oct 21, 2020
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
40 changes: 22 additions & 18 deletions examples/example-runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ fn main() {
})
.collect();

let index_buffer_data = [0u32, 1, 2];
let index_buffer_data = [0u32, 1, 2, 1, 2, 3];
let index_buffer_info = vk::BufferCreateInfo::builder()
.size(std::mem::size_of_val(&index_buffer_data) as u64)
.usage(vk::BufferUsageFlags::INDEX_BUFFER)
Expand Down Expand Up @@ -772,8 +772,27 @@ fn main() {
.bind_buffer_memory(index_buffer, index_buffer_memory, 0)
.unwrap();

let vertices = [
Vertex {
pos: [-1.0, 1.0, 0.0, 1.0],
color: [0.0, 1.0, 0.0, 1.0],
},
Vertex {
pos: [1.0, 1.0, 0.0, 1.0],
color: [0.0, 0.0, 1.0, 1.0],
},
Vertex {
pos: [-1.0, -1.0, 0.0, 1.0],
color: [1.0, 0.0, 0.0, 1.0],
},
Vertex {
pos: [1.0, -1.0, 0.0, 1.0],
color: [1.0, 1.0, 1.0, 1.0],
},
];

let vertex_input_buffer_info = vk::BufferCreateInfo {
size: 3 * std::mem::size_of::<Vertex>() as u64,
size: std::mem::size_of_val(&vertices) as u64 as u64,
usage: vk::BufferUsageFlags::VERTEX_BUFFER,
sharing_mode: vk::SharingMode::EXCLUSIVE,
..Default::default()
Expand Down Expand Up @@ -806,21 +825,6 @@ fn main() {
.allocate_memory(&vertex_buffer_allocate_info, None)
.unwrap();

let vertices = [
Vertex {
pos: [-1.0, 1.0, 0.0, 1.0],
color: [0.0, 1.0, 0.0, 1.0],
},
Vertex {
pos: [1.0, 1.0, 0.0, 1.0],
color: [0.0, 0.0, 1.0, 1.0],
},
Vertex {
pos: [0.0, -1.0, 0.0, 1.0],
color: [1.0, 0.0, 0.0, 1.0],
},
];

let vert_ptr = base
.device
.map_memory(
Expand Down Expand Up @@ -1061,7 +1065,7 @@ fn main() {
1,
0,
0,
1,
0,
);
// Or draw without the index buffer
// device.cmd_draw(draw_command_buffer, 3, 1, 0, 0);
Expand Down
176 changes: 171 additions & 5 deletions examples/example-shader/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,183 @@
//! Ported to Rust from https://github.com/Tw1ddle/Sky-Shader/blob/master/src/shaders/glsl/sky.fragment

#![no_std]
#![feature(register_attr)]
#![register_attr(spirv)]

use core::f32::consts::PI;
use core::panic::PanicInfo;
use spirv_std::{f32x4, Input, Output};
use spirv_std::{
builtin::*, f32x4, Input, Mat4, Output, Vec3, Vec4,
};

const DEPOLARIZATION_FACTOR: f32 = 0.035;
const LUMINANCE: f32 = 1.0;
const MIE_COEFFICIENT: f32 = 0.005;
const MIE_DIRECTIONAL_G: f32 = 0.8;
const MIE_K_COEFFICIENT: Vec3 = Vec3::new(0.686, 0.678, 0.666);
const MIE_V: f32 = 4.0;
const MIE_ZENITH_LENGTH: f32 = 1.25e3;
const NUM_MOLECULES: f32 = 2.542e25f32;
const PRIMARIES: Vec3 = Vec3::new(6.8e-7f32, 5.5e-7f32, 4.5e-7f32);
const RAYLEIGH: f32 = 1.0;
const RAYLEIGH_ZENITH_LENGTH: f32 = 8.4e3;
const REFRACTIVE_INDEX: f32 = 1.0003;
const SUN_ANGULAR_DIAMETER_DEGREES: f32 = 0.0093333;
const SUN_INTENSITY_FACTOR: f32 = 1000.0;
const SUN_INTENSITY_FALLOFF_STEEPNESS: f32 = 1.5;
const TONEMAP_WEIGHTING: Vec3 = Vec3::splat(9.50);
const TURBIDITY: f32 = 2.0;

/// Based on: https://seblagarde.wordpress.com/2014/12/01/inverse-trigonometric-functions-gpu-optimization-for-amd-gcn-architecture/
fn acos_approx(v: f32) -> f32 {
let x = absf32(v);
let mut res = -0.155972 * x + 1.56467; // p(x)
res *= sqrtf32(1.0f32 - x);

let mask = (v >= 0.0) as u32 as f32;

// can't use if-statement so do oldskool shader masking instead to avoid conditional
(res * mask) + ((1.0f32 - mask) * (PI - res))
}

fn clamp(a: f32, b: f32, c: f32) -> f32 {
a.max(b).min(c)
}

fn smoothstep(edge0: f32, edge1: f32, x: f32) -> f32 {
// Scale, bias and saturate x to 0..1 range
let x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
// Evaluate polynomial
return x * x * (3.0 - 2.0 * x);
}

fn total_rayleigh(lambda: Vec3) -> Vec3 {
(8.0 * powf32(PI, 3.0)
* powf32(powf32(REFRACTIVE_INDEX, 2.0) - 1.0, 2.0)
* (6.0 + 3.0 * DEPOLARIZATION_FACTOR))
/ (3.0 * NUM_MOLECULES * lambda.pow(4.0) * (6.0 - 7.0 * DEPOLARIZATION_FACTOR))
}

fn total_mie(lambda: Vec3, k: Vec3, t: f32) -> Vec3 {
let c = 0.2 * t * 10e-18;
0.434 * c * PI * ((2.0 * PI) / lambda).pow(MIE_V - 2.0) * k
}

fn rayleigh_phase(cos_theta: f32) -> f32 {
(3.0 / (16.0 * PI)) * (1.0 + powf32(cos_theta, 2.0))
}

fn henyey_greenstein_phase(cos_theta: f32, g: f32) -> f32 {
(1.0 / (4.0 * PI))
* ((1.0 - powf32(g, 2.0))
/ powf32(1.0 - 2.0 * g * cos_theta + powf32(g, 2.0), 1.5))
}

fn sun_intensity(zenith_angle_cos: f32) -> f32 {
let cutoff_angle = PI / 1.95; // Earth shadow hack
SUN_INTENSITY_FACTOR
* 0.0f32.max(
1.0 - expf32(
-((cutoff_angle - acos_approx(zenith_angle_cos)) / SUN_INTENSITY_FALLOFF_STEEPNESS),
),
)
}

fn uncharted2_tonemap(w: Vec3) -> Vec3 {
let a = Vec3::splat(0.15); // Shoulder strength
let b = Vec3::splat(0.50); // Linear strength
let c = Vec3::splat(0.10); // Linear angle
let d = Vec3::splat(0.20); // Toe strength
let e = Vec3::splat(0.02); // Toe numerator
let f = Vec3::splat(0.30); // Toe denominator

((w * (a * w + c * b) + d * e) / (w * (a * w + b) + d * f)) - e / f
}

fn sky(dir: Vec3, sun_position: Vec3) -> Vec3 {
let up = Vec3::new(0.0, 1.0, 0.0);
let sunfade = 1.0 - clamp(1.0 - expf32(sun_position.1 / 450000.0), 0.0, 1.0);
let rayleigh_coefficient = RAYLEIGH - (1.0 * (1.0 - sunfade));
let beta_r = total_rayleigh(PRIMARIES) * rayleigh_coefficient;

// Mie coefficient
let beta_m = total_mie(PRIMARIES, MIE_K_COEFFICIENT, TURBIDITY) * MIE_COEFFICIENT;

// Optical length, cutoff angle at 90 to avoid singularity
let zenith_angle = acos_approx(up.dot(dir).max(0.0));
let denom = cosf32(zenith_angle)
+ 0.15 * powf32(93.885 - ((zenith_angle * 180.0) / PI), -1.253);
let s_r = RAYLEIGH_ZENITH_LENGTH / denom;
let s_m = MIE_ZENITH_LENGTH / denom;

// Combined extinction factor
let fex = (-(beta_r * s_r + beta_m * s_m)).exp();

// In-scattering
let sun_direction = sun_position.normalize();
let cos_theta = dir.dot(sun_direction);
let beta_r_theta = beta_r * rayleigh_phase(cos_theta * 0.5 + 0.5);

let beta_m_theta = beta_m * henyey_greenstein_phase(cos_theta, MIE_DIRECTIONAL_G);
let sun_e = sun_intensity(sun_direction.dot(up));
let mut lin =
(sun_e * ((beta_r_theta + beta_m_theta) / (beta_r + beta_m)) * (Vec3::splat(1.0) - fex))
.pow(1.5);
lin *= Vec3::splat(1.0).lerp(
(sun_e * ((beta_r_theta + beta_m_theta) / (beta_r + beta_m)) * fex).pow(0.5),
clamp(powf32(1.0 - up.dot(sun_direction), 5.0), 0.0, 1.0),
);

// Composition + solar disc
let sun_angular_diameter_cos = cosf32(SUN_ANGULAR_DIAMETER_DEGREES);
let sundisk = smoothstep(
sun_angular_diameter_cos,
sun_angular_diameter_cos + 0.00002,
cos_theta,
);
let mut l0 = 0.1 * fex;
l0 += sun_e * 19000.0 * fex * sundisk;
let mut tex_color = lin + l0;
tex_color *= Vec3::splat(0.04);
tex_color += Vec3::new(0.0, 0.001, 0.0025) * 0.3;

// Tonemapping
let white_scale = 1.0 / uncharted2_tonemap(TONEMAP_WEIGHTING);
let curr =
uncharted2_tonemap((log2f32(2.0 / powf32(LUMINANCE, 4.0))) * tex_color);
let color = curr * white_scale;

color.pow(1.0 / (1.2 + (1.2 * sunfade)))
}

#[allow(unused_attributes)]
#[spirv(entry = "fragment")]
pub fn main_fs(input: Input<f32x4>, mut output: Output<f32x4>) {
output.store(input.load());
let color = input.load();
let mut dir = Vec3::new(color.0, color.1, 0.0);

// hard-code information because we can't bind buffers at the moment
let eye_pos = Vec3(0.0, 0.0997, 0.2);
let sun_pos = Vec3::new(0.0, 75.0, -1000.0);
let clip_to_world = Mat4 {
x_axis: Vec4(-0.5522849, 0.0, 0.0, 0.0),
y_axis: Vec4(0.0, 0.4096309, -0.061444636, 0.0),
z_axis: Vec4(0.0, 99.99999, 199.99998, 999.99994),
w_axis: Vec4(0.0, -0.14834046, -0.98893654, 0.0),
};

let cs_pos = Vec4(dir.0, -dir.1, 1.0, 1.0);
let mut ws_pos = clip_to_world.mul_vec4(cs_pos);
let ws_pos = Vec3(
ws_pos.0 / ws_pos.3,
ws_pos.1 / ws_pos.3,
ws_pos.2 / ws_pos.3,
);
let dir = (ws_pos - eye_pos).normalize();
let k = sky(dir, sun_pos);

output.store(f32x4(k.0, k.1, k.2, 0.0))
}

#[allow(unused_attributes)]
#[spirv(entry = "vertex")]
pub fn main_vs(
in_pos: Input<f32x4>,
Expand All @@ -20,7 +186,7 @@ pub fn main_vs(
mut out_color: Output<f32x4>,
) {
out_pos.store(in_pos.load());
out_color.store(in_color.load());
out_color.store(in_pos.load());
}

#[panic_handler]
Expand Down
6 changes: 5 additions & 1 deletion spirv-std/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#![no_std]
#![feature(register_attr, repr_simd)]
#![feature(register_attr, repr_simd, core_intrinsics)]
#![register_attr(spirv)]

pub mod math;
pub use crate::math::builtin::*;
pub use crate::math::*;

macro_rules! pointer_addrspace_write {
(false) => {};
(true) => {
Expand Down
Loading