summaryrefslogtreecommitdiff
path: root/src/model.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/model.c')
-rw-r--r--src/model.c179
1 files changed, 129 insertions, 50 deletions
diff --git a/src/model.c b/src/model.c
index 4171c21..2c78850 100644
--- a/src/model.c
+++ b/src/model.c
@@ -23,6 +23,7 @@
#include "camera.h"
#include "files.h"
#include "gpu.h"
+#include "shadow.h"
#include "ta_math.h"
static bool ta_model_push_vertex(ta_model_mesh *mesh, size_t *capacity, const ta_model_vertex *vertex) {
@@ -131,41 +132,39 @@ void ta_model_free(ta_model_mesh *mesh) {
}
typedef struct ta_model_uniforms {
- float mvp[16]; // TODO: Use dynamic buffer
- float model[16]; // TODO: Use dynamic buffer
+ float mvp[TA_MATRIX_ELEMENTS];
+ float model[TA_MATRIX_ELEMENTS];
+ float light_view_projection[TA_MATRIX_ELEMENTS];
float camera_position[TA_MODEL_DIMENSION];
- float padding;
+ float shadow_normal_offset;
} ta_model_uniforms;
-static SDL_GPUShader *ta_model_shader(SDL_GPUDevice *device, const void *code, size_t size, SDL_GPUShaderStage stage) {
+typedef struct ta_model_light_uniforms {
+ float direction[TA_MODEL_DIMENSION];
+ float shadow_texel_size;
+ float shadow_minimum_bias;
+ float shadow_maximum_bias;
+ float shadow_strength;
+ float padding;
+} ta_model_light_uniforms;
+
+typedef struct ta_model_shadow_uniforms {
+ float light_model_view_projection[TA_MATRIX_ELEMENTS];
+} ta_model_shadow_uniforms;
+
+static SDL_GPUShader *ta_model_shader(SDL_GPUDevice *device, const void *code, size_t size, SDL_GPUShaderStage stage, Uint32 num_samplers, Uint32 num_uniform_buffers) {
SDL_GPUShaderCreateInfo info = {
.code = code,
.code_size = size,
.entrypoint = "main",
.format = SDL_GPU_SHADERFORMAT_SPIRV,
.stage = stage,
- .num_uniform_buffers = stage == SDL_GPU_SHADERSTAGE_VERTEX ? 1 : 0,
+ .num_samplers = num_samplers,
+ .num_uniform_buffers = num_uniform_buffers,
};
return ta_sdl_create_gpu_shader(device, &info);
}
-static void ta_model_identity(float *matrix) {
- for (int index = 0; index < 16; index++) {
- matrix[index] = index % 5 == 0 ? 1.0f : 0.0f;
- }
-}
-
-static void ta_model_multiply(float *result, const float *left, const float *right) {
- float product[16];
- for (int column = 0; column < 4; column++) for (int row = 0; row < 4; row++) {
- product[column * 4 + row] = 0.0f;
- for (int inner = 0; inner < 4; inner++) {
- product[column * 4 + row] += left[inner * 4 + row] * right[column * 4 + inner];
- }
- }
- memcpy(result, product, sizeof(product));
-}
-
bool ta_model_init(ta_model *model, SDL_GPUDevice *device, const float positions[][TA_MODEL_DIMENSION], size_t position_count, const unsigned int faces[][TA_MODEL_DIMENSION], size_t face_count, SDL_GPUTextureFormat color_format, SDL_GPUTextureFormat depth_format, SDL_GPUSampleCount sample_count) {
memset(model, 0, sizeof(*model));
if (!ta_model_build(positions, position_count, faces, face_count, &model->mesh) || model->mesh.vertex_count == 0) {
@@ -182,8 +181,8 @@ bool ta_model_init(ta_model *model, SDL_GPUDevice *device, const float positions
return false;
}
model->vertex_count = (Uint32)model->mesh.vertex_count;
- SDL_GPUShader *vertex_shader = ta_model_shader(device, file_model_vert_slang_spv_start, file_model_vert_slang_spv_size, SDL_GPU_SHADERSTAGE_VERTEX);
- SDL_GPUShader *fragment_shader = ta_model_shader(device, file_model_frag_slang_spv_start, file_model_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT);
+ SDL_GPUShader *vertex_shader = ta_model_shader(device, file_model_vert_slang_spv_start, file_model_vert_slang_spv_size, SDL_GPU_SHADERSTAGE_VERTEX, 0, 1);
+ SDL_GPUShader *fragment_shader = ta_model_shader(device, file_model_frag_slang_spv_start, file_model_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
SDL_GPUVertexBufferDescription vertex_buffer = {.slot = 0, .pitch = sizeof(ta_model_vertex), .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX};
SDL_GPUVertexAttribute attributes[2] = {
{
@@ -232,15 +231,48 @@ bool ta_model_init(ta_model *model, SDL_GPUDevice *device, const float positions
};
model->pipeline = ta_sdl_create_gpu_graphics_pipeline(device, &pipeline_info);
- SDL_GPUShader *wireframe_fragment_shader = ta_model_shader(device, file_model_wireframe_frag_slang_spv_start, file_model_wireframe_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT);
+ SDL_GPUShader *wireframe_fragment_shader = ta_model_shader(device, file_model_wireframe_frag_slang_spv_start, file_model_wireframe_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 0);
pipeline_info.fragment_shader = wireframe_fragment_shader;
pipeline_info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_LINE;
model->wireframe_pipeline = ta_sdl_create_gpu_graphics_pipeline(device, &pipeline_info);
+ SDL_GPUShader *shadow_vertex_shader = ta_model_shader(device, file_shadow_vert_slang_spv_start, file_shadow_vert_slang_spv_size, SDL_GPU_SHADERSTAGE_VERTEX, 0, 1);
+ SDL_GPUShader *shadow_fragment_shader = ta_model_shader(device, file_shadow_frag_slang_spv_start, file_shadow_frag_slang_spv_size, SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 0);
+ SDL_GPUGraphicsPipelineCreateInfo shadow_pipeline_info = {
+ .vertex_shader = shadow_vertex_shader,
+ .fragment_shader = shadow_fragment_shader,
+ .vertex_input_state = {
+ .vertex_buffer_descriptions = &vertex_buffer,
+ .num_vertex_buffers = 1,
+ .vertex_attributes = attributes,
+ .num_vertex_attributes = 1
+ },
+ .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
+ .rasterizer_state = {
+ .cull_mode = SDL_GPU_CULLMODE_NONE
+ },
+ .depth_stencil_state = {
+ .compare_op = SDL_GPU_COMPAREOP_LESS,
+ .enable_depth_test = true,
+ .enable_depth_write = true
+ },
+ .multisample_state = {
+ .sample_count = SDL_GPU_SAMPLECOUNT_1
+ },
+ .target_info = {
+ .num_color_targets = 0,
+ .depth_stencil_format = TA_SHADOW_FORMAT,
+ .has_depth_stencil_target = true
+ },
+ };
+ model->shadow_pipeline = ta_sdl_create_gpu_graphics_pipeline(device, &shadow_pipeline_info);
+
SDL_ReleaseGPUShader(device, vertex_shader);
SDL_ReleaseGPUShader(device, fragment_shader);
SDL_ReleaseGPUShader(device, wireframe_fragment_shader);
- return model->pipeline != NULL && model->wireframe_pipeline != NULL;
+ SDL_ReleaseGPUShader(device, shadow_vertex_shader);
+ SDL_ReleaseGPUShader(device, shadow_fragment_shader);
+ return model->pipeline != NULL && model->wireframe_pipeline != NULL && model->shadow_pipeline != NULL;
}
void ta_model_upload(ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPUDevice *device) {
@@ -271,44 +303,48 @@ void ta_model_upload(ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_
model->uploaded = true;
}
-void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPURenderPass *render_pass, int window_width, int window_height) {
- if (!model->pipeline || !model->vertex_buffer || !model->uploaded) {
- return;
- }
- ta_model_uniforms uniforms;
- float view[16];
- float projection[16] = {0};
- float view_model[16];
- float rotation_x[16];
- float rotation_y[16];
- float rotation_z[16];
- float rotation_xy[16];
+static void ta_model_get_model_matrix(const ta_model *model, float *matrix) {
+ float rotation_x[TA_MATRIX_ELEMENTS];
+ float rotation_y[TA_MATRIX_ELEMENTS];
+ float rotation_z[TA_MATRIX_ELEMENTS];
+ float rotation_xy[TA_MATRIX_ELEMENTS];
float cosine = cosf(model->rotation[0]);
float sine = sinf(model->rotation[0]);
- ta_model_identity(rotation_x);
+ ta_matrix_identity(rotation_x);
rotation_x[5] = cosine;
rotation_x[6] = sine;
rotation_x[9] = -sine;
rotation_x[10] = cosine;
cosine = cosf(model->rotation[1]);
sine = sinf(model->rotation[1]);
- ta_model_identity(rotation_y);
+ ta_matrix_identity(rotation_y);
rotation_y[0] = cosine;
rotation_y[2] = -sine;
rotation_y[8] = sine;
rotation_y[10] = cosine;
cosine = cosf(model->rotation[2]);
sine = sinf(model->rotation[2]);
- ta_model_identity(rotation_z);
+ ta_matrix_identity(rotation_z);
rotation_z[0] = cosine;
rotation_z[1] = sine;
rotation_z[4] = -sine;
rotation_z[5] = cosine;
- ta_model_multiply(rotation_xy, rotation_y, rotation_x);
- ta_model_multiply(uniforms.model, rotation_z, rotation_xy);
- uniforms.model[12] = model->position[0];
- uniforms.model[13] = model->position[1];
- uniforms.model[14] = model->position[2];
+ ta_matrix_multiply(rotation_xy, rotation_y, rotation_x);
+ ta_matrix_multiply(matrix, rotation_z, rotation_xy);
+ matrix[12] = model->position[0];
+ matrix[13] = model->position[1];
+ matrix[14] = model->position[2];
+}
+
+void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPURenderPass *render_pass, int window_width, int window_height) {
+ if (!model->pipeline || !model->vertex_buffer || !model->uploaded) {
+ return;
+ }
+ ta_model_uniforms uniforms;
+ float view[TA_MATRIX_ELEMENTS];
+ float projection[TA_MATRIX_ELEMENTS] = {0};
+ float view_model[TA_MATRIX_ELEMENTS];
+ ta_model_get_model_matrix(model, uniforms.model);
float aspect = (float)window_width / (float)window_height;
float focal_length = 1.0f / tanf(ta_rad(ta_camera_current.fov * 0.5f));
float near_plane = 0.1f;
@@ -319,15 +355,57 @@ void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer
projection[10] = far_plane / (near_plane - far_plane);
projection[11] = -1.0f;
projection[14] = near_plane * far_plane / (near_plane - far_plane);
- ta_model_multiply(view_model, view, uniforms.model);
- ta_model_multiply(uniforms.mvp, projection, view_model);
+ ta_matrix_multiply(view_model, view, uniforms.model);
+ ta_matrix_multiply(uniforms.mvp, projection, view_model);
+ ta_shadow_get_light_view_projection(uniforms.light_view_projection);
uniforms.camera_position[0] = ta_camera_current.x;
uniforms.camera_position[1] = ta_camera_current.y;
uniforms.camera_position[2] = ta_camera_current.z;
- uniforms.padding = 0.0f;
- SDL_GPUGraphicsPipeline *pipeline = ta_gpu_enable_wireframe && model->wireframe_pipeline ? model->wireframe_pipeline : model->pipeline;
+ uniforms.shadow_normal_offset = ta_shadow_normal_offset;
+ bool wireframe = ta_gpu_enable_wireframe && model->wireframe_pipeline;
+ SDL_GPUGraphicsPipeline *pipeline = wireframe ? model->wireframe_pipeline : model->pipeline;
SDL_PushGPUVertexUniformData(command_buffer, 0, &uniforms, sizeof(uniforms));
SDL_BindGPUGraphicsPipeline(render_pass, pipeline);
+
+ if (!wireframe) {
+ ta_model_light_uniforms light = {
+ .direction = {
+ ta_shadow_light_direction[0],
+ ta_shadow_light_direction[1],
+ ta_shadow_light_direction[2]
+ },
+ .shadow_texel_size = 1.0f / (float)TA_SHADOW_MAP_SIZE,
+ .shadow_minimum_bias = ta_shadow_minimum_bias,
+ .shadow_maximum_bias = ta_shadow_maximum_bias,
+ .shadow_strength = ta_shadow_strength,
+ };
+ SDL_GPUTextureSamplerBinding shadow_binding = {
+ .texture = ta_shadow_texture,
+ .sampler = ta_shadow_sampler
+ };
+ SDL_PushGPUFragmentUniformData(command_buffer, 0, &light, sizeof(light));
+ SDL_BindGPUFragmentSamplers(render_pass, 0, &shadow_binding, 1);
+ }
+
+ SDL_GPUBufferBinding binding = {
+ .buffer = model->vertex_buffer
+ };
+ SDL_BindGPUVertexBuffers(render_pass, 0, &binding, 1);
+ SDL_DrawGPUPrimitives(render_pass, model->vertex_count, 1, 0, 0);
+}
+
+void ta_model_render_shadow(const ta_model *model, SDL_GPUCommandBuffer *command_buffer, SDL_GPURenderPass *render_pass) {
+ if (!model->shadow_pipeline || !model->vertex_buffer || !model->uploaded) {
+ return;
+ }
+ ta_model_shadow_uniforms uniforms;
+ float model_matrix[TA_MATRIX_ELEMENTS];
+ float light_view_projection[TA_MATRIX_ELEMENTS];
+ ta_model_get_model_matrix(model, model_matrix);
+ ta_shadow_get_light_view_projection(light_view_projection);
+ ta_matrix_multiply(uniforms.light_model_view_projection, light_view_projection, model_matrix);
+ SDL_PushGPUVertexUniformData(command_buffer, 0, &uniforms, sizeof(uniforms));
+ SDL_BindGPUGraphicsPipeline(render_pass, model->shadow_pipeline);
SDL_GPUBufferBinding binding = {
.buffer = model->vertex_buffer
};
@@ -338,6 +416,7 @@ void ta_model_render(const ta_model *model, SDL_GPUCommandBuffer *command_buffer
void ta_model_destroy(ta_model *model, SDL_GPUDevice *device) {
SDL_ReleaseGPUGraphicsPipeline(device, model->pipeline);
SDL_ReleaseGPUGraphicsPipeline(device, model->wireframe_pipeline);
+ SDL_ReleaseGPUGraphicsPipeline(device, model->shadow_pipeline);
SDL_ReleaseGPUBuffer(device, model->vertex_buffer);
ta_model_free(&model->mesh);
memset(model, 0, sizeof(*model));