Run shadow render pass and compute light position in vertex shaders
This commit is contained in:
1 parent
73340b3a39
commit
633a922e42
6 files changed
+121
-23
No files matched your search
@@ -5,6 +5,8 @@ vec3 light_dir = normalize(vec3(2, 2, -1));
|
|||||||
vec3 base_colour = vec3(1.0, 0.94, 0.8);
|
vec3 base_colour = vec3(1.0, 0.94, 0.8);
|
||||||
|
|
||||||
layout(location = 0) in vec3 frag_normal;
|
layout(location = 0) in vec3 frag_normal;
|
||||||
|
layout(location = 1) in vec4 light_pos;
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_colour;
|
layout(location = 0) out vec4 out_colour;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
|||||||
+8
-4
@@ -1,10 +1,12 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) out vec3 frag_normal;
|
layout(location = 0) out vec3 frag_normal;
|
||||||
|
layout(location = 1) out vec4 light_pos;
|
||||||
|
|
||||||
layout(push_constant) uniform vp_t {
|
layout(push_constant) uniform push_t {
|
||||||
mat4 transform;
|
mat4 vp;
|
||||||
} vp;
|
mat4 light_vp;
|
||||||
|
} push;
|
||||||
|
|
||||||
vec2 vertices[4] = vec2[](
|
vec2 vertices[4] = vec2[](
|
||||||
vec2(-1, -1),
|
vec2(-1, -1),
|
||||||
@@ -15,6 +17,8 @@ vec2 vertices[4] = vec2[](
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
const vec2 pos = 3 * vertices[gl_VertexIndex];
|
const vec2 pos = 3 * vertices[gl_VertexIndex];
|
||||||
gl_Position = vp.transform * vec4(pos.x, 0, pos.y, 1);
|
const vec4 world_pos = vec4(pos.x, 0, pos.y, 1);
|
||||||
|
gl_Position = push.vp * world_pos;
|
||||||
frag_normal = vec3(0, 1, 0);
|
frag_normal = vec3(0, 1, 0);
|
||||||
|
light_pos = push.light_vp * world_pos;
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,11 @@
|
|||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
#define CLAMP(x, min, max) MAX((min), MIN(x, (max)))
|
#define CLAMP(x, min, max) MAX((min), MIN(x, (max)))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mat4_t vp;
|
||||||
|
mat4_t light_vp;
|
||||||
|
} push_t;
|
||||||
|
|
||||||
static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
|
static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
|
||||||
static const char *extensions[] = {
|
static const char *extensions[] = {
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
@@ -547,7 +552,7 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name)
|
|||||||
const VkPushConstantRange push_constant_range = {
|
const VkPushConstantRange push_constant_range = {
|
||||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = sizeof(mat4_t),
|
.size = sizeof(push_t),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load vertex and fragment shader modules
|
// Load vertex and fragment shader modules
|
||||||
@@ -1083,7 +1088,7 @@ void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void gpu_render(
|
void gpu_render(
|
||||||
const gpu_ctx_t *ctx, mat4_t vp, size_t model_count,
|
const gpu_ctx_t *ctx, mat4_t vp, mat4_t light_vp, size_t model_count,
|
||||||
const gpu_model_t *models, const mat4_t **bone_matrices,
|
const gpu_model_t *models, const mat4_t **bone_matrices,
|
||||||
const mat4_t *model_transforms)
|
const mat4_t *model_transforms)
|
||||||
{
|
{
|
||||||
@@ -1100,6 +1105,14 @@ void gpu_render(
|
|||||||
&curr_img);
|
&curr_img);
|
||||||
assert(result == VK_SUCCESS);
|
assert(result == VK_SUCCESS);
|
||||||
|
|
||||||
|
// Update models' transforms and bones
|
||||||
|
for (unsigned i = 0; i < model_count; ++i) {
|
||||||
|
models[i].transform_ptr[curr_img] = model_transforms[i];
|
||||||
|
memcpy(
|
||||||
|
models[i].bone_ptr + (models[i].bone_count * curr_img),
|
||||||
|
bone_matrices[i], models[i].bone_count * sizeof(mat4_t));
|
||||||
|
}
|
||||||
|
|
||||||
// Reset command buffer, then begin writing
|
// Reset command buffer, then begin writing
|
||||||
vkResetCommandBuffer(ctx->cmd_buf, 0);
|
vkResetCommandBuffer(ctx->cmd_buf, 0);
|
||||||
const VkCommandBufferBeginInfo cmd_begin = {
|
const VkCommandBufferBeginInfo cmd_begin = {
|
||||||
@@ -1108,6 +1121,61 @@ void gpu_render(
|
|||||||
result = vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin);
|
result = vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin);
|
||||||
assert(result == VK_SUCCESS);
|
assert(result == VK_SUCCESS);
|
||||||
|
|
||||||
|
// Run shadow pass
|
||||||
|
VkRenderPassBeginInfo shadow_pass_begin = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||||
|
.renderPass = ctx->shadow_pass,
|
||||||
|
.framebuffer = ctx->shadow_framebuf,
|
||||||
|
.renderArea.extent = {
|
||||||
|
.width = SHADOW_IMG_SIZE,
|
||||||
|
.height = SHADOW_IMG_SIZE,
|
||||||
|
},
|
||||||
|
.clearValueCount = 1,
|
||||||
|
.pClearValues = &(VkClearValue){ .depthStencil = { 1.0, 0.0 } },
|
||||||
|
};
|
||||||
|
vkCmdBeginRenderPass(
|
||||||
|
ctx->cmd_buf, &shadow_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
vkCmdBindPipeline(
|
||||||
|
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->shadow_pipeline);
|
||||||
|
vkCmdPushConstants(
|
||||||
|
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
0, sizeof(push_t), &(push_t) { .vp = light_vp });
|
||||||
|
for (unsigned i = 0; i < model_count; ++i) {
|
||||||
|
vkCmdBindVertexBuffers(
|
||||||
|
ctx->cmd_buf, 0, 1, &models[i].vertex_buf,
|
||||||
|
&(VkDeviceSize) { 0 });
|
||||||
|
vkCmdBindIndexBuffer(
|
||||||
|
ctx->cmd_buf, models[i].index_buf, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
|
||||||
|
vkCmdBindDescriptorSets(
|
||||||
|
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
ctx->model_pipeline_layout, 0, 1, models[i].desc_sets + curr_img,
|
||||||
|
0, nullptr);
|
||||||
|
|
||||||
|
vkCmdDrawIndexed(ctx->cmd_buf, models[i].index_count, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
vkCmdEndRenderPass(ctx->cmd_buf);
|
||||||
|
|
||||||
|
// Wait until shadow map is fully written and transition to shader
|
||||||
|
// read-only layout.
|
||||||
|
const VkImageMemoryBarrier shadows_ready = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
.image = ctx->shadow_img,
|
||||||
|
.subresourceRange = {
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||||
|
.levelCount = 1,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
ctx->cmd_buf, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1,
|
||||||
|
&shadows_ready);
|
||||||
|
|
||||||
VkClearValue clear_values[] = {
|
VkClearValue clear_values[] = {
|
||||||
[0] = { .color = { { 0.0, 0.0, 0.0, 1.0 } } },
|
[0] = { .color = { { 0.0, 0.0, 0.0, 1.0 } } },
|
||||||
[1] = { .depthStencil = { 1.0, 0.0 } },
|
[1] = { .depthStencil = { 1.0, 0.0 } },
|
||||||
@@ -1123,12 +1191,14 @@ void gpu_render(
|
|||||||
vkCmdBeginRenderPass(
|
vkCmdBeginRenderPass(
|
||||||
ctx->cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
ctx->cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
const push_t push = { .vp = vp, .light_vp = light_vp };
|
||||||
|
|
||||||
// Draw floor
|
// Draw floor
|
||||||
vkCmdBindPipeline(
|
vkCmdBindPipeline(
|
||||||
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->floor_pipeline);
|
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->floor_pipeline);
|
||||||
vkCmdPushConstants(
|
vkCmdPushConstants(
|
||||||
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
0, sizeof(mat4_t), &vp);
|
0, sizeof(push_t), &push);
|
||||||
vkCmdDraw(ctx->cmd_buf, 4, 1, 0, 0);
|
vkCmdDraw(ctx->cmd_buf, 4, 1, 0, 0);
|
||||||
|
|
||||||
// Draw models
|
// Draw models
|
||||||
@@ -1136,13 +1206,8 @@ void gpu_render(
|
|||||||
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->model_pipeline);
|
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->model_pipeline);
|
||||||
vkCmdPushConstants(
|
vkCmdPushConstants(
|
||||||
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
0, sizeof(mat4_t), &vp);
|
0, sizeof(push_t), &push);
|
||||||
for (unsigned i = 0; i < model_count; ++i) {
|
for (unsigned i = 0; i < model_count; ++i) {
|
||||||
models[i].transform_ptr[curr_img] = model_transforms[i];
|
|
||||||
memcpy(
|
|
||||||
models[i].bone_ptr + (models[i].bone_count * curr_img),
|
|
||||||
bone_matrices[i], models[i].bone_count * sizeof(mat4_t));
|
|
||||||
|
|
||||||
vkCmdBindVertexBuffers(
|
vkCmdBindVertexBuffers(
|
||||||
ctx->cmd_buf, 0, 1, &models[i].vertex_buf,
|
ctx->cmd_buf, 0, 1, &models[i].vertex_buf,
|
||||||
&(VkDeviceSize) { 0 });
|
&(VkDeviceSize) { 0 });
|
||||||
@@ -1157,8 +1222,28 @@ void gpu_render(
|
|||||||
vkCmdDrawIndexed(ctx->cmd_buf, models[i].index_count, 1, 0, 0, 0);
|
vkCmdDrawIndexed(ctx->cmd_buf, models[i].index_count, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish render pass and end writing to command buffer
|
|
||||||
vkCmdEndRenderPass(ctx->cmd_buf);
|
vkCmdEndRenderPass(ctx->cmd_buf);
|
||||||
|
|
||||||
|
// Wait until render pass is finished reading shadow map and transition
|
||||||
|
// back to depth stencil layout
|
||||||
|
const VkImageMemoryBarrier shadows_done = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||||
|
.image = ctx->shadow_img,
|
||||||
|
.subresourceRange = {
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||||
|
.levelCount = 1,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
ctx->cmd_buf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0, 0, nullptr, 0,
|
||||||
|
nullptr, 1, &shadows_done);
|
||||||
|
|
||||||
result = vkEndCommandBuffer(ctx->cmd_buf);
|
result = vkEndCommandBuffer(ctx->cmd_buf);
|
||||||
assert(result == VK_SUCCESS);
|
assert(result == VK_SUCCESS);
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ void gpu_model_load(
|
|||||||
void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model);
|
void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model);
|
||||||
|
|
||||||
void gpu_render(
|
void gpu_render(
|
||||||
const gpu_ctx_t *ctx, mat4_t vp, size_t model_count,
|
const gpu_ctx_t *ctx, mat4_t vp, mat4_t light_vp, size_t model_count,
|
||||||
const gpu_model_t *models, const mat4_t **bone_matrices,
|
const gpu_model_t *models, const mat4_t **bone_matrices,
|
||||||
const mat4_t *model_transforms);
|
const mat4_t *model_transforms);
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,12 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
const vec3_t cam = { 0, 4, -8 };
|
const vec3_t cam = { 0, 4, -8 };
|
||||||
const vec3_t tgt = { 0, 0, 0 };
|
const vec3_t tgt = { 0, 0, 0 };
|
||||||
const mat4_t view = mat4_lookat(cam, tgt, (vec3_t) { 0, 1, 0 });
|
const vec3_t up = { 0, 1, 0 };
|
||||||
|
const vec3_t light = { 2, 2, -1 };
|
||||||
|
const mat4_t view = mat4_lookat(cam, tgt, up);
|
||||||
const mat4_t proj = mat4_perspective((float)W / H, PI / 8, 0.1, 100.0);
|
const mat4_t proj = mat4_perspective((float)W / H, PI / 8, 0.1, 100.0);
|
||||||
const mat4_t vp = mat4_mul(proj, view);
|
const mat4_t vp = mat4_mul(proj, view);
|
||||||
|
const mat4_t light_vp = mat4_lookat(light, tgt, up);
|
||||||
mat4_t transforms[NELEMS(gpu_models)] = {
|
mat4_t transforms[NELEMS(gpu_models)] = {
|
||||||
mat4_mul(
|
mat4_mul(
|
||||||
MAT4_TRANSLATE(1, 0, 0),
|
MAT4_TRANSLATE(1, 0, 0),
|
||||||
@@ -100,8 +103,8 @@ int main(int argc, char *argv[])
|
|||||||
anim.bone_matrices,
|
anim.bone_matrices,
|
||||||
};
|
};
|
||||||
gpu_render(
|
gpu_render(
|
||||||
&gpu, vp, NELEMS(gpu_models), gpu_models, bone_matrices,
|
&gpu, vp, light_vp, NELEMS(gpu_models), gpu_models,
|
||||||
transforms);
|
bone_matrices, transforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
|
|||||||
+9
-5
@@ -6,10 +6,12 @@ layout(location = 2) in uvec4 bone_indices;
|
|||||||
layout(location = 3) in vec4 weights;
|
layout(location = 3) in vec4 weights;
|
||||||
|
|
||||||
layout(location = 0) out vec3 frag_normal;
|
layout(location = 0) out vec3 frag_normal;
|
||||||
|
layout(location = 1) out vec4 light_pos;
|
||||||
|
|
||||||
layout(push_constant) uniform vp_t {
|
layout(push_constant) uniform push_t {
|
||||||
mat4 transform;
|
mat4 vp;
|
||||||
} vp;
|
mat4 light_vp;
|
||||||
|
} push;
|
||||||
|
|
||||||
layout(binding = 0) uniform transform_t {
|
layout(binding = 0) uniform transform_t {
|
||||||
mat4 model;
|
mat4 model;
|
||||||
@@ -25,8 +27,10 @@ void main() {
|
|||||||
+ weights.y * bones.matrices[bone_indices.y]
|
+ weights.y * bones.matrices[bone_indices.y]
|
||||||
+ weights.z * bones.matrices[bone_indices.z]
|
+ weights.z * bones.matrices[bone_indices.z]
|
||||||
+ weights.w * bones.matrices[bone_indices.w];
|
+ weights.w * bones.matrices[bone_indices.w];
|
||||||
gl_Position = vp.transform * transform.model * skinning_matrix
|
const vec4 world_pos
|
||||||
* vec4(position, 1.0);
|
= transform.model * skinning_matrix * vec4(position, 1.0);
|
||||||
|
gl_Position = push.vp * world_pos;
|
||||||
frag_normal = transpose(
|
frag_normal = transpose(
|
||||||
inverse(mat3(transform.model * skinning_matrix))) * normal;
|
inverse(mat3(transform.model * skinning_matrix))) * normal;
|
||||||
|
light_pos = push.light_vp * world_pos;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user