aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/material.hpp2
-rw-r--r--include/utils.hpp6
-rw-r--r--shaders/compute.comp45
-rw-r--r--src/main.cpp10
-rw-r--r--src/utils.cpp15
-rw-r--r--src/vk-api.cpp3
6 files changed, 52 insertions, 29 deletions
diff --git a/include/material.hpp b/include/material.hpp
index 10886da..ee4281b 100644
--- a/include/material.hpp
+++ b/include/material.hpp
@@ -7,10 +7,12 @@ enum MATERIAL_TYPE: uint32_t {
LAMBERTIAN = 0,
METAL = 1,
DIELECTRIC = 2,
+ EMISSIVE = 3,
};
struct material {
color albedo;
+ color emissive;
float fuzz;
float ior;
uint32_t type;
diff --git a/include/utils.hpp b/include/utils.hpp
index 11d377a..a95c95d 100644
--- a/include/utils.hpp
+++ b/include/utils.hpp
@@ -20,19 +20,21 @@ struct input_data {
bvh_node nodes[1024];
uint32_t max_bounce;
- uint32_t samples_per_pixel;
// Output image resolution
uint32_t width;
uint32_t height;
uint32_t sample_index;
+
+ uint32_t spheres_count;
+ uint32_t padding[3];
};
std::vector<uint8_t> get_shader_code(const char* path);
std::vector<uint8_t> get_shader_code(std::string& path);
-struct input_data create_inputs(uint32_t width, uint32_t height, uint32_t samples_per_pixel);
+struct input_data create_inputs(uint32_t width, uint32_t height);
#define PI 3.14159265359
diff --git a/shaders/compute.comp b/shaders/compute.comp
index 11256ad..a6fd9e4 100644
--- a/shaders/compute.comp
+++ b/shaders/compute.comp
@@ -9,11 +9,13 @@ const float PI = 3.141592653589793;
const uint LAMBERTIAN_MATERIAL = 0;
const uint METAL_MATERIAL = 1;
const uint DIELECTRIC_MATERIAL = 2;
+const uint EMISSIVE_MATERIAL = 3;
const vec3 light_position = vec3(10, -25, 0);
struct material {
vec4 albedo;
+ vec4 emissive;
float fuzz;
float ior;
uint type;
@@ -73,11 +75,11 @@ layout(set = 0, binding = 0) buffer Inputs {
bvh_node[1024] nodes;
uint max_bounce;
- uint samples_per_pixel;
uint width;
uint height;
-
uint sample_index;
+
+ uint spheres_count;
uint[3] padding;
};
@@ -221,7 +223,7 @@ bool hit_spheres(ray r, float min_t, float max_t, out hit_info info) {
float closest_t = max_t;
hit_info temp_info;
bool hit = false;
- for (uint sphere_index = 0; sphere_index < 512; sphere_index++) {
+ for (uint sphere_index = 0; sphere_index <= spheres_count; sphere_index++) {
if (spheres[sphere_index].radius > 0.0 && hit_sphere(spheres[sphere_index], r, min_t, closest_t, temp_info)) {
info = temp_info;
closest_t = temp_info.t;
@@ -280,28 +282,37 @@ vec4 ray_color(ray r, uint seed) {
hit_info info;
uint bounces = 0;
- vec4 final_color = vec4(1.0);
+ vec4 final_color = vec4(0.0);
+ vec4 throughput = vec4(1.0);
ray current_ray = r;
while (hit_spheres(current_ray, 0.001, 1e15, info) && bounces < max_bounce) {
ray scattered;
- vec4 attenuation;
+ vec4 attenuation = vec4(0.0);
if ((info.mat.type == LAMBERTIAN_MATERIAL && lambertian_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
(info.mat.type == METAL_MATERIAL && metal_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
- (info.mat.type == DIELECTRIC_MATERIAL && dielectric_scattering(info.mat, current_ray, seed, info, attenuation, scattered))) {
- final_color *= attenuation;
+ (info.mat.type == DIELECTRIC_MATERIAL && dielectric_scattering(info.mat, current_ray, seed, info, attenuation, scattered)) ||
+ info.mat.type == EMISSIVE_MATERIAL) {
+ final_color += info.mat.emissive * throughput;
+ throughput *= attenuation;
current_ray = scattered;
- } else {
- return vec4(0.0);
- }
- bounces++;
- }
+ // Russian Roulette
+ // As the throughput gets smaller, the ray is more likely to get terminated early.
+ // Survivors have their value boosted to make up for fewer samples being in the average.
+ {
+ float p = max(throughput.r, max(throughput.g, throughput.b));
+ if (rand(seed) > p) {
+ break;
+ }
- if (bounces == max_bounce) {
- return vec4(0.0);
+ // Add the energy we 'lose' by randomly terminating paths
+ throughput *= 1.0 / p;
+ }
+ }
+ bounces++;
}
- return final_color * mix(ground_color, sky_color, (normalize(r.direction).y + 1.0) * 0.5);
+ return final_color;
}
void main() {
@@ -310,7 +321,7 @@ void main() {
vec2 uv = vec2(float(x) / (width - 1), 1.0 - (float(y) / (height - 1)));
- uint seed = (y * width + x) * 100 + sample_index;
+ uint seed = uint(x * uint(1973) + y * uint(9277) + sample_index * uint(26699)) | uint(1);
vec2 rand_disk = disk_vec(seed);
vec2 jittered_uvs = uv + vec2(rand_disk.x / (width - 1), rand_disk.y / (height - 1));
vec2 lens_disk = rand_disk * cam.lens_radius;
@@ -321,7 +332,7 @@ void main() {
vec4 out_color = ray_color(r, seed);
- float spp_scale = (1.0 / samples_per_pixel);
+ float spp_scale = (1.0 / sample_index);
vec4 acc_color = imageLoad(accumulation_image, ivec2(x, y));
imageStore(output_image, ivec2(x, y), vec4(mix(acc_color, out_color, spp_scale)));
}
diff --git a/src/main.cpp b/src/main.cpp
index 0e2911c..071903a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -54,7 +54,7 @@ int main() {
uint64_t frame_count = 0;
auto start = std::chrono::high_resolution_clock::now();
auto end = std::chrono::high_resolution_clock::now();
- auto inputs = create_inputs(width, height, samples_per_pixel);
+ auto inputs = create_inputs(width, height);
auto can_render = true;
vkrenderer renderer { wnd, inputs };
@@ -179,10 +179,7 @@ int main() {
ImGui::Text("frame per second %u\n", static_cast<uint32_t>(1000.f / delta_time));
ImGui::Text("frame time %f ms\n", delta_time);
-
- if (ImGui::SliderInt("samples per pixel", (int32_t*)&((input_data*) renderer.compute_shader_buffer.alloc_info.pMappedData)->samples_per_pixel, 1, 1000)) {
- reset_accumulation = true;
- }
+ ImGui::Text("frame count %u\n", ((input_data*) renderer.compute_shader_buffer.alloc_info.pMappedData)->sample_index);
ImGui::SliderInt("bounces", (int32_t*)&((input_data*) renderer.compute_shader_buffer.alloc_info.pMappedData)->max_bounce, 2, 250);
@@ -200,12 +197,13 @@ int main() {
renderer.begin_frame();
if (reset_accumulation) {
+ ((input_data*) renderer.compute_shader_buffer.alloc_info.pMappedData)->sample_index = 0;
renderer.reset_accumulation();
}
renderer.compute(width, height);
- ((input_data*) renderer.compute_shader_buffer.alloc_info.pMappedData)->sample_index = frame_count % 1000;
+ ((input_data*) renderer.compute_shader_buffer.alloc_info.pMappedData)->sample_index++;
renderer.ui();
diff --git a/src/utils.cpp b/src/utils.cpp
index d4419b0..6467563 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -104,10 +104,17 @@ uint32_t random_scene(sphere *world) {
material3.type = MATERIAL_TYPE::METAL;
world[world_sphere_index + 2] = { { 4, 1, 0 }, material3, 1.0 };
- return world_sphere_index + 2;
+ material material4 = {};
+ material4.albedo = color{ 0.0, 0.0, 0.0 };
+ material4.emissive = color{ 1.0, 1.0, 1.0 } * 100.0;
+ material4.fuzz = 0.0;
+ material4.type = MATERIAL_TYPE::EMISSIVE;
+ world[world_sphere_index + 3] = { { 2, 1.5, 2 }, material4, 0.5 };
+
+ return world_sphere_index + 3;
}
-struct input_data create_inputs(uint32_t width, uint32_t height, uint32_t samples_per_pixel) {
+struct input_data create_inputs(uint32_t width, uint32_t height) {
// Image dimensions
const float aspect_ratio = (float)width / (float) height;
@@ -129,7 +136,7 @@ struct input_data create_inputs(uint32_t width, uint32_t height, uint32_t sample
.nodes = {},
.max_bounce = max_depth,
- .samples_per_pixel = samples_per_pixel,
+
.width = width,
.height = height,
@@ -139,6 +146,8 @@ struct input_data create_inputs(uint32_t width, uint32_t height, uint32_t sample
// World hittable objects
uint32_t spheres_count = random_scene(inputs.spheres);
+ inputs.spheres_count = spheres_count;
+
inputs.nodes[0] = { inputs.spheres, 0, spheres_count, inputs.nodes, 1 };
return inputs;
diff --git a/src/vk-api.cpp b/src/vk-api.cpp
index dc30520..1d0c8a5 100644
--- a/src/vk-api.cpp
+++ b/src/vk-api.cpp
@@ -736,7 +736,8 @@ Swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count,
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
create_info.preTransform = caps.currentTransform;
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ // create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ create_info.presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
create_info.clipped = VK_TRUE;
create_info.oldSwapchain = old_swapchain;