Added closest vertex to ray-world intersection, and added pipeline to draw closest click/hover vertex

main
noah metz 2024-11-09 21:51:23 -07:00
parent 02c73ce617
commit 5f00f06de5
7 changed files with 285 additions and 41 deletions

@ -53,8 +53,10 @@ typedef struct GPUHexContextStruct {
uint32_t current_map;
uint32_t clicked_region;
uint32_t clicked_hex;
uint32_t clicked_vertex;
uint32_t hovered_region;
uint32_t hovered_hex;
uint32_t hovered_vertex;
VkDeviceAddress regions[MAX_LOADED_REGIONS];
} GPUHexContext;
@ -67,6 +69,7 @@ typedef struct HexContextStruct {
GraphicsPipeline graphics;
GraphicsPipeline highlight_pipeline;
GraphicsPipeline point_pipeline;
#ifdef DRAW_HEX_RAYS
GraphicsPipeline ray_pipeline;
#endif
@ -98,6 +101,7 @@ VkResult allocate_hex_region(
bool ray_world_intersect(
float* distance,
uint32_t* vertex,
uint32_t* rid,
uint32_t* hid,
vec4 ray_start,

@ -20,9 +20,11 @@ layout(std430, buffer_reference) readonly buffer HexContext {
vec4 hover_end;
uint current_map;
uint clicked_region;
int clicked_hex;
uint clicked_hex;
uint clicked_vertex;
uint hovered_region;
int hovered_hex;
uint hovered_hex;
uint hovered_vertex;
Region regions[];
};

@ -6,19 +6,17 @@
layout(location = 0) flat out vec4 color;
void main() {
int hex_index;
uint hex_index;
Region region;
float raise;
float raise = 0.01;
if(gl_InstanceIndex == 0) {
hex_index = pc.context.clicked_hex;
region = pc.context.regions[pc.context.clicked_region];
color = vec4(0.5, 0.5, 0.5, 0.3);
raise = 0.015;
} else {
hex_index = pc.context.hovered_hex;
region = pc.context.regions[pc.context.hovered_region];
color = vec4(0.25, 0.25, 0.25, 0.3);
raise = 0.01;
}
vec2 region_qr = vec2(region.q, region.r);

@ -0,0 +1,12 @@
#version 450
layout(location = 0) out vec4 color;
layout(location = 0) flat in vec4 color_in;
void main() {
if (length(gl_PointCoord - vec2(0.5)) > 0.5) {
discard;
}
color = color_in;
}

@ -0,0 +1,54 @@
#version 450
#extension GL_EXT_buffer_reference : require
#include "hex_common.glsl"
layout(location = 0) flat out vec4 color;
void main() {
uint hex_index;
uint vertex_index;
Region region;
float raise;
if(gl_InstanceIndex == 0) {
hex_index = pc.context.clicked_hex;
region = pc.context.regions[pc.context.clicked_region];
vertex_index = pc.context.clicked_vertex;
color = vec4(1, 0, 0, 1);
gl_PointSize = 15;
raise = 0.01;
} else {
hex_index = pc.context.hovered_hex;
region = pc.context.regions[pc.context.hovered_region];
vertex_index = pc.context.hovered_vertex;
color = vec4(0, 1, 0, 1);
gl_PointSize = 10;
raise = 0.015;
}
vec2 region_qr = vec2(region.q, region.r);
vec4 region_pos = vec4(0, 0, 0, 0);
region_pos.x = (region_qr.x+region_qr.y/2)*region_width - region_qr.y*x/2;
region_pos.z = 0.75*region_qr.y*region_height + 0.25*region_qr.y*z + 0.5*region_qr.x*z;
float radius = 0;
float ring = 0;
int side = 0;
if(hex_index != 0) {
radius = floor(0.5 + sqrt(12*hex_index-3)/6);
ring = hex_index - (3*radius*radius - 3*radius + 1);
side = int(floor(ring/radius));
}
vec4 position = vertices[vertex_index]
+ (starts[side]*radius)
+ (direction[side]*(ring-(radius*side)))
+ region_pos;
position.y = region.hexes[hex_index].heights[vertex_index-1] + region.y + raise;
gl_Position = pc.context.proj * pc.context.view * position;
}

@ -32,8 +32,11 @@ void record_hex_draw(VkCommandBuffer command_buffer, HexContext* hex, double tim
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->graphics.pipeline);
vkCmdDraw(command_buffer, 18, REGION_HEX_COUNT*MAX_LOADED_REGIONS, 0, 0);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->point_pipeline.pipeline);
vkCmdDraw(command_buffer, 6, 2, 0, 0);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->highlight_pipeline.pipeline);
vkCmdDraw(command_buffer, 18, 2, 0, 0);
vkCmdDraw(command_buffer, 1, 2, 0, 0);
#ifdef DRAW_HEX_RAYS
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, hex->ray_pipeline.pipeline);

@ -41,6 +41,166 @@ int hex_indices[] = {
0, 1, 6,
};
VkResult create_point_pipeline(
RenderContext* gpu,
GraphicsPipeline* pipeline) {
VkResult result;
VkShaderModule vert_shader = load_shader_file("shader/point.vert.spv", gpu->device);
VkShaderModule frag_shader = load_shader_file("shader/point.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 = sizeof(HexPushConstant),
.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_POINT_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 graphics_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,
};
VK_RESULT(vkCreateGraphicsPipelines(
gpu->device,
VK_NULL_HANDLE,
1, &graphics_pipeline_info,
NULL,
&pipeline->pipeline));
return VK_SUCCESS;
}
VkResult create_ray_pipeline(
RenderContext* gpu,
GraphicsPipeline* pipeline) {
@ -531,6 +691,7 @@ VkResult create_hex_context(
VK_RESULT(create_ray_pipeline(gpu, &context->ray_pipeline));
#endif
VK_RESULT(create_hex_highlight_pipeline(gpu, &context->highlight_pipeline));
VK_RESULT(create_point_pipeline(gpu, &context->point_pipeline));
memset(&context->data, 0, sizeof(GPUHexContext));
glm_perspective(
@ -636,6 +797,7 @@ VkResult allocate_hex_region(
bool ray_hex_intersect(
float* distance,
uint32_t* vertex,
vec3 start,
vec3 dir,
vec3 region_offset,
@ -685,39 +847,41 @@ bool ray_hex_intersect(
glm_vec3_add(vertices[vertex], hex_offset, vertices[vertex]);
}
*distance = INFINITY;
bool intersect = false;
vec3 t;
glm_vec3_sub(start, vertices[0], t);
for(uint32_t triangle = 0; triangle < 6; triangle++) {
vec3 vert[3];
for(int v_i = 0; v_i < 3; v_i++) {
vert[v_i][0] = vertices[hex_indices[triangle*3+v_i]][0];
vert[v_i][1] = vertices[hex_indices[triangle*3+v_i]][1];
vert[v_i][2] = vertices[hex_indices[triangle*3+v_i]][2];
vec3 vert[2];
for(int v_i = 0; v_i < 2; v_i++) {
vert[v_i][0] = vertices[hex_indices[triangle*3+v_i + 1]][0];
vert[v_i][1] = vertices[hex_indices[triangle*3+v_i + 1]][1];
vert[v_i][2] = vertices[hex_indices[triangle*3+v_i + 1]][2];
}
vec3 v0v1;
glm_vec3_sub(vert[1], vert[0], v0v1);
glm_vec3_sub(vert[0], vertices[0], v0v1);
vec3 v0v2;
glm_vec3_sub(vert[2], vert[0], v0v2);
glm_vec3_sub(vert[1], vertices[0], v0v2);
vec3 pvec;
glm_vec3_cross(dir, v0v2, pvec);
float det = glm_vec3_dot(v0v1, pvec);
float det_inv = 1/det;
vec3 t;
glm_vec3_sub(start, vert[0], t);
float u = glm_vec3_dot(t, pvec) * det_inv;
float u = glm_vec3_dot(t, pvec) / det;
if(u < 0 || u > 1) continue;
vec3 q;
glm_vec3_cross(t, v0v1, q);
float v = glm_vec3_dot(dir, q) * det_inv;
float v = glm_vec3_dot(dir, q) / det;
if(v < 0 || (u+v) > 1) continue;
intersect = true;
*distance = min(*distance, glm_vec3_dot(v0v2, q) * det_inv);
float intersect_distance = glm_vec3_dot(v0v2, q) / det;
if(intersect_distance < *distance) {
*distance = intersect_distance;
*vertex = (u > v) ? ((triangle+1) % 6)+1 : triangle+1;
}
}
return intersect;
@ -725,26 +889,27 @@ bool ray_hex_intersect(
bool ray_region_intersect(
float* distance,
uint32_t* vertex,
uint32_t* hid,
vec3 start,
vec3 dir,
HexRegion* region) {
bool intersect = false;
float temp_distance;
*distance = INFINITY;
float intersect_distance = INFINITY;
uint32_t intersection_vertex = 0;
vec3 region_offset = {
((float)region->data.q + (float)region->data.r/2)*REGION_WIDTH - region->data.r*HEX_X/2,
0,
0.75*region->data.r*REGION_HEIGHT + 0.25*region->data.r*HEX_Z + 0.5*region->data.q*HEX_Z,
};
for(uint32_t temp_hid = 0; temp_hid < REGION_HEX_COUNT; temp_hid++) {
if(ray_hex_intersect(&temp_distance, start, dir, region_offset, temp_hid, region)) {
if(temp_distance < *distance) {
for(uint32_t intersect_hid = 0; intersect_hid < REGION_HEX_COUNT; intersect_hid++) {
if(ray_hex_intersect(&intersect_distance, &intersection_vertex, start, dir, region_offset, intersect_hid, region)) {
if(intersect_distance < *distance) {
intersect = true;
*hid = temp_hid;
*distance = temp_distance;
*hid = intersect_hid;
*distance = intersect_distance;
*vertex = intersection_vertex;
}
}
}
@ -754,6 +919,7 @@ bool ray_region_intersect(
bool ray_world_intersect(
float* distance,
uint32_t* vertex,
uint32_t* rid,
uint32_t* hid,
vec4 ray_start,
@ -777,24 +943,27 @@ bool ray_world_intersect(
glm_vec3_divs(dir, mdir, dir);
bool intersect = false;
float temp_distance;
uint32_t temp_hid;
float intersect_distance = INFINITY;
uint32_t intersection_vertex = 0;
uint32_t intersect_hid;
*distance = INFINITY;
for(uint32_t temp_rid = 0; temp_rid < MAX_LOADED_REGIONS; temp_rid++) {
HexRegion* region = context->regions[temp_rid];
for(uint32_t intersect_rid = 0; intersect_rid < MAX_LOADED_REGIONS; intersect_rid++) {
HexRegion* region = context->regions[intersect_rid];
if(region == NULL) {
continue;
} else if(region->data.map != context->data.current_map) {
continue;
}
if(ray_region_intersect(&temp_distance, &temp_hid, start, dir, region)) {
if(temp_distance < *distance) {
if(ray_region_intersect(&intersect_distance, &intersection_vertex, &intersect_hid, start, dir, region)) {
if(intersect_distance < *distance) {
intersect = true;
*hid = temp_hid;
*rid = temp_rid;
*distance = temp_distance;
*hid = intersect_hid;
*rid = intersect_rid;
*vertex = intersection_vertex;
*distance = intersect_distance;
}
}
}
@ -884,6 +1053,7 @@ VkResult update_hex_hover(
float distance;
if(ray_world_intersect(
&distance,
&hex->data.hovered_vertex,
&hex->data.hovered_region,
&hex->data.hovered_hex,
hex->data.hover_start,
@ -893,7 +1063,7 @@ VkResult update_hex_hover(
&hex->data.hovered_region,
hex->context,
offsetof(GPUHexContext, hovered_region),
sizeof(uint32_t)*2,
sizeof(uint32_t)*3,
gpu);
}
@ -923,6 +1093,7 @@ VkResult update_hex_click(
if(ray_world_intersect(
&distance,
&hex->data.clicked_vertex,
&hex->data.clicked_region,
&hex->data.clicked_hex,
hex->data.click_start,
@ -932,7 +1103,7 @@ VkResult update_hex_click(
&hex->data.clicked_region,
hex->context,
offsetof(GPUHexContext, clicked_region),
sizeof(uint32_t)*2,
sizeof(uint32_t)*3,
gpu));
}