From 906290edfa2512521e5f1bd96469b7164df3df5b Mon Sep 17 00:00:00 2001 From: Draklaw Date: Sun, 20 Feb 2022 23:47:13 +0100 Subject: [PATCH] Wireframe rendering. --- CMakeLists.txt | 1 + shaders/shader.frag | 25 ++++++++- shaders/shader.geom | 49 +++++++++++++++++ shaders/shader.vert | 26 +++++++-- src/Planet.cpp | 54 +++++++++++++++--- src/Planet.h | 10 +++- src/Vulkan/Context.cpp | 8 +++ src/VulkanTutorial.cpp | 122 +++++++++++++++++++++++++---------------- src/VulkanTutorial.h | 2 +- 9 files changed, 229 insertions(+), 68 deletions(-) create mode 100644 shaders/shader.geom diff --git a/CMakeLists.txt b/CMakeLists.txt index 68904ae..ac8f11c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable(vk_expe add_shaders(vk_expe shaders/shader.vert + shaders/shader.geom shaders/shader.frag ) diff --git a/shaders/shader.frag b/shaders/shader.frag index 7c5b0e7..84b2e55 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -1,9 +1,28 @@ #version 450 -layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec3 in_normal; +layout(location = 2) in vec3 in_color; +layout(location = 3) in vec3 in_edge_dist; -layout(location = 0) out vec4 outColor; +layout(location = 0) out vec4 out_color; void main() { - outColor = vec4(fragColor, 1.0); + vec3 edge_dist = vec3(0.75) - in_edge_dist; + float edge = clamp( + max(edge_dist[0], max(edge_dist[1], edge_dist[2])), + 0.0, 1.0 + ); + + vec3 edge_color = vec3(1.0); + vec3 light_dir = normalize(vec3(-0.2, -0.1, -1.0)); + + vec3 color = in_color; + + // vec3 normal = normalize(in_normal); + // color *= clamp( + // dot(normal, light_dir), + // 0.0, 1.0 + // ); + + out_color = vec4(mix(color, edge_color, edge), 1.0); } diff --git a/shaders/shader.geom b/shaders/shader.geom new file mode 100644 index 0000000..ea8f235 --- /dev/null +++ b/shaders/shader.geom @@ -0,0 +1,49 @@ +#version 450 + +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +layout(binding = 0) uniform Uniforms { + mat4 scene_from_model; + mat4 projection_from_scene; + vec2 half_screen_size; + float lod; +} uniforms; + +layout(location = 0) in vec4 in_position[3]; +layout(location = 1) in vec3 in_normal[3]; +layout(location = 2) in vec3 in_color[3]; + +layout(location = 0) out vec4 out_position; +layout(location = 1) out vec3 out_normal; +layout(location = 2) out vec3 out_color; +layout(location = 3) noperspective out vec3 out_edge_dist; + +void main() { + vec2 positions[3] = { + uniforms.half_screen_size * gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w, + uniforms.half_screen_size * gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w, + uniforms.half_screen_size * gl_in[2].gl_Position.xy / gl_in[2].gl_Position.w, + }; + + for(int i = 0; i < 3; i += 1) { + gl_Position = gl_in[i].gl_Position; + out_position = in_position[i]; + out_normal = in_normal[i]; + out_color = in_color[i]; + out_edge_dist = vec3(0.0); + + vec2 p0 = positions[(i + 0) % 3]; + vec2 p1 = positions[(i + 1) % 3]; + vec2 p2 = positions[(i + 2) % 3]; + + // vec2 v21 = p2 - p1; + // out_edge_dist[i] = (p1.x * v21.x + p1.y * v21.y) / dot(v21, v21); + + vec2 v0 = p0 - p2; + vec2 v1 = p1 - p2; + out_edge_dist[i] = determinant(mat2(v0, v1)) / length(v1); + + EmitVertex(); + } +} diff --git a/shaders/shader.vert b/shaders/shader.vert index 4b6e4e5..5438978 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -3,17 +3,31 @@ layout(binding = 0) uniform Uniforms { mat4 scene_from_model; mat4 projection_from_scene; + vec2 screen_size; + float lod; } uniforms; -layout(location = 0) in vec3 inPosition; -layout(location = 1) in vec3 inColor; +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_position2; +layout(location = 2) in vec3 in_normal; +layout(location = 3) in vec3 in_color; -layout(location = 0) out vec3 fragColor; +layout(location = 0) out vec4 out_position; +layout(location = 1) out vec3 out_normal; +layout(location = 2) out vec3 out_color; void main() { - gl_Position = + float lod = clamp( + 2.0 * dot(transpose(uniforms.scene_from_model)[0].xyz, in_position) + 0.5, + 0.0, 1.0 + ); + vec3 position = mix(in_position2, in_position, lod); + out_position = uniforms.projection_from_scene * uniforms.scene_from_model * - vec4(inPosition, 1.0); - fragColor = inColor; + vec4(position, 1.0); + out_normal = in_normal; + out_color = in_color; + + gl_Position = out_position; } diff --git a/src/Planet.cpp b/src/Planet.cpp index 12bf2c3..a7b803d 100644 --- a/src/Planet.cpp +++ b/src/Planet.cpp @@ -38,7 +38,7 @@ size_t Cell::triangle_count(uint32_t subdiv_count) { } void Cell::build_mesh( - Vector3AV positions, TriangleAV triangles, + Vector3AV positions, Vector3AV positions2, Vector3AV normals, TriangleAV triangles, uint32_t subdiv_count, Index index_offset ) const { auto const side_edge_count = (1u << subdiv_count); @@ -54,8 +54,8 @@ void Cell::build_mesh( auto const index = [side_vert_count](uint32_t x, uint32_t y) -> uint32_t { return x + y * side_vert_count; }; - auto const vertex = [&positions, &index](uint32_t x, uint32_t y) -> Vector3& { - return positions[index(x, y)]; + auto const vertex = [&normals, &index](uint32_t x, uint32_t y) -> Vector3& { + return normals[index(x, y)]; }; vertex( 0, 0) = m_corners[0]; @@ -106,16 +106,46 @@ void Cell::build_mesh( } } + for (Index index = 0; index < normals.size(); index += 1) { + positions[index] = normals[index]; + } + + int x_offset = ( + m_corners[0][0] < m_corners[1][0] || + m_corners[0][1] < m_corners[1][1] || + m_corners[0][2] < m_corners[1][2] + )? -1: 1; + int y_offset = ( + m_corners[0][0] < m_corners[2][0] || + m_corners[0][1] < m_corners[2][1] || + m_corners[0][2] < m_corners[2][2] + )? -1: 1; + for(Index y = 0; y < side_vert_count; y += 1) { + for(Index x = 0; x < side_vert_count; x += 1) { + Index x2 = x + (x & 0x01) * x_offset; + Index y2 = y + (y & 0x01) * y_offset; + + positions2[index(x, y)] = positions[index(x2, y2)]; + } + } + auto triangleIndex = 0; - for(uint32_t y = 0; y < side_edge_count; y += 1) { - for(uint32_t x = 0; x < side_edge_count; x += 1) { + bool flip = false; // (x_offset > 0) ^ (y_offset > 0); + for(Index y = 0; y < side_edge_count; y += 1) { + for(Index x = 0; x < side_edge_count; x += 1) { const auto i00 = index_offset + index(x, y); const auto i01 = i00 + 1; const auto i10 = i00 + side_vert_count; const auto i11 = i10 + 1; - triangles[triangleIndex++] = Triangle { i00, i01, i10 }; - triangles[triangleIndex++] = Triangle { i10, i01, i11 }; + if (flip) { + triangles[triangleIndex++] = Triangle { i00, i01, i11 }; + triangles[triangleIndex++] = Triangle { i00, i11, i10 }; + } + else { + triangles[triangleIndex++] = Triangle { i00, i01, i10 }; + triangles[triangleIndex++] = Triangle { i10, i01, i11 }; + } } } } @@ -169,7 +199,7 @@ Planet::Planet() {} void Planet::build_mesh( - Vector3AV positions, TriangleAV triangles, + Vector3AV positions, Vector3AV positions2, Vector3AV normals, TriangleAV triangles, uint32_t subdiv_count, Index index_offset ) const { auto const vertex_count = Cell::vertex_count(subdiv_count); @@ -179,11 +209,19 @@ void Planet::build_mesh( auto sub_positions = positions.slice( cell_index * vertex_count, vertex_count ); + auto sub_positions2 = positions2.slice( + cell_index * vertex_count, vertex_count + ); + auto sub_normals = normals.slice( + cell_index * vertex_count, vertex_count + ); auto sub_triangles = triangles.slice( cell_index * index_count, index_count ); cell(cell_index).build_mesh( sub_positions, + sub_positions2, + sub_normals, sub_triangles, subdiv_count, index_offset + cell_index * vertex_count diff --git a/src/Planet.h b/src/Planet.h index 0e7ef4f..12aaf28 100644 --- a/src/Planet.h +++ b/src/Planet.h @@ -12,6 +12,8 @@ using CellUP = std::unique_ptr; struct Vertex { Vector3 position; + Vector3 position2; + Vector3 normal; Vector3 color; }; @@ -41,7 +43,7 @@ public: static size_t triangle_count(uint32_t subdiv_count); void build_mesh( - Vector3AV positions, TriangleAV triangles, + Vector3AV positions, Vector3AV positions2, Vector3AV normals, TriangleAV triangles, uint32_t subdiv_count=4, Index index_offset=0 ) const; @@ -78,8 +80,10 @@ public: return m_cells[cell_index]; } - void build_mesh(Vector3AV positions, TriangleAV triangles, - uint32_t subdiv_count=4, Index index_offset=0) const; + void build_mesh( + Vector3AV positions, Vector3AV positions2, Vector3AV normals, TriangleAV triangles, + uint32_t subdiv_count=4, Index index_offset=0 + ) const; private: Cell m_cells[CellCount]; diff --git a/src/Vulkan/Context.cpp b/src/Vulkan/Context.cpp index d7dfc12..b7cbafb 100644 --- a/src/Vulkan/Context.cpp +++ b/src/Vulkan/Context.cpp @@ -737,6 +737,13 @@ std::optional Context::select_physical_device( VkPhysicalDeviceProperties device_properties; vkGetPhysicalDeviceProperties(physical_device, &device_properties); + VkPhysicalDeviceFeatures available_features; + vkGetPhysicalDeviceFeatures(physical_device, &available_features); + + if (!available_features.geometryShader) + return std::nullopt; + + m_transfer_queue_index = settings.queues().size(); m_queue_families.assign(settings.queues().size() + 1, INVALID_QUEUE_FAMILY); m_presentation_queue_family = INVALID_QUEUE_FAMILY; @@ -841,6 +848,7 @@ void Context::create_device(const ContextSettings& settings) { } VkPhysicalDeviceFeatures const device_features { + .geometryShader = true, }; std::vector extensions; diff --git a/src/VulkanTutorial.cpp b/src/VulkanTutorial.cpp index bb2af04..2e15086 100644 --- a/src/VulkanTutorial.cpp +++ b/src/VulkanTutorial.cpp @@ -24,7 +24,7 @@ VkVertexInputBindingDescription vertex_binding_description() { }; } -std::array vertex_attributes_description() { +std::array vertex_attributes_description() { return { VkVertexInputAttributeDescription { .location = 0, @@ -32,10 +32,22 @@ std::array vertex_attributes_description() .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, position), }, - { + VkVertexInputAttributeDescription { .location = 1, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, position2), + }, + VkVertexInputAttributeDescription { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, normal), + }, + { + .location = 3, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, color), }, }; @@ -43,40 +55,42 @@ std::array vertex_attributes_description() std::vector vertices = { - {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, - {{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, - {{-0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}}, - {{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}}, - - {{-0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 1.0f}}, - {{0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 1.0f}}, - {{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.0f}}, - {{0.5f, 0.5f, 0.5f}, {0.2f, 0.2f, 0.2f}}, + // {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, + // {{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, + // {{-0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}}, + // {{0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}}, + + // {{-0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 1.0f}}, + // {{0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 1.0f}}, + // {{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 0.0f}}, + // {{0.5f, 0.5f, 0.5f}, {0.2f, 0.2f, 0.2f}}, }; std::vector indices = { - 0, 1, 2, - 2, 1, 3, + // 0, 1, 2, + // 2, 1, 3, - 1, 5, 3, - 3, 5, 7, + // 1, 5, 3, + // 3, 5, 7, - 5, 4, 7, - 7, 4, 6, + // 5, 4, 7, + // 7, 4, 6, - 4, 0, 6, - 6, 0, 2, + // 4, 0, 6, + // 6, 0, 2, - 0, 4, 1, - 1, 4, 5, + // 0, 4, 1, + // 1, 4, 5, - 2, 3, 6, - 6, 3, 7, + // 2, 3, 6, + // 6, 3, 7, }; struct Uniforms { alignas(16) Eigen::Matrix4f scene_from_model; alignas(16) Eigen::Matrix4f projection_from_scene; + alignas(8) Eigen::Vector2f half_screen_size; + alignas(4) float lod; }; @@ -91,24 +105,21 @@ VulkanTutorial::VulkanTutorial() { vertices.resize(6 * Cell::vertex_count(subdiv_count)); indices.resize(6 * 3 * Cell::triangle_count(subdiv_count)); - // MeshView mesh( - // vertices.size(), - // reinterpret_cast(vertices.data()) + offsetof(Vertex, position), - // sizeof(Vertex), - // nullptr, - // sizeof(Vertex), - // reinterpret_cast(vertices.data()) + offsetof(Vertex, color), - // sizeof(Vertex), - // indices.size(), - // reinterpret_cast(indices.data()), - // sizeof(Index) - // ); - Vector3AV positions( vertices.size(), vertices.data(), sizeof(Vertex), offsetof(Vertex, position) ); + Vector3AV positions2( + vertices.size(), vertices.data(), + sizeof(Vertex), offsetof(Vertex, position2) + ); + + Vector3AV normals( + vertices.size(), vertices.data(), + sizeof(Vertex), offsetof(Vertex, normal) + ); + Vector3AV colors( vertices.size(), vertices.data(), sizeof(Vertex), offsetof(Vertex, color) @@ -120,7 +131,7 @@ VulkanTutorial::VulkanTutorial() { ); Planet planet; - planet.build_mesh(positions, triangles, subdiv_count); + planet.build_mesh(positions, positions2, normals, triangles, subdiv_count); for (size_t vertex_index = 0; vertex_index < vertices.size(); vertex_index += 1) { colors[vertex_index] = @@ -195,7 +206,7 @@ void VulkanTutorial::draw_frame() { } m_last_frame_time = now; - const float alpha = SecondsD(m_time).count() * (2.0 * M_PI) / 3.0; + const float alpha = SecondsD(m_time).count() * (2.0 * M_PI) / 10.0; const float dist = 2.0f; const Eigen::Matrix4f view = look_at_matrix( // Eigen::Vector3f(0.0f, 0.0f, -dist), @@ -226,6 +237,11 @@ void VulkanTutorial::draw_frame() { const Uniforms uniforms = { .scene_from_model = model.matrix(), .projection_from_scene = proj * view, + .half_screen_size = { + 0.5 * m_swapchain.extent().width, + 0.5 * m_swapchain.extent().height, + }, + .lod = std::cos(alpha) * 0.5f + 0.5f, }; void* uniform_buffer; @@ -381,7 +397,7 @@ void VulkanTutorial::create_descriptor_set_layout() { .binding = 0, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, }; VkDescriptorSetLayoutCreateInfo layout_info { @@ -405,6 +421,12 @@ void VulkanTutorial::create_graphic_pipeline() { vkDestroyShaderModule(m_context.device(), vertex_shader_module, nullptr); }); + auto const geometry_shader_module = + m_context.create_shader_module_from_file("shaders/shader.geom.spv"); + auto const geometry_shader_guard = make_guard([&]{ + vkDestroyShaderModule(m_context.device(), geometry_shader_module, nullptr); + }); + auto const fragment_shader_module = m_context.create_shader_module_from_file("shaders/shader.frag.spv"); auto const fragment_shader_guard = make_guard([&]{ @@ -418,6 +440,12 @@ void VulkanTutorial::create_graphic_pipeline() { .module = vertex_shader_module, .pName = "main", }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_GEOMETRY_BIT, + .module = geometry_shader_module, + .pName = "main", + }, { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, @@ -534,7 +562,7 @@ void VulkanTutorial::create_graphic_pipeline() { VkGraphicsPipelineCreateInfo pipeline_info { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = 2, + .stageCount = 3, .pStages = shader_stage_infos, .pVertexInputState = &vertex_info, .pInputAssemblyState = &assembly_info, @@ -819,6 +847,13 @@ void VulkanTutorial::create_command_buffers() { offsets ); + vkCmdBindIndexBuffer( + command_buffer, + m_index_buffer, + 0, + VK_INDEX_TYPE_UINT32 + ); + vkCmdBindDescriptorSets( command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -827,13 +862,6 @@ void VulkanTutorial::create_command_buffers() { 0, nullptr ); - vkCmdBindIndexBuffer( - command_buffer, - m_index_buffer, - 0, - VK_INDEX_TYPE_UINT32 - ); - vkCmdDrawIndexed( command_buffer, uint32_t(indices.size()), diff --git a/src/VulkanTutorial.h b/src/VulkanTutorial.h index a8f4498..c06b631 100644 --- a/src/VulkanTutorial.h +++ b/src/VulkanTutorial.h @@ -11,7 +11,7 @@ VkVertexInputBindingDescription vertex_binding_description(); -std::array vertex_attributes_description(); +std::array vertex_attributes_description(); class VulkanTutorial {