From 8c1f18ac703c536b8def63e670842c09b228f68b Mon Sep 17 00:00:00 2001 From: MitchellHansen Date: Fri, 4 Nov 2016 23:11:24 -0700 Subject: [PATCH] Software raycasting now works, but has some major problems / is extremely slow. Perhaps it will only be useful in debugging the kernel via emulation --- include/RayCaster.h | 1 + include/Software_Caster.h | 8 +- include/util.hpp | 3 +- kernels/ray_caster_kernel.cl | 2 +- src/Hardware_Caster.cpp | 6 +- src/Old_map.cpp | 5 +- src/Software_Caster.cpp | 382 +++++++++++++++++++---------------- src/main.cpp | 21 +- 8 files changed, 244 insertions(+), 184 deletions(-) diff --git a/include/RayCaster.h b/include/RayCaster.h index 3213d27..0b49e73 100644 --- a/include/RayCaster.h +++ b/include/RayCaster.h @@ -40,6 +40,7 @@ protected: Old_Map * map = nullptr; Camera *camera = nullptr; std::vector lights; + int light_count = 0; sf::Uint8 *viewport_image = nullptr; sf::Vector4f *viewport_matrix = nullptr; sf::Vector2i viewport_resolution; diff --git a/include/Software_Caster.h b/include/Software_Caster.h index 083ca12..110f6d8 100644 --- a/include/Software_Caster.h +++ b/include/Software_Caster.h @@ -1,4 +1,5 @@ #include "RayCaster.h" +#include class Software_Caster : public RayCaster { @@ -26,6 +27,9 @@ public: private: - void cast_rays(); - + void cast_viewport(); + void cast_thread(int start_id, int end_id); + void cast_ray(int id); + void blit_pixel(sf::Color color, sf::Vector2i position, sf::Vector3i mask); + sf::Color global_light(sf::Color in, sf::Vector3i mask); }; diff --git a/include/util.hpp b/include/util.hpp index d51a35e..3cc31d5 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -10,14 +10,13 @@ const double PI = 3.141592653589793238463; const float PI_F = 3.14159265358979f; struct Light { +#pragma pack(1) sf::Vector4f rgbi; // I believe that Vector3's get padded to Vector4's. Give them a non-garbage value sf::Vector3f position; - const float padding_1 = -1; sf::Vector3f direction_cartesian; - const float padding_2 = -2; }; struct fps_counter { diff --git a/kernels/ray_caster_kernel.cl b/kernels/ray_caster_kernel.cl index cb7a8ce..4fb03e2 100644 --- a/kernels/ray_caster_kernel.cl +++ b/kernels/ray_caster_kernel.cl @@ -191,7 +191,7 @@ __kernel void raycaster( case 5: //write_imagef(image, pixel, (float4)(.00, .00, + 0.5, 1.00)); - write_imagef(image, pixel, white_light((float4)(.35, .00, ((1.0 - 0) / (128 - 0) * (voxel.z - 128)) + 1, 0.2), (float3)(lights[7], lights[8], lights[9]), mask)); + write_imagef(image, pixel, white_light((float4)(.40, .00, ((1.0 - 0) / (128 - 0) * (voxel.z - 128)) + 1, 0.2), (float3)(lights[7], lights[8], lights[9]), mask)); return; float3 vox = convert_float3(voxel); diff --git a/src/Hardware_Caster.cpp b/src/Hardware_Caster.cpp index 6c33d66..93364a6 100644 --- a/src/Hardware_Caster.cpp +++ b/src/Hardware_Caster.cpp @@ -170,11 +170,13 @@ void Hardware_Caster::create_viewport(int width, int height, float v_fov, float void Hardware_Caster::assign_lights(std::vector lights) { + std::cout << sizeof(Light); + this->lights = std::vector(lights); - int light_count = lights.size(); + light_count = lights.size(); - create_buffer("lights", sizeof(float) * 12 * light_count, lights.data(), CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR); + create_buffer("lights", sizeof(float) * 10 * light_count, this->lights.data(), CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR); create_buffer("light_count", sizeof(int), &light_count); diff --git a/src/Old_map.cpp b/src/Old_map.cpp index 42e88c8..f6526ea 100644 --- a/src/Old_map.cpp +++ b/src/Old_map.cpp @@ -17,7 +17,7 @@ Old_Map::~Old_Map() { void Old_Map::generate_terrain() { std::mt19937 gen; std::uniform_real_distribution dis(-1.0, 1.0); - auto f_rand = std::bind(dis, gen); + auto f_rand = std::bind(dis, std::ref(gen)); voxel_data = new char[dimensions.x * dimensions.y * dimensions.z]; height_map = new double[dimensions.x * dimensions.y]; @@ -34,7 +34,8 @@ void Old_Map::generate_terrain() { //value 2^n+1 int DATA_SIZE = dimensions.x + 1; //an initial seed value for the corners of the data - double SEED = rand() % 25 + 25; + //srand(f_rand()); + double SEED = rand() % 25 + 55; //seed the data set_sample(0, 0, SEED); diff --git a/src/Software_Caster.cpp b/src/Software_Caster.cpp index 04145e6..5117e2f 100644 --- a/src/Software_Caster.cpp +++ b/src/Software_Caster.cpp @@ -19,19 +19,19 @@ int Software_Caster::init() void Software_Caster::create_viewport(int width, int height, float v_fov, float h_fov) { // CL needs the screen resolution - sf::Vector2i view_res(width, height); + viewport_resolution = sf::Vector2i(width, height); // And an array of vectors describing the way the "lens" of our // camera works // This could be modified to make some odd looking camera lenses - double y_increment_radians = DegreesToRadians(v_fov / view_res.y); - double x_increment_radians = DegreesToRadians(h_fov / view_res.x); + double y_increment_radians = DegreesToRadians(v_fov / viewport_resolution.y); + double x_increment_radians = DegreesToRadians(h_fov / viewport_resolution.x); viewport_matrix = new sf::Vector4f[width * height * 4]; - for (int y = -view_res.y / 2; y < view_res.y / 2; y++) { - for (int x = -view_res.x / 2; x < view_res.x / 2; x++) { + for (int y = -viewport_resolution.y / 2; y < viewport_resolution.y / 2; y++) { + for (int x = -viewport_resolution.x / 2; x < viewport_resolution.x / 2; x++) { // The base ray direction to slew from sf::Vector3f ray(1, 0, 0); @@ -51,7 +51,7 @@ void Software_Caster::create_viewport(int width, int height, float v_fov, float static_cast(ray.z) ); - int index = (x + view_res.x / 2) + view_res.x * (y + view_res.y / 2); + int index = (x + viewport_resolution.x / 2) + viewport_resolution.x * (y + viewport_resolution.y / 2); ray = Normalize(ray); viewport_matrix[index] = sf::Vector4f( @@ -71,7 +71,7 @@ void Software_Caster::create_viewport(int width, int height, float v_fov, float viewport_image[i] = 255; // R viewport_image[i + 1] = 255; // G viewport_image[i + 2] = 255; // B - viewport_image[i + 3] = 100; // A + viewport_image[i + 3] = 255; // A } // Interop lets us keep a reference to it as a texture @@ -109,7 +109,7 @@ void Software_Caster::validate() { } void Software_Caster::compute() { - cast_rays(); + cast_viewport(); } void Software_Caster::draw(sf::RenderWindow * window) { @@ -117,184 +117,224 @@ void Software_Caster::draw(sf::RenderWindow * window) { window->draw(viewport_sprite); } -void Software_Caster::cast_rays() -{ +void Software_Caster::cast_viewport() { - int i = 0; - for (int y = 0; y < viewport_resolution.y; y++) { - for (int x = 0; x < viewport_resolution.x; x++) { + std::vector threads; + for (int i = 0; i < 13; i++) { + int s = viewport_resolution.x * ((viewport_resolution.y / 13) * i); + int e = viewport_resolution.x * ((viewport_resolution.y / 13) * (i + 1)); + threads.push_back(new std::thread(&Software_Caster::cast_thread, this, s, e)); + } - int id = i; - sf::Vector2i pixel = { id % viewport_resolution.x, id / viewport_resolution.x }; - - // 4f 3f ?? - sf::Vector4f ray_dir = viewport_matrix[pixel.x + viewport_resolution.x * pixel.y]; + for (auto i : threads) { + i->join(); + delete i; + } +} - ray_dir = sf::Vector4f( - ray_dir.z * sin(camera->get_direction().x) + ray_dir.x * cos(camera->get_direction().x), - ray_dir.y, - ray_dir.z * cos(camera->get_direction().x) - ray_dir.x * sin(camera->get_direction().x), - 0 - ); +void Software_Caster::cast_thread(int start_id, int end_id) { - ray_dir = sf::Vector4f( - ray_dir.x * cos(camera->get_direction().y) - ray_dir.y * sin(camera->get_direction().y), - ray_dir.x * sin(camera->get_direction().y) + ray_dir.y * cos(camera->get_direction().y), - ray_dir.z, - 0 - ); + for (int i = start_id; i < end_id; i++) { + cast_ray(i); + } - // Setup the voxel step based on what direction the ray is pointing - sf::Vector3i voxel_step = sf::Vector3i( - static_cast(1 * (abs(ray_dir.x) / ray_dir.x)), - static_cast(1 * (abs(ray_dir.y) / ray_dir.y)), - static_cast(1 * (abs(ray_dir.z) / ray_dir.z)) - ); - - // Setup the voxel coords from the camera origin - sf::Vector3i voxel = sf::Vector3i( - static_cast(camera->get_position().x), - static_cast(camera->get_position().y), - static_cast(camera->get_position().z) - ); +} - // Delta T is the units a ray must travel along an axis in order to - // traverse an integer split - sf::Vector3f delta_t = sf::Vector3f( - fabs(1.0f / ray_dir.x), - fabs(1.0f / ray_dir.y), - fabs(1.0f / ray_dir.z) - ); +void Software_Caster::cast_ray(int id) +{ + sf::Vector2i pixel = { id % viewport_resolution.x, id / viewport_resolution.x }; + + // 4f 3f ?? + sf::Vector4f ray_dir = viewport_matrix[pixel.x + viewport_resolution.x * pixel.y]; + + ray_dir = sf::Vector4f( + ray_dir.z * sin(camera->get_direction().x) + ray_dir.x * cos(camera->get_direction().x), + ray_dir.y, + ray_dir.z * cos(camera->get_direction().x) - ray_dir.x * sin(camera->get_direction().x), + 0 + ); + + ray_dir = sf::Vector4f( + ray_dir.x * cos(camera->get_direction().y) - ray_dir.y * sin(camera->get_direction().y), + ray_dir.x * sin(camera->get_direction().y) + ray_dir.y * cos(camera->get_direction().y), + ray_dir.z, + 0 + ); + + // Setup the voxel step based on what direction the ray is pointing + sf::Vector3i voxel_step = sf::Vector3i( + static_cast(1 * (abs(ray_dir.x) / ray_dir.x)), + static_cast(1 * (abs(ray_dir.y) / ray_dir.y)), + static_cast(1 * (abs(ray_dir.z) / ray_dir.z)) + ); + + // Setup the voxel coords from the camera origin + sf::Vector3i voxel = sf::Vector3i( + static_cast(camera->get_position().x), + static_cast(camera->get_position().y), + static_cast(camera->get_position().z) + ); + + // Delta T is the units a ray must travel along an axis in order to + // traverse an integer split + sf::Vector3f delta_t = sf::Vector3f( + fabs(1.0f / ray_dir.x), + fabs(1.0f / ray_dir.y), + fabs(1.0f / ray_dir.z) + ); + + // offset is how far we are into a voxel, enables sub voxel movement + sf::Vector3f offset = sf::Vector3f( + (camera->get_position().x - floor(camera->get_position().x)) * voxel_step.x, + (camera->get_position().y - floor(camera->get_position().y)) * voxel_step.y, + (camera->get_position().z - floor(camera->get_position().z)) * voxel_step.z + ); + + // Intersection T is the collection of the next intersection points + // for all 3 axis XYZ. + sf::Vector3f intersection_t = sf::Vector3f( + delta_t.x * offset.x, + delta_t.y * offset.y, + delta_t.z * offset.z + ); + + // for negative values, wrap around the delta_t, rather not do this + // component wise, but it doesn't appear to want to work + if (intersection_t.x < 0) { + intersection_t.x += delta_t.x; + } + if (intersection_t.y < 0) { + intersection_t.y += delta_t.y; + } + if (intersection_t.z < 0) { + intersection_t.z += delta_t.z; + } - // offset is how far we are into a voxel, enables sub voxel movement - sf::Vector3f offset = sf::Vector3f( - (camera->get_position().x - floor(camera->get_position().x)) * voxel_step.x, - (camera->get_position().y - floor(camera->get_position().y)) * voxel_step.y, - (camera->get_position().z - floor(camera->get_position().z)) * voxel_step.z - ); + // use a ghetto ass rng to give rays a "fog" appearance + sf::Vector2i randoms = { 3, 14 }; + int seed = randoms.x + id; + int t = seed ^ (seed << 11); + int result = randoms.y ^ (randoms.y >> 19) ^ (t ^ (t >> 8)); - // Intersection T is the collection of the next intersection points - // for all 3 axis XYZ. - sf::Vector3f intersection_t = sf::Vector3f( - delta_t.x * offset.x, - delta_t.y * offset.y, - delta_t.z * offset.z - ); + int max_dist = 800 + result % 50; + int dist = 0; + + sf::Vector3i mask = { 0, 0, 0 }; + + // Andrew Woo's raycasting algo + do { + + if ((intersection_t.x) < (intersection_t.y)) { + if ((intersection_t.x) < (intersection_t.z)) { + + mask.x = 1; + voxel.x += voxel_step.x; + intersection_t.x = intersection_t.x + delta_t.x; + } + else { - // for negative values, wrap around the delta_t, rather not do this - // component wise, but it doesn't appear to want to work - if (intersection_t.x < 0) { - intersection_t.x += delta_t.x; + mask.z = 1; + voxel.z += voxel_step.z; + intersection_t.z = intersection_t.z + delta_t.z; } - if (intersection_t.y < 0) { - intersection_t.y += delta_t.y; + } + else { + if ((intersection_t.y) < (intersection_t.z)) { + + mask.y = 1; + voxel.y += voxel_step.y; + intersection_t.y = intersection_t.y + delta_t.y; } - if (intersection_t.z < 0) { - intersection_t.z += delta_t.z; + else { + + mask.z = 1; + voxel.z += voxel_step.z; + intersection_t.z = intersection_t.z + delta_t.z; } + } - // use a ghetto ass rng to give rays a "fog" appearance - sf::Vector2i randoms = { 3, 14 }; - int seed = randoms.x + id; - int t = seed ^ (seed << 11); - int result = randoms.y ^ (randoms.y >> 19) ^ (t ^ (t >> 8)); - - int max_dist = 800 + result % 50; - int dist = 0; - - sf::Vector3i mask = { 0, 0, 0 }; - - // Andrew Woo's raycasting algo - do { - - if ((intersection_t.x) < (intersection_t.y)) { - if ((intersection_t.x) < (intersection_t.z)) { - - mask.x = 1; - voxel.x += voxel_step.x; - intersection_t.x = intersection_t.x + delta_t.x; - } - else { - - mask.z = 1; - voxel.z += voxel_step.z; - intersection_t.z = intersection_t.z + delta_t.z; - } - } - else { - if ((intersection_t.y) < (intersection_t.z)) { - - mask.y = 1; - voxel.y += voxel_step.y; - intersection_t.y = intersection_t.y + delta_t.y; - } - else { - - mask.z = 1; - voxel.z += voxel_step.z; - intersection_t.z = intersection_t.z + delta_t.z; - } - } - - - // If the ray went out of bounds - sf::Vector3i overshoot = sf::Vector3i( - voxel.x <= map->getDimensions().x, - voxel.y <= map->getDimensions().y, - voxel.z <= map->getDimensions().z - ); - sf::Vector3i undershoot = sf::Vector3i( - voxel.x > 0, - voxel.y > 0, - voxel.z > 0 - ); + // If the ray went out of bounds + sf::Vector3i overshoot = sf::Vector3i( + voxel.x <= map->getDimensions().x, + voxel.y <= map->getDimensions().y, + voxel.z <= map->getDimensions().z + ); + + sf::Vector3i undershoot = sf::Vector3i( + voxel.x > 0, + voxel.y > 0, + voxel.z > 0 + ); - if (overshoot.x == 0 || overshoot.y == 0 || overshoot.z == 0 || undershoot.x == 0 || undershoot.y == 0) { - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - } - if (undershoot.z == 0) { - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - } - - // If we hit a voxel - //int index = voxel.x * (*map_dim).y * (*map_dim).z + voxel.z * (*map_dim).z + voxel.y; - // Why the off by one on voxel.y? - int index = voxel.x + map->getDimensions().x * (voxel.y + map->getDimensions().z * (voxel.z - 1)); - int voxel_data = map->get_voxel_data()[index]; - - if (voxel_data != 0) { - switch (voxel_data) { - case 255: - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - case 2: - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - case 3: - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - case 4: - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - case 5: - viewport_image[x + viewport_resolution.x * y] = (0, 255, 255, 255); - case 6: - viewport_image[x + viewport_resolution.x * y] = (255, 0, 255, 255); - return; - default: - //write_imagef(image, pixel, (float4)(.30, .2550, .2550, 255.00)); - continue; - } - } - - dist++; - } while (dist < max_dist); - - viewport_image[x + viewport_resolution.x * y] = (255, 0, 0, 255); + if (overshoot.x == 0 || overshoot.y == 0 || overshoot.z == 0 || undershoot.x == 0 || undershoot.y == 0) { + blit_pixel(sf::Color::Yellow, sf::Vector2i{ pixel.x,pixel.y }, mask); return; } - } + if (undershoot.z == 0) { + blit_pixel(sf::Color::Yellow, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + } + + // If we hit a voxel + //int index = voxel.x * (*map_dim).y * (*map_dim).z + voxel.z * (*map_dim).z + voxel.y; + // Why the off by one on voxel.y? + int index = voxel.x + map->getDimensions().x * (voxel.y + map->getDimensions().z * (voxel.z - 1)); + int voxel_data = map->get_voxel_data()[index]; + + if (voxel_data != 0) { + switch (voxel_data) { + case 1: + blit_pixel(sf::Color::Green, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + case 2: + blit_pixel(sf::Color::Green, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + case 3: + blit_pixel(sf::Color::Green, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + case 4: + blit_pixel(sf::Color::Green, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + case 5: + blit_pixel(sf::Color(30, 10, 200, 100), sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + case 6: + blit_pixel(sf::Color::Green, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; + default: + //write_imagef(image, pixel, (float4)(.30, .2550, .2550, 255.00)); + return; + } + } + + dist++; + } while (dist < max_dist); + + blit_pixel(sf::Color::Red, sf::Vector2i{ pixel.x,pixel.y }, mask); + return; +} + +void Software_Caster::blit_pixel(sf::Color color, sf::Vector2i position, sf::Vector3i mask) { + + sf::Color t = global_light(color, mask); + viewport_image[(position.x + viewport_resolution.x * position.y) * 4 + 0] = t.r; + viewport_image[(position.x + viewport_resolution.x * position.y) * 4 + 1] = t.g; + viewport_image[(position.x + viewport_resolution.x * position.y) * 4 + 2] = t.b; + viewport_image[(position.x + viewport_resolution.x * position.y) * 4 + 3] = t.a; } + +sf::Color Software_Caster::global_light(sf::Color in, sf::Vector3i mask) { + + sf::Vector3f mask_f(mask); + + in.a = in.a + acos( + DotProduct( + Normalize(lights.at(0).direction_cartesian), + Normalize(mask_f) + ) + )/ 2; + + return in; + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 2393f73..7e79518 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,6 +31,7 @@ #include "Hardware_Caster.h" #include "Vector4.hpp" #include +#include "Software_Caster.h" const int WINDOW_X = 1920; const int WINDOW_Y = 1080; @@ -67,6 +68,7 @@ int main() { // Initialize the raycaster hardware, compat, or software RayCaster *rc = new Hardware_Caster(); + //RayCaster *rc = new Software_Caster(); if (rc->init() != 1) { delete rc; // rc = new Hardware_Caster_Compat(); @@ -95,8 +97,8 @@ int main() { rc->create_viewport(WINDOW_X, WINDOW_Y, 50.0f, 80.0f); Light l; - l.direction_cartesian = sf::Vector3f(1.0f, 1.0f, 0.0f); - l.position = sf::Vector3f(10.0f, 10.0f, 10.0f); + l.direction_cartesian = sf::Vector3f(1.5f, 1.2f, 0.5f); + l.position = sf::Vector3f(100.0f, 100.0f, 100.0f); l.rgbi = sf::Vector4f(0.3f, 0.4f, 0.3f, 1.0f); rc->assign_lights(std::vector{l}); @@ -125,7 +127,9 @@ int main() { // Mouse capture sf::Vector2i deltas; sf::Vector2i fixed(window.getSize()); + sf::Vector2i prev_pos; bool mouse_enabled = true; + bool reset = false; while (window.isOpen()) { @@ -142,6 +146,8 @@ int main() { mouse_enabled = false; else mouse_enabled = true; + } if (event.key.code == sf::Keyboard::R) { + reset = true; } } } @@ -174,11 +180,18 @@ int main() { } if (mouse_enabled) { - deltas = fixed - sf::Mouse::getPosition(); + if (reset) { + reset = false; + sf::Mouse::setPosition(sf::Vector2i(2560/2, 1080/2)); + prev_pos = sf::Vector2i(2560 / 2, 1080 / 2); + } + + deltas = prev_pos - sf::Mouse::getPosition(); if (deltas != sf::Vector2i(0, 0) && mouse_enabled == true) { // Mouse movement - sf::Mouse::setPosition(fixed); + //sf::Mouse::setPosition(fixed); + prev_pos = sf::Mouse::getPosition(); camera->slew_camera(sf::Vector2f( deltas.y / 300.0f, deltas.x / 300.0f