add camera tilt

This commit is contained in:
Sven Balzer
2025-03-11 09:16:17 +01:00
parent e77086601b
commit 2ad30458bf
11 changed files with 530 additions and 461 deletions
+37 -18
View File
@@ -19,6 +19,8 @@
using namespace M;
#define NEAR_PLANE (0.01f)
SDL_GPUDevice *device;
SDL_Window *window;
@@ -37,11 +39,11 @@ Sint32 window_height;
bool Running = true;
#define view_width 16
#define view_height 9
M4x4 view_matrix = view (V3_(0.0f, 0.0f, 0.0f), radians(45.0f), 10.0f);
M4x4 inverse_view_matrix = inverse_view(V3_(0.0f, 0.0f, 0.0f), radians(45.0f), 10.0f);
M4x4 projection_matrix = projection (radians(45.0f), 1.0f, 0.001f);
M4x4 inverse_projection_matrix = inverse_projection(radians(45.0f), 1.0f, 0.001f);
M4x4 projection_matrix = projection (radians(45.0f), 16.0f / 9.0f, NEAR_PLANE);
M4x4 inverse_projection_matrix = inverse_projection(radians(45.0f), 16.0f / 9.0f, NEAR_PLANE);
struct Vertex {
V3 pos;
@@ -84,11 +86,12 @@ struct PerFrame {
float fovy_degrees;
float camera_x;
float camera_y;
float camera_z;
float camera_distance;
float camera_tilt;
Uint32 map_width;
};
PerFrame per_frame = { 1.0f, 45.0f, 0, 0, -10 };
PerFrame per_frame = { 1.0f, 45.0f, 0.0f, 0.0f, 10.0f, 45.0f };
typedef struct {
Uint16 type;
@@ -590,6 +593,13 @@ ImVec4 sRGB_to_linear(ImVec4 linear) {
return ImVec4(red, green, blue, linear.w);
}
V3 Unproject(V3 screen_pos) {
V4 result = inverse_view_matrix * inverse_projection_matrix * V4_(screen_pos, 1.0f);
result.xyz /= result.w;
return result.xyz;
}
int main(int argc, char **argv) {
load_map();
@@ -908,7 +918,7 @@ int main(int argc, char **argv) {
.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE,
.max_anisotropy = 16.0f,
.enable_anisotropy = true,
// .enable_anisotropy = true,
};
point_sampler = SDL_CreateGPUSampler(device, &point_sampler_info);
@@ -1033,8 +1043,9 @@ int main(int argc, char **argv) {
selected_rotation = -1;
}
ImGui::DragFloat("fovy", &per_frame.fovy_degrees);
ImGui::DragFloat("camera_z", &per_frame.camera_z);
ImGui::DragFloat("fovy", &per_frame.fovy_degrees);
ImGui::DragFloat("camera_distance", &per_frame.camera_distance, 0.25f, 1.0f, INFINITY);
ImGui::DragFloat("camera_tilt", &per_frame.camera_tilt, 0.25f, 0.0f, 89.0f);
}
ImGui::End();
@@ -1079,7 +1090,7 @@ int main(int argc, char **argv) {
continue;
if (event.key.key == SDLK_UP || event.key.key == SDLK_W) {
player.pos_y = clamp(0, player.pos_y - 1, map_height - 1);
player.pos_y = clamp(0, player.pos_y + 1, map_height - 1);
}
if (event.key.key == SDLK_LEFT || event.key.key == SDLK_A) {
@@ -1087,7 +1098,7 @@ int main(int argc, char **argv) {
}
if (event.key.key == SDLK_DOWN || event.key.key == SDLK_S) {
player.pos_y = clamp(0, player.pos_y + 1, map_height - 1);
player.pos_y = clamp(0, player.pos_y - 1, map_height - 1);
}
if (event.key.key == SDLK_RIGHT || event.key.key == SDLK_D) {
@@ -1110,12 +1121,17 @@ int main(int argc, char **argv) {
float mouse_x = event.button.x;
float mouse_y = event.button.y;
V2 mouse = remap(V2{ 0, 0 }, V2{ (float)window_width, (float)window_height }, V2{ -1, -1 }, V2{ 1, 1 }, V2{ mouse_x, mouse_y });
V4 mouse_world = inverse_projection_matrix * V4{ mouse.x, mouse.y, -per_frame.camera_z * 0.001f, 1 };
mouse_world.xy *= mouse_world.w;
V2 mouse = remap(V2{ 0, 0 }, V2{ (float)window_width, (float)window_height }, V2{ -1, 1 }, V2{ 1, -1 }, V2{ mouse_x, mouse_y });
V3 camera_position = (inverse_view_matrix * V4_(0, 0, 0, 1)).xyz;
Sint32 tile_x = roundf(mouse_world.x) + player.pos_x;
Sint32 tile_y = roundf(mouse_world.y) + player.pos_y;
V3 probe = Unproject(V3_(mouse, .5));
V3 ray_dir = normalize(probe - camera_position);
float t = -camera_position.z / ray_dir.z;
V3 floor_intersection = camera_position + (t * ray_dir);
Sint32 tile_x = roundf(floor_intersection.x);
Sint32 tile_y = roundf(floor_intersection.y);
if (selected_tile != -1) {
if(0 <= tile_x && tile_x < map_width &&
@@ -1182,8 +1198,11 @@ int main(int argc, char **argv) {
SDL_PushGPUVertexUniformData(command_buffer, 0, &per_frame, sizeof(per_frame));
projection_matrix = projection (radians(per_frame.fovy_degrees), per_frame.aspect_ratio, 0.001f);
inverse_projection_matrix = inverse_projection(radians(per_frame.fovy_degrees), per_frame.aspect_ratio, 0.001f);
view_matrix = view (V3_((float)player.pos_x, (float)player.pos_y, 0), radians(per_frame.camera_tilt), per_frame.camera_distance);
inverse_view_matrix = inverse_view(V3_((float)player.pos_x, (float)player.pos_y, 0), radians(per_frame.camera_tilt), per_frame.camera_distance);
projection_matrix = projection (radians(per_frame.fovy_degrees), per_frame.aspect_ratio, NEAR_PLANE);
inverse_projection_matrix = inverse_projection(radians(per_frame.fovy_degrees), per_frame.aspect_ratio, NEAR_PLANE);
SDL_GPUColorTargetInfo color_target_info = {
.texture = swapchain_texture,
+24
View File
@@ -873,6 +873,30 @@ namespace M {
};
}
M4x4 view(V3 player_pos, float tilt, float camera_distance) {
float s = sinf(-tilt);
float c = cosf(-tilt);
return M4x4_(
1, 0, 0, -player_pos.x,
0, c, s, c * -player_pos.y,
0, -s, c, s * player_pos.y + camera_distance,
0, 0, 0, 1
);
}
M4x4 inverse_view(V3 player_pos, float tilt, float camera_distance) {
float s = sinf(-tilt);
float c = cosf(-tilt);
return M4x4_(
1, 0, 0, player_pos.x,
0, c, -s, s * camera_distance + player_pos.y,
0, s, c, c * -camera_distance,
0, 0, 0, 1
);
}
M4x4 projection(float fovy, float aspect, float near) {
float g = 1.0 / tanf(fovy * 0.5);
+23
View File
@@ -258,6 +258,16 @@ namespace M {
float _a;
};
struct {
V3 xyz;
float _w2;
};
struct {
float _x2;
V3 yzw;
};
struct {
V3 rgb;
float _a2;
@@ -268,6 +278,16 @@ namespace M {
V3 gba;
};
struct {
V3 uvs;
float _t2;
};
struct {
float _u2;
V3 vst;
};
struct {
float E[4];
};
@@ -461,6 +481,9 @@ namespace M {
M4x4 transpose(M4x4 a);
M4x4 view (V3 player_pos, float tilt, float camera_distance);
M4x4 inverse_view(V3 player_pos, float tilt, float camera_distance);
M4x4 projection (float fovy, float aspect, float near);
M4x4 inverse_projection(float fovy, float aspect, float near);
}