Implement configurable lighting
This commit is contained in:
1 parent
070758b6cc
commit
b5bda150d2
6 files changed
+148
-49
No files matched your search
+66
-10
@@ -1,8 +1,28 @@
|
||||
#version 450
|
||||
|
||||
float ambient = 0.1;
|
||||
vec3 light_dir = normalize(vec3(2, 2, -1));
|
||||
vec3 base_colour = vec3(1.0, 0.94, 0.8);
|
||||
#define PI 3.14159265358979
|
||||
|
||||
float floor_light_coeff = 0.01;
|
||||
|
||||
float sunny_sky_light_coeff = 0.5;
|
||||
float cloudy_sky_light_coeff = 0.4;
|
||||
|
||||
float sunny_sun_light_coeff = 0.8;
|
||||
float cloudy_sun_light_coeff = 0.3;
|
||||
|
||||
float sunny_shadow_pcf_radius = 1;
|
||||
float cloudy_shadow_pcf_radius = 24;
|
||||
|
||||
vec3 sunny_sky_colour = vec3(0.5, 0.7, 1.0);
|
||||
vec3 cloudy_sky_colour = vec3(0.7, 0.7, 1.0);
|
||||
|
||||
vec3 sunny_sun_colour = vec3(1.0, 0.95, 0.8);
|
||||
vec3 cloudy_sun_colour = vec3(0.7, 0.7, 1.0);
|
||||
|
||||
vec3 material_colour = vec3(1.0, 0.94, 0.8);
|
||||
|
||||
float shadow_bias = 0.005;
|
||||
float shadow_map_size = 4096;
|
||||
|
||||
layout(location = 0) in vec3 frag_normal;
|
||||
layout(location = 1) in vec4 light_pos;
|
||||
@@ -11,18 +31,54 @@ layout(location = 0) out vec4 out_colour;
|
||||
|
||||
layout(binding = 2) uniform sampler2DShadow shadow_map;
|
||||
|
||||
layout(push_constant) uniform params_t {
|
||||
layout(offset = 128) vec3 sun_dir;
|
||||
layout(offset = 140) float cloudiness;
|
||||
} params;
|
||||
|
||||
void main()
|
||||
{
|
||||
const float lambertian = max(dot(frag_normal, light_dir), 0.0);
|
||||
const float sky_light_coeff
|
||||
= mix(sunny_sky_light_coeff, cloudy_sky_light_coeff,
|
||||
params.cloudiness);
|
||||
const float sun_light_coeff
|
||||
= mix(sunny_sun_light_coeff, cloudy_sun_light_coeff,
|
||||
params.cloudiness);
|
||||
const float shadow_pcf_radius
|
||||
= mix(sunny_shadow_pcf_radius, cloudy_shadow_pcf_radius,
|
||||
params.cloudiness);
|
||||
const vec3 sky_colour
|
||||
= mix(sunny_sky_colour, cloudy_sky_colour,
|
||||
params.cloudiness);
|
||||
const vec3 sun_colour
|
||||
= mix(sunny_sun_colour, cloudy_sun_colour,
|
||||
params.cloudiness);
|
||||
|
||||
const float lambertian = max(dot(frag_normal, params.sun_dir), 0.0);
|
||||
|
||||
const float shadow_bias = 0.005;
|
||||
const vec3 proj_coords = light_pos.xyz / light_pos.w;
|
||||
const vec3 shadow_map_pos
|
||||
= vec3(0.5 * proj_coords.xy + 0.5, proj_coords.z);
|
||||
float shadow = texture(
|
||||
shadow_map,
|
||||
vec3(shadow_map_pos.xy, shadow_map_pos.z - shadow_bias));
|
||||
float shadow = 0.0;
|
||||
for (int x = -2; x <= 2; ++x) {
|
||||
for (int y = -2; y < 3; ++y) {
|
||||
const vec2 offset
|
||||
= shadow_pcf_radius * vec2(x, y) / shadow_map_size;
|
||||
shadow += texture(
|
||||
shadow_map,
|
||||
vec3(shadow_map_pos.xy + offset,
|
||||
shadow_map_pos.z - shadow_bias));
|
||||
}
|
||||
}
|
||||
shadow /= 25;
|
||||
const vec3 sun_light = shadow * lambertian * sun_colour;
|
||||
|
||||
const float intensity = min(shadow * lambertian + ambient, 1.0);
|
||||
out_colour = vec4(intensity * base_colour, 1.0);
|
||||
const vec3 floor_colour = floor_light_coeff * material_colour;
|
||||
const float t = 0.5 * clamp(frag_normal.y, -1, 1) + 0.5;
|
||||
const vec3 sky_light = mix(floor_colour, sky_colour, t);
|
||||
|
||||
const vec3 lighting
|
||||
= sun_light_coeff * sun_light
|
||||
+ sky_light_coeff * sky_light;
|
||||
out_colour = vec4(lighting * material_colour, 1.0);
|
||||
}
|
||||
+5
-5
@@ -3,10 +3,10 @@
|
||||
layout(location = 0) out vec3 frag_normal;
|
||||
layout(location = 1) out vec4 light_pos;
|
||||
|
||||
layout(push_constant) uniform push_t {
|
||||
layout(push_constant) uniform vps_t {
|
||||
mat4 vp;
|
||||
mat4 light_vp;
|
||||
} push;
|
||||
} vps;
|
||||
|
||||
vec2 vertices[4] = vec2[](
|
||||
vec2(-1, -1),
|
||||
@@ -16,9 +16,9 @@ vec2 vertices[4] = vec2[](
|
||||
);
|
||||
|
||||
void main() {
|
||||
const vec2 pos = 3 * vertices[gl_VertexIndex];
|
||||
const vec2 pos = 4 * vertices[gl_VertexIndex];
|
||||
const vec4 world_pos = vec4(pos.x, 0, pos.y, 1);
|
||||
gl_Position = push.vp * world_pos;
|
||||
gl_Position = vps.vp * world_pos;
|
||||
frag_normal = vec3(0, 1, 0);
|
||||
light_pos = push.light_vp * world_pos;
|
||||
light_pos = vps.light_vp * world_pos;
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#define MAX_MODEL_COUNT 4
|
||||
|
||||
#define SHADOW_IMG_SIZE 2048
|
||||
#define SHADOW_IMG_SIZE 4096
|
||||
|
||||
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
typedef struct {
|
||||
mat4_t vp;
|
||||
mat4_t light_vp;
|
||||
} vps_t;
|
||||
|
||||
typedef struct {
|
||||
vps_t vps;
|
||||
light_params_t light;
|
||||
} push_t;
|
||||
|
||||
static const char *layers[] = { "VK_LAYER_KHRONOS_validation" };
|
||||
@@ -570,11 +575,18 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name)
|
||||
.pAttachments = &colour_blend_attatchment,
|
||||
};
|
||||
|
||||
// Set up push constant config
|
||||
const VkPushConstantRange push_constant_range = {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0,
|
||||
.size = sizeof(push_t),
|
||||
// Push constant configs
|
||||
const VkPushConstantRange push_constants[] = {
|
||||
{
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = offsetof(push_t, vps),
|
||||
.size = sizeof(vps_t),
|
||||
},
|
||||
{
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
.offset = offsetof(push_t, light),
|
||||
.size = sizeof(light_params_t),
|
||||
},
|
||||
};
|
||||
|
||||
// Load vertex and fragment shader modules
|
||||
@@ -638,8 +650,8 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name)
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &ctx->floor_desc_set_layout,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &push_constant_range,
|
||||
.pushConstantRangeCount = 2,
|
||||
.pPushConstantRanges = push_constants,
|
||||
};
|
||||
result = vkCreatePipelineLayout(
|
||||
ctx->dev, &floor_pipeline_layout_config, nullptr,
|
||||
@@ -753,8 +765,8 @@ void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name)
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &ctx->desc_set_layout,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &push_constant_range,
|
||||
.pushConstantRangeCount = 2,
|
||||
.pPushConstantRanges = push_constants,
|
||||
};
|
||||
result = vkCreatePipelineLayout(
|
||||
ctx->dev, &model_pipeline_layout_config, nullptr,
|
||||
@@ -1187,12 +1199,18 @@ void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model)
|
||||
}
|
||||
|
||||
void gpu_render(
|
||||
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 mat4_t *model_transforms)
|
||||
const gpu_ctx_t *ctx, mat4_t vp, light_params_t light,
|
||||
size_t model_count, const gpu_model_t *models,
|
||||
const mat4_t **bone_matrices, const mat4_t *model_transforms)
|
||||
{
|
||||
VkResult result;
|
||||
|
||||
// Compute light VP
|
||||
const mat4_t light_view = mat4_lookat(
|
||||
light.sun_dir, (vec3_t) { 0, 0, 0 }, (vec3_t) { 0, 1, 0 });
|
||||
const mat4_t light_proj = mat4_orthographic(8, 8, -10, 10);
|
||||
const mat4_t light_vp = mat4_mul(light_proj, light_view);
|
||||
|
||||
// Wait for previous frame to finish
|
||||
vkWaitForFences(ctx->dev, 1, &ctx->in_flight, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(ctx->dev, 1, &ctx->in_flight);
|
||||
@@ -1238,7 +1256,7 @@ void gpu_render(
|
||||
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 });
|
||||
0, sizeof(vps_t), &(vps_t) { .vp = light_vp });
|
||||
for (unsigned i = 0; i < model_count; ++i) {
|
||||
vkCmdBindVertexBuffers(
|
||||
ctx->cmd_buf, 0, 1, &models[i].vertex_buf,
|
||||
@@ -1290,14 +1308,18 @@ void gpu_render(
|
||||
vkCmdBeginRenderPass(
|
||||
ctx->cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
const push_t push = { .vp = vp, .light_vp = light_vp };
|
||||
const vps_t vps = { .vp = vp, .light_vp = light_vp };
|
||||
|
||||
// Draw floor
|
||||
vkCmdBindPipeline(
|
||||
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->floor_pipeline);
|
||||
vkCmdPushConstants(
|
||||
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0, sizeof(push_t), &push);
|
||||
ctx->cmd_buf, ctx->floor_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
offsetof(push_t, vps), sizeof(vps_t), &vps);
|
||||
vkCmdPushConstants(
|
||||
ctx->cmd_buf, ctx->floor_pipeline_layout,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, offsetof(push_t, light),
|
||||
sizeof(light_params_t), &light);
|
||||
vkCmdBindDescriptorSets(
|
||||
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
ctx->floor_pipeline_layout, 0, 1, ctx->floor_desc_sets + curr_img, 0,
|
||||
@@ -1309,7 +1331,11 @@ void gpu_render(
|
||||
ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->model_pipeline);
|
||||
vkCmdPushConstants(
|
||||
ctx->cmd_buf, ctx->model_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0, sizeof(push_t), &push);
|
||||
offsetof(push_t, vps), sizeof(vps_t), &vps);
|
||||
vkCmdPushConstants(
|
||||
ctx->cmd_buf, ctx->model_pipeline_layout,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, offsetof(push_t, light),
|
||||
sizeof(light_params_t), &light);
|
||||
for (unsigned i = 0; i < model_count; ++i) {
|
||||
vkCmdBindVertexBuffers(
|
||||
ctx->cmd_buf, 0, 1, &models[i].vertex_buf,
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
|
||||
#define MAX_FRAMES_IN_FLIGHT 4
|
||||
|
||||
typedef struct {
|
||||
vec3_t sun_dir;
|
||||
float cloudiness;
|
||||
} light_params_t;
|
||||
|
||||
typedef struct {
|
||||
VkInstance inst;
|
||||
VkSurfaceKHR surface;
|
||||
@@ -77,8 +82,8 @@ void gpu_model_load(
|
||||
void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model);
|
||||
|
||||
void gpu_render(
|
||||
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 mat4_t *model_transforms);
|
||||
const gpu_ctx_t *ctx, mat4_t vp, light_params_t light,
|
||||
size_t model_count, const gpu_model_t *models,
|
||||
const mat4_t **bone_matrices, const mat4_t *model_transforms);
|
||||
|
||||
#endif
|
||||
@@ -7,13 +7,15 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define W 800
|
||||
#define H 600
|
||||
#define W 1280
|
||||
#define H 720
|
||||
|
||||
#define DT (1'000'000 / 60) // Assume 60 Hz for now
|
||||
|
||||
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
static light_params_t light_params;
|
||||
|
||||
static void
|
||||
key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
@@ -28,6 +30,17 @@ key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
||||
case GLFW_KEY_Q:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_UP:
|
||||
light_params.cloudiness += 0.05;
|
||||
if (light_params.cloudiness > 1)
|
||||
light_params.cloudiness = 1;
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
light_params.cloudiness -= 0.05;
|
||||
if (light_params.cloudiness < 0)
|
||||
light_params.cloudiness = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,16 +70,12 @@ int main(int argc, char *argv[])
|
||||
gpu_model_load(&gpu, &model, gpu_models + 0);
|
||||
gpu_model_load(&gpu, &model, gpu_models + 1);
|
||||
|
||||
const vec3_t cam = { 0, 4, -8 };
|
||||
const vec3_t cam = { 2, 2, -8 };
|
||||
const vec3_t tgt = { 0, 0, 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 / 12, 0.1, 100.0);
|
||||
const mat4_t vp = mat4_mul(proj, view);
|
||||
const mat4_t light_view = mat4_lookat(light, tgt, up);
|
||||
const mat4_t light_proj = mat4_orthographic(5, 5, 10);
|
||||
const mat4_t light_vp = mat4_mul(light_proj, light_view);
|
||||
mat4_t transforms[NELEMS(gpu_models)] = {
|
||||
mat4_mul(
|
||||
MAT4_TRANSLATE(1, 0, 0),
|
||||
@@ -92,6 +101,9 @@ int main(int argc, char *argv[])
|
||||
animation_state_t anim = animation_init(&model);
|
||||
animation_start(&anim, &model, 0);
|
||||
|
||||
light_params.sun_dir = vec3_norm((vec3_t) { 2, 4, -1 });
|
||||
light_params.cloudiness = 0.0;
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
glfwPollEvents();
|
||||
|
||||
@@ -105,7 +117,7 @@ int main(int argc, char *argv[])
|
||||
anim.bone_matrices,
|
||||
};
|
||||
gpu_render(
|
||||
&gpu, vp, light_vp, NELEMS(gpu_models), gpu_models,
|
||||
&gpu, vp, light_params, NELEMS(gpu_models), gpu_models,
|
||||
bone_matrices, transforms);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -8,10 +8,10 @@ layout(location = 3) in vec4 weights;
|
||||
layout(location = 0) out vec3 frag_normal;
|
||||
layout(location = 1) out vec4 light_pos;
|
||||
|
||||
layout(push_constant) uniform push_t {
|
||||
layout(push_constant) uniform vps_t {
|
||||
mat4 vp;
|
||||
mat4 light_vp;
|
||||
} push;
|
||||
} vps;
|
||||
|
||||
layout(binding = 0) uniform transform_t {
|
||||
mat4 model;
|
||||
@@ -29,8 +29,8 @@ void main() {
|
||||
+ weights.w * bones.matrices[bone_indices.w];
|
||||
const vec4 world_pos
|
||||
= transform.model * skinning_matrix * vec4(position, 1.0);
|
||||
gl_Position = push.vp * world_pos;
|
||||
gl_Position = vps.vp * world_pos;
|
||||
frag_normal = transpose(
|
||||
inverse(mat3(transform.model * skinning_matrix))) * normal;
|
||||
light_pos = push.light_vp * world_pos;
|
||||
light_pos = vps.light_vp * world_pos;
|
||||
}
|
||||
Reference in new issue
Block a user