diff --git a/Renderer/Renderer.cpp b/Renderer/Renderer.cpp index 7e07b54..82cebff 100644 --- a/Renderer/Renderer.cpp +++ b/Renderer/Renderer.cpp @@ -194,12 +194,12 @@ Renderer::Renderer(Window& win) : win(win) { shader_buffer = std::make_unique(phys_dev, dev); textures = createResources({ - "assets/textures/eire.png", + "assets/textures/oil.jpg", }); std::vector shaders = { {dev, "assets/shaders/ray.vert.spv", vk::ShaderStageFlagBits::eVertex }, - { dev, "assets/shaders/manual.frag.spv", vk::ShaderStageFlagBits::eFragment }, + { dev, "assets/shaders/ray.frag.spv", vk::ShaderStageFlagBits::eFragment }, }; std::vector bindings = { @@ -220,10 +220,24 @@ Renderer::Renderer(Window& win) : win(win) { { { -1.0,-1.0 } }, }); - shader_buffer->upload(std::vector { - { { 0.0, -10.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0, 0.0 }, 0, Shape::SPHERE }, - { { 0.0, -12.0, 0.0, 0.0 }, { 10.0, 1.0, 10.0, 0.0 }, 1, Shape::BOX }, - }); + /* load map */ + bsp = std::make_unique("assets/maps/git.bsp"); + + std::vector objects; + objects.reserve(bsp->planes.size()); + uint id = 0; + for (const auto& plane : bsp->planes) { + /* for planes, center.xyz holds normal, dimensions.x holds distance */ + objects.push_back(Object{ + .center = glm::vec4(plane.norm, 0.0), + .dimensions = glm::vec4(plane.dist, 0.0, 0.0, 0.0), + .id = id, + .shape = Shape::ePLANE, + }); + id++; + } + + shader_buffer->upload(objects); pipeline = std::make_unique(dev, shaders, swapchain->extent, *render_pass, bindings, *vertex_buffer); @@ -330,12 +344,13 @@ void Renderer::draw() { auto sz = win.getDimensions(); - uniform_buffer->upload(UniformData { + uniform_buffer->upload(UniformData{ .cam_pos = cam.pos, .time = time, .viewport = glm::vec4(viewport.width, viewport.y, 0.0, 0.0), .cam_dir = cam.dir(), .n_objects = 2, + .rad = rad, }); command_buffer->bind(*pipeline); diff --git a/Renderer/Renderer.hpp b/Renderer/Renderer.hpp index 561f0d2..60c39c5 100644 --- a/Renderer/Renderer.hpp +++ b/Renderer/Renderer.hpp @@ -5,11 +5,12 @@ #define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS #include -#include #include #include #include +#include +#include #include #include @@ -46,7 +47,6 @@ struct Renderer { std::unique_ptr command_buffer; std::unique_ptr render_pass; - std::unique_ptr pipeline; /* just holds single quad */ std::unique_ptr shader_buffer; @@ -55,6 +55,8 @@ struct Renderer { std::vector textures; + std::unique_ptr bsp; + uint32_t current_image_idx; uint64_t frame = 0; @@ -67,5 +69,6 @@ struct Renderer { /* time speed */ float time = 0.0; float speed = 1.0; + float rad = 1.0; bool running = true; }; diff --git a/Renderer/UniformBuffer.hpp b/Renderer/UniformBuffer.hpp index 97119df..6c75c42 100644 --- a/Renderer/UniformBuffer.hpp +++ b/Renderer/UniformBuffer.hpp @@ -21,6 +21,7 @@ layout (set = 0, binding = 0) uniform Matrices { vec4 viewport; vec3 cam_dir; uint n_objects; + float rad; }; */ @@ -30,6 +31,7 @@ struct UniformData { vec4 viewport; vec3 cam_dir; uint n_objects; + float rad; }; struct UniformBuffer { diff --git a/Scene/BSP.cpp b/Scene/BSP.cpp new file mode 100644 index 0000000..66fd87c --- /dev/null +++ b/Scene/BSP.cpp @@ -0,0 +1,60 @@ +#include + +#include +#include + +using namespace Q3BSP; + +static inline void copy_data(void* file_data, std::string& dst, Lump& lump) { + dst.resize(lump.len); + std::memcpy(dst.data(), (u8*)file_data + (size_t)lump.offset, lump.len); +} + +template +static inline void copy_data(void* file_data, std::vector& dst, Lump& lump) { + dst.resize(lump.len / sizeof(T)); + //Log::debug("%p %p\n", dst.data(), (u8*)file_data + lump.offset); + std::memcpy(dst.data(), (u8*)file_data + (size_t)lump.offset, lump.len); +} + +BSP::BSP(const std::string& fname) : filename(fname) { + file_data = file::slurpb(fname); + Log::debug("File size: %zu\n", file_data.size()); + header = reinterpret_cast(file_data.data()); + + Log::info("Loading BSP: %s\n", fname.c_str()); + + if(header->magic != BSP_MAGIC) { + Log::error("BSP file missing magic!\n"); + } + + size_t i = 0; + for (auto& lump : header->lumps) { + i++; + Log::debug("%i: Offset: %u | Length: %u\n", i, lump.offset, lump.len); + Log::debug("\tPointer: 0x%p\n", (u8*)file_data.data() + (size_t)lump.offset); + } + + copy_data(file_data.data(), entities, header->entities); + copy_data(file_data.data(), textures, header->textures); + copy_data(file_data.data(), planes, header->planes); + copy_data(file_data.data(), nodes, header->nodes); + copy_data(file_data.data(), leafs, header->leafs); + copy_data(file_data.data(), leaf_faces, header->leaf_faces); + copy_data(file_data.data(), leaf_brushes, header->leaf_brushes); + copy_data(file_data.data(), models, header->models); + copy_data(file_data.data(), brushes, header->brushes); + copy_data(file_data.data(), brush_sides, header->brush_sides); + copy_data(file_data.data(), vertices, header->vertices); + copy_data(file_data.data(), mesh_vertices, header->mesh_vertices); + copy_data(file_data.data(), effects, header->effects); + copy_data(file_data.data(), faces, header->faces); + copy_data(file_data.data(), lightmaps, header->lightmaps); + copy_data(file_data.data(), lightvols, header->lightvols); + + vis_info.sz_vectors = *reinterpret_cast(file_data.data() + header->vis_info.offset); + vis_info.vectors.resize(header->vis_info.len); + std::memcpy(vis_info.vectors.data(), file_data.data() + header->vis_info.offset + sizeof(u32), header->vis_info.len); + + vis_info = *reinterpret_cast(file_data.data() + header->vis_info.offset); +} \ No newline at end of file diff --git a/Scene/BSP.hpp b/Scene/BSP.hpp new file mode 100644 index 0000000..7c54d9e --- /dev/null +++ b/Scene/BSP.hpp @@ -0,0 +1,191 @@ +#pragma once + +#include +#include + +#include +#include + +/* contains loading functions for Quake III-style BSPs */ +namespace Q3BSP { + struct Lump { + u32 offset; + u32 len; + }; + using rgb = glm::u8vec3; + using rgba = glm::u8vec4; + + /* "IBSP" */ + const uint32_t BSP_MAGIC = 0x50534249U; + struct Header { + u32 magic; + u32 version; + + union { + Lump lumps[17]; + Lump entities, + textures, + planes, + nodes, + leafs, + leaf_faces, + leaf_brushes, + models, + brushes, + brush_sides, + vertices, + mesh_vertices, + effects, + faces, + lightmaps, + lightvols, + vis_info; + }; + }; + + struct Texture { + char name[64]; + /* values of unknown meaning - TODO: check darkplaces or some other 3rd party loader */ + i32 flags; + i32 contents; + }; + + struct Plane { + glm::vec3 norm; + float dist; + }; + + struct Node { + u32 plane; + /* negative numbers are leaf indices */ + i32 children[2]; + + /* bounding box coords (integer) */ + glm::ivec3 bb_mins; + glm::ivec3 bb_maxes; + }; + + struct Leaf { + i32 cluster_idx; + u32 area; + glm::ivec3 bb_mins; + glm::ivec3 bb_maxes; + i32 first_leaf_face_idx; + u32 n_leaf_faces; + i32 first_leaf_brush_idx; + u32 n_leaf_brushes; + }; + + + struct LeafFaces { + /* list of face indices (one list per leaf) */ + i32 face_idx; + }; + + struct LeafBrush { + /* list of brush indices (one list leaf) */ + i32 brush_idx; + }; + + struct Model { + glm::vec3 bb_mins; + glm::vec3 bb_maxes; + i32 first_face_idx; + u32 n_faces; + i32 first_brush_idx; + u32 n_brushes; + }; + + struct Brush { + i32 first_brushside_idx; + u32 n_brushsides; + i32 texture_idx; + }; + + struct BrushSide { + i32 plane_idx; + i32 texture_idx; + }; + + struct Vertex { + glm::vec3 tex_coords; + glm::vec2 lightmap_coords; + glm::vec3 normal; + glm::u8vec4 color; + }; + + struct MeshVertex { + i32 idx; + }; + + struct Effect { + char name[64]; + i32 brush_idx; + /* almost always 5 for some reason */ + i32 unknown; + }; + + struct Face { + i32 texture_idx; + /* -1 if no effect */ + i32 effect_idx; + enum FaceType { + ePOLYGON = 1, + ePATCH = 2, + eMESH = 3, + eBILLBOARD = 4, + } type; + i32 first_vertex_idx; + u32 n_vertices; + i32 first_mesh_vertex_idx; + u32 n_mesh_vertices; + i32 lightmap_idx; + glm::vec2 lightmap_start; + glm::vec2 lightmap_end; + + glm::vec3 lightmap_origin; + glm::vec3 lightmap_unit_vectors[2]; + glm::vec3 norm; + glm::ivec2 patch_dimensions; + }; + + struct Lightmap { + u8 map[128][128][3]; + }; + + struct Lightvol { + rgb ambient; + rgb directional; + /* spherical coordinates */ + glm::u8vec2 direction; + }; + + struct VisibilityInfo { + u32 sz_vectors; + std::vector vectors; + }; + + struct BSP { + Header* header; + BSP(const std::string& fname); + std::string filename; + std::vector file_data; + std::string entities; + std::vector textures; + std::vector planes; + std::vector nodes; + std::vector leafs; + std::vector leaf_brushes; + std::vector leaf_faces; + std::vector models; + std::vector brushes; + std::vector brush_sides; + std::vector vertices; + std::vector mesh_vertices; + std::vector effects; + std::vector faces; + std::vector lightmaps; + std::vector lightvols; + VisibilityInfo vis_info; + }; +} \ No newline at end of file diff --git a/Scene/Object.hpp b/Scene/Object.hpp index 1846bcd..4d411cf 100644 --- a/Scene/Object.hpp +++ b/Scene/Object.hpp @@ -6,8 +6,9 @@ using namespace glsl; enum Shape { - SPHERE, - BOX, + eSPHERE, + eBOX, + ePLANE, }; struct Object { diff --git a/UI/UI.cpp b/UI/UI.cpp index 6239537..774e49f 100644 --- a/UI/UI.cpp +++ b/UI/UI.cpp @@ -11,7 +11,7 @@ #include -UI::UI(Renderer* ren) : info { .flycam = ren->flycam, .time = ren->time, .cam = ren->cam }, dev(ren->dev) { +UI::UI(Renderer* ren) : info { .flycam = ren->flycam, .time = ren->time, .rad = ren->rad, .cam = ren->cam }, dev(ren->dev) { IMGUI_CHECKVERSION(); ImGui::CreateContext(); @@ -89,11 +89,9 @@ void UI::newFrame() { ImGui::SetNextWindowBgAlpha(0.5f); ImGui::Begin("Rendering Info", nullptr); - auto target = info.cam.dir() + info.cam.pos; - ImGui::Text("FPS: %f", info.fps); ImGui::Text("Time: %f", info.time); - ImGui::Text("Target: %f %f %f", target.x, target.y, target.z); + ImGui::SliderFloat("Rad", &info.rad, 0.0, 3.0); ImGui::SliderFloat("Theta", &info.cam.theta, 0.0, glm::pi()); ImGui::SliderFloat("Phi", &info.cam.phi, 0.0, glm::two_pi()); diff --git a/UI/UI.hpp b/UI/UI.hpp index 8bd8f85..f278bd2 100644 --- a/UI/UI.hpp +++ b/UI/UI.hpp @@ -13,6 +13,8 @@ struct UI { float fps = 0.0; bool& flycam; float& time; + /* for cantor */ + float& rad; /* camera stuff */ Camera& cam; } info; diff --git a/assets/maps/git.bsp b/assets/maps/git.bsp new file mode 100644 index 0000000..64783cc Binary files /dev/null and b/assets/maps/git.bsp differ diff --git a/assets/shaders/manual.frag b/assets/shaders/manual.frag index d565910..affcd07 100644 --- a/assets/shaders/manual.frag +++ b/assets/shaders/manual.frag @@ -3,17 +3,22 @@ #define MAX_STEPS 100 #define MAX_DIST 1000.0 +layout (set = 0, binding = 1) uniform sampler2D tex; + layout (set = 0, binding = 0) uniform Matrices { vec3 cam_pos; float time; vec4 viewport; vec3 cam_dir; uint n_objects; + float rad; }; layout (location = 0) in vec2 pos; layout (location = 0) out vec4 fragColor; +vec2 eps = vec2(0.001, 0.0); + /* joins two parts of a scene */ float op_union(float v1, float v2) { return min(v1, v2); @@ -24,6 +29,14 @@ float op_subtract(float v1, float v2) { return max(v1, -v2); } +/* twists! in the xz */ +vec3 op_twist(vec3 p, float k) { + float c = cos(k*p.y); + float s = sin(k*p.y); + mat2 m = mat2(c, -s, s, c); + return vec3(m*p.xz, p.y); +} + float box(vec3 p, vec3 r) { vec3 q = abs(p) - r; return length(max(q,0.0)) + min(max(q.x, max(q.y,q.z)), 0.0); @@ -49,6 +62,7 @@ float sphere(vec3 p, float r) { } float sdf(vec3 p) { + p = op_twist(p.xzy, cos(time)).xzy; float d = box(p, vec3(1.0)); float s = 1.0; for(int i = 0; i < 5; i++) { @@ -56,24 +70,34 @@ float sdf(vec3 p) { vec3 a = mod(p * s, 2.0) - 1.0; s *= 3.0; vec3 r = 1.0 - 3.0*abs(a); - float c = infcross(r, 1.0)/s; + float c = infcross(r, rad)/s; d = max(d, c); } return d; } +vec3 norm(vec3 pos) { + return normalize( + vec3( + sdf(pos+eps.xyy), + sdf(pos+eps.yxy), + sdf(pos+eps.yyx) + ) - sdf(pos) + ); +} + vec2 raycast(vec3 dir) { float t = 0.0; for(int i = 0; i < MAX_STEPS; i++) { float dt = sdf(cam_pos + dir * t); if(dt < 0.0001*t) return vec2(t, float(i)); - /*else if(dt > MAX_DIST) - return vec2(t, float(i));*/ + else if(dt > MAX_DIST) + return vec2(0.0, -1.0); t += dt; } - return vec2(0, 64.0); + return vec2(0.0, 64.0); } vec3 raygen() { @@ -84,10 +108,19 @@ vec3 raygen() { return normalize(pos.x * right + pos.y * up + forward * 2.0); } +vec3 gamma(vec3 c) { + return pow(c, vec3(0.4545)); +} + void main() { vec3 dir = raygen(); vec2 d = raycast(dir); - vec3 point = cam_pos + dir * d.x; + if(d.y == -1.0) { + fragColor = vec4(0.0); + return; + } fragColor = vec4(d.y/MAX_STEPS); + + fragColor.xyz = gamma(fragColor.xyz); } \ No newline at end of file diff --git a/assets/shaders/manual.frag.spv b/assets/shaders/manual.frag.spv index 322b6cd..826c0f7 100644 Binary files a/assets/shaders/manual.frag.spv and b/assets/shaders/manual.frag.spv differ diff --git a/assets/shaders/ray.frag b/assets/shaders/ray.frag index d52413e..55a16ad 100644 --- a/assets/shaders/ray.frag +++ b/assets/shaders/ray.frag @@ -1,5 +1,11 @@ #version 450 core +#define MAX_STEPS 64 + +const vec2 eps = vec2(0.001, 0.0); + +layout (set = 0, binding = 1) uniform sampler2D tex; + layout (set = 0, binding = 0) uniform Matrices { vec3 cam_pos; float time; @@ -12,11 +18,13 @@ layout (set = 0, binding = 0) uniform Matrices { enum Shape { SPHERE, BOX, + PLANE, }; */ #define SPHERE 0 #define BOX 1 +#define PLANE 2 struct Object { vec4 center; @@ -42,14 +50,18 @@ float op_subtract(float v1, float v2) { return max(v1, -v2); } +float sphere(vec3 p, vec3 c, float r) { + return length(p-c) - r; +} + float box(vec3 p, vec3 c, vec3 r) { p -= c; vec3 q = abs(p) - r; return length(max(q,0.0)) + min(max(q.x, max(q.y,q.z)), 0.0); } -float sphere(vec3 p, vec3 c, float r) { - return length(p-c) - r; +float plane(vec3 p, vec3 norm, float d) { + return dot(p, norm) + d; } float obj_to_sdf(vec3 p, uint n) { @@ -63,26 +75,36 @@ float obj_to_sdf(vec3 p, uint n) { } } +float map(vec2 p) { + return sin(p.x)*sin(p.y); +} + +float terrain(vec3 p) { + /* render terrain with bumps */ + return box(p, vec3(0.0), vec3(100.0, 0.1, 100.0)) - abs(map(p.xz)); +} + float sdf(vec3 pos) { - float d = 100000000.0; + /*float d = 100000000.0; for(uint i = 0; i < n_objects; i++) { d = op_union(d, obj_to_sdf(pos, i)); - } + }*/ /*float dsphere = sphere(pos, vec3(0.0, 3.0*sin(time)-10.0, 0.0), 1.0); float dbox = box(pos, vec3(0.0, -10.0, 0.0), vec3(10.0, 1.0, 10.0)); float dpellet = sphere(pos, vec3(0.0, 10.0*sin(time) - 10.0, 0.0), 0.1); float d = op_union(op_subtract(dbox, dsphere), dpellet);*/ - return d; + + return terrain(pos); } float raycast(vec3 dir) { float t = 0.0; - for(int i = 0; i < 64; i++) { + for(int i = 0; i < MAX_STEPS; i++) { float dt = sdf(cam_pos + dir * t); if(dt < 0.0001*t) - return t; + return float(i)/MAX_STEPS; else if(dt > 200.0) return -1.0; t += dt; @@ -91,6 +113,17 @@ float raycast(vec3 dir) { return -1.0; } +vec3 norm(vec3 pos) { + return normalize( + vec3( + sdf(pos+eps.xyy), + sdf(pos+eps.yxy), + sdf(pos+eps.yyx) + ) - sdf(pos) + ); +} + + vec3 raygen() { vec3 forward = cam_dir; vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0))); @@ -102,12 +135,9 @@ vec3 raygen() { void main() { vec3 dir = raygen(); float d = raycast(dir); - vec3 point = cam_pos + dir * d; - - float c = 1.0-(length(point)*0.075); if(d < 0.0) - fragColor = vec4(0.1); + fragColor = vec4(0.0); else - fragColor = vec4(c); + fragColor = vec4(abs(norm(d*dir+cam_pos)).r); } \ No newline at end of file diff --git a/assets/shaders/ray.frag.spv b/assets/shaders/ray.frag.spv index d4846e6..1f7b5e9 100644 Binary files a/assets/shaders/ray.frag.spv and b/assets/shaders/ray.frag.spv differ