From 6b999ebbdec4d463fd6191ffac29243bed9e32ac Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Mon, 4 Nov 2024 00:24:42 -0700 Subject: [PATCH] Added pipeline to visualize click ray, and added calculation of click ray --- client/Makefile | 6 +- client/include/draw.h | 2 + client/include/gpu.h | 5 + client/shader/hex.vert | 13 ++- client/shader/ray.frag | 7 ++ client/shader/ray.vert | 25 +++++ client/src/draw.c | 8 +- client/src/main.c | 212 +++++++++++++++++++++++++++++++++++++++-- 8 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 client/shader/ray.frag create mode 100644 client/shader/ray.vert diff --git a/client/Makefile b/client/Makefile index 980979b..eb95d75 100644 --- a/client/Makefile +++ b/client/Makefile @@ -60,10 +60,10 @@ debug: roleplay $(EXTRA_DEBUG_REQUIREMENTS) $(SPV_FILES) $(GDB) roleplay %.vert.spv: %.vert - glslc -O -o $@ $< + glslc -o $@ $< %.frag.spv: %.frag - glslc -O -o $@ $< + glslc -o $@ $< %.comp.spv: %.comp - glslc -O -o $@ $< + glslc -o $@ $< diff --git a/client/include/draw.h b/client/include/draw.h index c915e63..d2aa12f 100644 --- a/client/include/draw.h +++ b/client/include/draw.h @@ -9,6 +9,8 @@ VkResult draw_frame( RenderContext* context, UIContext* ui, HexContext* hex, + GraphicsPipeline ray_pipeline, + VkDeviceAddress ray_address, double time); #endif diff --git a/client/include/gpu.h b/client/include/gpu.h index b805a5c..371db0b 100644 --- a/client/include/gpu.h +++ b/client/include/gpu.h @@ -25,9 +25,14 @@ #include #include +#include + #define MAX_FRAMES_IN_FLIGHT 2 #define WINDOW_MIN_WIDTH 800 #define WINDOW_MIN_HEIGHT 600 +#define PERSPECTIVE_FOVY (-M_PI/3) +#define PERSPECTIVE_NEARZ 0.01 +#define PERSPECTIVE_FARZ 1000 #define VK_RESULT(x) {\ result = x;\ diff --git a/client/shader/hex.vert b/client/shader/hex.vert index f487d12..a0e8446 100644 --- a/client/shader/hex.vert +++ b/client/shader/hex.vert @@ -111,12 +111,7 @@ void main() { } color = int2color(region.hexes[hex_index].colors[indices[gl_VertexIndex]]); - /* vec2 hex_qr = start_coords[side]*radius + direction_coords[side]*(ring-(radius*side)); - vec2 world_qr; - world_qr.x = (x*hex_qr.x + (region_qr.x+region_qr.y/2)*region_width - region_qr.y*x/2)/x; - world_qr.y = -(-z*hex_qr.y - z*hex_qr.x/2 + 0.75*region_qr.y*region_height + 0.25*region_qr.y*z + 0.5*region_qr.x*z)/z - (x*hex_qr.x + (region_qr.x+region_qr.y/2)*region_width - region_qr.y*x/2)/(2*x); - vec4 hex_pos = vec4(0, 0, 0, 1); hex_pos.x = x*hex_qr.x; hex_pos.z = -z*hex_qr.y - z*hex_qr.x/2; @@ -125,6 +120,14 @@ void main() { world_pos.x = hex_pos.x + region_pos.x; world_pos.z = hex_pos.z + region_pos.z; + color = vec4(world_pos.x/10+0.5, 0, world_pos.z/10+0.5, 1); + + /* + vec2 world_qr; + world_qr.x = (x*hex_qr.x + (region_qr.x+region_qr.y/2)*region_width - region_qr.y*x/2)/x; + world_qr.y = -(-z*hex_qr.y - z*hex_qr.x/2 + 0.75*region_qr.y*region_height + 0.25*region_qr.y*z + 0.5*region_qr.x*z)/z - (x*hex_qr.x + (region_qr.x+region_qr.y/2)*region_width - region_qr.y*x/2)/(2*x); + + vec2 world_qr = vec2(0, 0); world_qr.x = world_pos.x/x; world_qr.y = -world_pos.z/z - world_pos.x/(2*x); diff --git a/client/shader/ray.frag b/client/shader/ray.frag new file mode 100644 index 0000000..5d47d6d --- /dev/null +++ b/client/shader/ray.frag @@ -0,0 +1,7 @@ +#version 450 + +layout(location = 0) out vec4 color; + +void main() { + color = vec4(1, 1, 1, 1); +} diff --git a/client/shader/ray.vert b/client/shader/ray.vert new file mode 100644 index 0000000..f7d2495 --- /dev/null +++ b/client/shader/ray.vert @@ -0,0 +1,25 @@ +#version 450 +#extension GL_EXT_buffer_reference : require + +layout(std430, buffer_reference) readonly buffer Ray { + vec4 a; + vec4 b; +}; + +layout(std430, buffer_reference) readonly buffer HexContext { + mat4 proj; + mat4 view; +}; + +layout(push_constant, std430) uniform PushConstant { + Ray ray; + HexContext context; +} pc; + +void main() { + if(gl_VertexIndex == 0) { + gl_Position = pc.context.proj * pc.context.view * pc.ray.a; + } else { + gl_Position = pc.context.proj * pc.context.view * pc.ray.b; + } +} diff --git a/client/src/draw.c b/client/src/draw.c index 2c91c4f..ad42229 100644 --- a/client/src/draw.c +++ b/client/src/draw.c @@ -31,7 +31,7 @@ void record_hex_draw(VkCommandBuffer command_buffer, HexContext* hex, double tim }; vkCmdPushConstants(command_buffer, hex->graphics.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(HexPushConstant), &push); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->graphics.pipeline); - vkCmdDraw(command_buffer, 18, REGION_HEX_COUNT*MAX_LOADED_REGIONS, 0, 0); + vkCmdDraw(command_buffer, 18, REGION_HEX_COUNT, 0, 0); } void record_ui_compute(VkCommandBuffer command_buffer, UIContext* ui, uint32_t frame) { @@ -66,6 +66,8 @@ VkResult draw_frame( RenderContext* context, UIContext* ui, HexContext* hex, + GraphicsPipeline ray_pipeline, + VkDeviceAddress ray_address, double time) { VkResult result; @@ -191,6 +193,10 @@ VkResult draw_frame( vkCmdBeginRenderPass(command_buffer, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); record_hex_draw(command_buffer, hex, time, context->current_frame); + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, ray_pipeline.pipeline); + VkDeviceAddress push[2] = {ray_address, hex->address}; + vkCmdPushConstants(command_buffer, ray_pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, 2*sizeof(VkDeviceAddress), &push); + vkCmdDraw(command_buffer, 2, 1, 0, 0); vkCmdNextSubpass(command_buffer, VK_SUBPASS_CONTENTS_INLINE); record_ui_draw(command_buffer, ui, time, context->current_frame); vkCmdEndRenderPass(command_buffer); diff --git a/client/src/main.c b/client/src/main.c index 8f8b7ef..5bb9fc2 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -1,6 +1,9 @@ #include "GLFW/glfw3.h" +#define CGLM_PRINT_PRECISION 10 +#define CGLM_DEFINE_PRINTS 1 #include "cglm/cam.h" #include "cglm/mat4.h" +#include "cglm/io.h" #include "ui.h" #include "gpu.h" #include "draw.h" @@ -16,6 +19,11 @@ #define max(a, b) ((a > b) ? a : b) +typedef struct GPURayStruct { + vec4 a; + vec4 b; +} GPURay; + typedef struct ClientContextStruct { GLFWwindow* window; RenderContext* render; @@ -41,6 +49,14 @@ typedef struct ClientContextStruct { float key_spin_speed; float cur_spin_speed; float zoom_speed; + + mat4 inverse; + + GraphicsPipeline ray_pipeline; + VkBuffer ray; + VkDeviceAddress ray_address; + VmaAllocation ray_memory; + } ClientContext; void* network_thread(void* data) { @@ -53,9 +69,169 @@ void* network_thread(void* data) { vec3 zero = {0, 0, 0}; vec3 up = {0, 1, 0}; +VkResult create_ray_pipeline(RenderContext* gpu, GraphicsPipeline* pipeline) { + VkResult result; + VkShaderModule vert_shader = load_shader_file("shader/ray.vert.spv", gpu->device); + VkShaderModule frag_shader = load_shader_file("shader/ray.frag.spv", gpu->device); + + VkPipelineShaderStageCreateInfo stages[] = { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .pName = "main", + .module = vert_shader, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .pName = "main", + .module = frag_shader, + }, + }; + + VkPushConstantRange push = { + .size = 2*sizeof(VkDeviceAddress), + .offset = 0, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + }; + + VkPipelineLayoutCreateInfo layout_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pPushConstantRanges = &push, + .pushConstantRangeCount = 1, + }; + + VK_RESULT(vkCreatePipelineLayout(gpu->device, &layout_info, NULL, &pipeline->layout)); + + VkPipelineVertexInputStateCreateInfo vertex_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + }; + + VkPipelineInputAssemblyStateCreateInfo input_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + + VkViewport viewport = { + .x = 0.0f, + .y = 0.0f, + .width = (float)(100), + .height = (float)(100), + .minDepth = 0.0f, + .maxDepth = 1.0f, + }; + + VkRect2D scissor = { + .offset = { + .x = 0, + .y = 0, + }, + .extent = { + .width = 100, + .height = 100, + }, + }; + + VkPipelineViewportStateCreateInfo viewport_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .pViewports = &viewport, + .scissorCount = 1, + .pScissors = &scissor, + }; + + VkPipelineRasterizationStateCreateInfo raster_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + }; + + VkPipelineColorBlendAttachmentState blend_attachments = { + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, + }; + + VkPipelineColorBlendStateCreateInfo blend_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &blend_attachments, + }; + + VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + VkPipelineDynamicStateCreateInfo dynamic_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = sizeof(dynamic_states)/sizeof(VkDynamicState), + .pDynamicStates = dynamic_states, + }; + + VkPipelineMultisampleStateCreateInfo multisample_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .sampleShadingEnable = VK_FALSE, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .minSampleShading = 1.0f, + .pSampleMask = 0, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + VkPipelineDepthStencilStateCreateInfo depth_info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_TRUE, + .depthWriteEnable = VK_TRUE, + .depthCompareOp = VK_COMPARE_OP_LESS, + }; + + VkGraphicsPipelineCreateInfo pipeline_info = { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .layout = pipeline->layout, + .stageCount = sizeof(stages)/sizeof(VkPipelineShaderStageCreateInfo), + .pStages = stages, + .pVertexInputState = &vertex_info, + .pInputAssemblyState = &input_info, + .pViewportState = &viewport_info, + .pRasterizationState = &raster_info, + .pColorBlendState = &blend_info, + .pDynamicState = &dynamic_info, + .pMultisampleState = &multisample_info, + .pDepthStencilState = &depth_info, + .renderPass = gpu->render_pass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = -1, + }; + + return vkCreateGraphicsPipelines(gpu->device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &pipeline->pipeline); +} + VkResult main_thread(ClientContext* context) { VkResult result; + VK_RESULT(create_ray_pipeline(context->render, &context->ray_pipeline)); + + VK_RESULT(create_storage_buffer( + context->render->allocator, + 0, + sizeof(GPURay), + &context->ray, + &context->ray_memory)); + context->ray_address = buffer_address(context->render->device, context->ray); GPUString strings[] = { { @@ -96,8 +272,8 @@ VkResult main_thread(ClientContext* context) { }; uint32_t region = 0; - for(int32_t q = -10; q < 10; q++) { - for(int32_t r = -10; r < 10; r++) { + for(int32_t q = 0; q < 1; q++) { + for(int32_t r = 0; r < 1; r++) { VK_RESULT(create_hex_region(q, r, ®ions[region], context->hex, context->render)); for(uint32_t i = 0; i < REGION_HEX_COUNT; i++) { for(uint32_t h = 0; h < 6; h++) { @@ -159,10 +335,10 @@ VkResult main_thread(ClientContext* context) { if(context->render->framebuffer_recreated == true) { context->render->framebuffer_recreated = false; glm_perspective( - -M_PI*1/8, + PERSPECTIVE_FOVY, (float)context->render->swapchain_extent.width/(float)context->render->swapchain_extent.height, - 0.01, - 1000, + PERSPECTIVE_NEARZ, + PERSPECTIVE_FARZ, context->hex->data.proj); VK_RESULT(add_transfer( &context->hex->data.proj, @@ -208,6 +384,11 @@ VkResult main_thread(ClientContext* context) { hex_forward[1] = 0; glm_lookat(camera, context->position, up, context->hex->data.view); + + mat4 regular; + glm_mat4_mul(context->hex->data.proj, context->hex->data.view, regular); + glm_mat4_inv(regular, context->inverse); + add_transfer(&context->hex->data, context->hex->context, 0, 2*sizeof(mat4), context->render->current_frame, context->render); add_transfer(hex_pos, context->hex->context, offsetof(GPUHexContext, camera), sizeof(vec2), context->render->current_frame, context->render); add_transfer(hex_forward, context->hex->context, offsetof(GPUHexContext, forward), sizeof(vec2), context->render->current_frame, context->render); @@ -233,7 +414,7 @@ VkResult main_thread(ClientContext* context) { } // - VkResult result = draw_frame(context->render, context->ui, context->hex, frame_time); + VkResult result = draw_frame(context->render, context->ui, context->hex, context->ray_pipeline, context->ray_address, frame_time); if(result != VK_SUCCESS) { fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); glfwDestroyWindow(context->window); @@ -314,6 +495,25 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) break; case GLFW_MOUSE_BUTTON_LEFT: if(action == GLFW_PRESS) { + vec4 start = { + cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1, + cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1, + 0, + 1.0 + }; + + vec4 end = { + PERSPECTIVE_FARZ*(cursor[0]*context->render->window_scale[0]*2/context->render->swapchain_extent.width - 1), + PERSPECTIVE_FARZ*(cursor[1]*context->render->window_scale[1]*2/context->render->swapchain_extent.height - 1), + PERSPECTIVE_FARZ, + PERSPECTIVE_FARZ, + }; + + vec4 rays[2] = {}; + glm_mat4_mulv(context->inverse, start, rays[0]); + glm_mat4_mulv(context->inverse, end, rays[1]); + add_transfer(rays, context->ray, 0, 2*sizeof(vec4), context->render->current_frame, context->render); + for(int32_t c = context->ui->max_containers - 1; c >= 0; c--) { if(context->ui->containers[c].id == 0x00000000) { continue;