add remaining camera modes

This commit is contained in:
Crydsch 2022-07-12 16:36:18 +02:00
parent 5cd17cc024
commit cb8f2ff494
2 changed files with 193 additions and 96 deletions

View File

@ -29,12 +29,15 @@ int main(void)
// Define the camera to look into our 3d world (position, target, up vector) // Define the camera to look into our 3d world (position, target, up vector)
Camera camera = { 0 }; Camera camera = { 0 };
camera.position = (Vector3){ 4.0f, 2.0f, 4.0f }; camera.position = (Vector3){ 0.0f, 2.0f, 4.0f };
camera.target = (Vector3){ 0.0f, 1.8f, 0.0f }; camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
camera.fovy = 60.0f; camera.fovy = 60.0f;
camera.projection = CAMERA_PERSPECTIVE; camera.projection = CAMERA_PERSPECTIVE;
// Set a first person camera mode
SetCameraMode(&camera, CAMERA_FIRST_PERSON);
// Generates some random columns // Generates some random columns
float heights[MAX_COLUMNS] = { 0 }; float heights[MAX_COLUMNS] = { 0 };
Vector3 positions[MAX_COLUMNS] = { 0 }; Vector3 positions[MAX_COLUMNS] = { 0 };
@ -47,8 +50,6 @@ int main(void)
colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 }; colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 };
} }
SetCameraMode(&camera, CAMERA_FIRST_PERSON); // Set a first person camera mode
// Catch cursor // Catch cursor
DisableCursor(); DisableCursor();
@ -83,14 +84,39 @@ int main(void)
DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, MAROON); DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, MAROON);
} }
// Draw player cube
if (camera.mode == CAMERA_THIRD_PERSON)
{
DrawCube(camera.target, 0.5f, 0.5f, 0.5f, PURPLE);
DrawCubeWires(camera.target, 0.5f, 0.5f, 0.5f, DARKPURPLE);
}
EndMode3D(); EndMode3D();
DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f)); // Draw info boxes
DrawRectangleLines( 10, 10, 220, 70, BLUE); DrawRectangle(5, 5, 330, 100, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(5, 5, 330, 100, BLUE);
DrawText("First person camera default controls:", 20, 20, 10, BLACK); DrawText("Camera controls:", 15, 15, 10, BLACK);
DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY); DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK);
DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY); DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK);
DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, BLACK);
DrawText("- Zoom keys: num-plus, num-minus or mouse scroll", 15, 75, 10, BLACK);
DrawText("- Camera projection key: P", 15, 90, 10, BLACK);
DrawRectangle(600, 5, 195, 100, Fade(SKYBLUE, 0.5f));
DrawRectangleLines(600, 5, 195, 100, BLUE);
DrawText("Camera status:", 610, 15, 10, BLACK);
DrawText(TextFormat("- Mode: %s", (camera.mode == CAMERA_FREE) ? "FREE" :
(camera.mode == CAMERA_FIRST_PERSON) ? "FIRST_PERSON" :
(camera.mode == CAMERA_THIRD_PERSON) ? "THIRD_PERSON" :
(camera.mode == CAMERA_ORBITAL) ? "ORBITAL" : "CUSTOM"), 610, 30, 10, BLACK);
DrawText(TextFormat("- Projection: %s", (camera.projection == CAMERA_PERSPECTIVE) ? "PERSPECTIVE" :
(camera.projection == CAMERA_ORTHOGRAPHIC) ? "ORTHOGRAPHIC" : "CUSTOM"), 610, 45, 10, BLACK);
DrawText(TextFormat("- Position: (%06.3f, %06.3f, %06.3f)", camera.position.x, camera.position.y, camera.position.z), 610, 60, 10, BLACK);
DrawText(TextFormat("- Target: (%06.3f, %06.3f, %06.3f)", camera.target.x, camera.target.y, camera.target.z), 610, 75, 10, BLACK);
DrawText(TextFormat("- Up: (%06.3f, %06.3f, %06.3f)", camera.up.x, camera.up.y, camera.up.z), 610, 90, 10, BLACK);
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------

View File

@ -150,6 +150,9 @@ void SetCameraMoveControls(int keyFront, int keyBack,
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define CAMERA_MOVE_SPEED 0.09f
#define CAMERA_ROTATION_SPEED 0.03f
// Camera mouse movement sensitivity // Camera mouse movement sensitivity
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independant of framerate #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independant of framerate
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
@ -213,6 +216,7 @@ typedef enum {
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Rotates the given vector around the given axis // Rotates the given vector around the given axis
// Note: angle must be provided in radians // Note: angle must be provided in radians
Vector3 Vector3RotateAxis(Vector3 v, Vector3 axis, float angle) { // TODO there is a better way without the intermediate matrix Vector3 Vector3RotateAxis(Vector3 v, Vector3 axis, float angle) { // TODO there is a better way without the intermediate matrix
@ -225,43 +229,43 @@ Vector3 Vector3RotateAxis(Vector3 v, Vector3 axis, float angle) { // TODO there
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// TODO declare all functions in raylib.h and standalone "header" // TODO declare all functions in raylib.h and standalone "header"
void CameraPitch(Camera3D* camera, float angle); void CameraPitch(Camera3D *camera, float angle);
void CameraYaw(Camera3D* camera, float angle); void CameraYaw(Camera3D *camera, float angle);
void CameraRoll(Camera3D* camera, float angle); void CameraRoll(Camera3D *camera, float angle);
// Select camera mode (multiple camera modes available) // Select camera mode (multiple camera modes available)
void SetCameraMode(Camera3D* camera, int mode) void SetCameraMode(Camera3D *camera, int mode)
{ {
camera->mode = mode; camera->mode = mode;
// TODO // Reset roll
camera->up = (Vector3){ 0.0f, 1.0f, 0.0f };
// TODO Reset roll and fix overrotation (i.e. somersaults)
} }
// Returns the cameras current forward vector (normalized) // Returns the cameras forward vector (normalized)
Vector3 GetCameraForward(Camera3D* camera) { Vector3 GetCameraForward(Camera3D *camera)
{
return Vector3Normalize(Vector3Subtract(camera->target, camera->position)); return Vector3Normalize(Vector3Subtract(camera->target, camera->position));
} }
// Returns the cameras current up vector (normalized) // Returns the cameras up vector (normalized)
Vector3 GetCameraUp(Camera3D* camera) { // Note: The up vector might not be perpendicular to the forward vector
// Note: The up vector might not be perpendicular to the forward vector Vector3 GetCameraUp(Camera3D *camera)
Vector3 forward = Vector3Subtract(camera->target, camera->position); {
Vector3OrthoNormalize(&forward, &camera->up); return Vector3Normalize(camera->up);
return camera->up;
} }
// Returns the cameras current right vector (normalized) // Returns the cameras right vector (normalized)
Vector3 GetCameraRight(Camera3D* camera) { Vector3 GetCameraRight(Camera3D *camera)
{
Vector3 forward = GetCameraForward(camera); Vector3 forward = GetCameraForward(camera);
Vector3 up = GetCameraUp(camera); Vector3 up = GetCameraUp(camera);
return Vector3CrossProduct(forward, up); return Vector3CrossProduct(forward, up);
} }
// Moves the camera in its current forward vector direction // Moves the camera in its forward direction
void CameraMoveForward(Camera3D *camera, float distance) { void CameraMoveForward(Camera3D *camera, float distance)
{
Vector3 forward = GetCameraForward(camera); Vector3 forward = GetCameraForward(camera);
if (camera->mode == CAMERA_FIRST_PERSON || if (camera->mode == CAMERA_FIRST_PERSON ||
@ -272,24 +276,30 @@ void CameraMoveForward(Camera3D *camera, float distance) {
forward = Vector3Normalize(forward); forward = Vector3Normalize(forward);
} }
// Scale by distance
forward = Vector3Scale(forward, distance); forward = Vector3Scale(forward, distance);
// Move position and target
camera->position = Vector3Add(camera->position, forward); camera->position = Vector3Add(camera->position, forward);
camera->target = Vector3Add(camera->target, forward); camera->target = Vector3Add(camera->target, forward);
} }
// Moves the camera in its current up vector direction // Moves the camera in its up direction
void CameraMoveUp(Camera3D *camera, float distance) { void CameraMoveUp(Camera3D *camera, float distance)
{
Vector3 up = GetCameraUp(camera); Vector3 up = GetCameraUp(camera);
// Scale by distance
up = Vector3Scale(up, distance); up = Vector3Scale(up, distance);
// Move position and target
camera->position = Vector3Add(camera->position, up); camera->position = Vector3Add(camera->position, up);
camera->target = Vector3Add(camera->target, up); camera->target = Vector3Add(camera->target, up);
} }
// Moves the camera target in its current right vector direction // Moves the camera target in its current right direction
void CameraMoveRight(Camera3D *camera, float distance) { void CameraMoveRight(Camera3D *camera, float distance)
{
Vector3 right = GetCameraRight(camera); Vector3 right = GetCameraRight(camera);
if (camera->mode == CAMERA_FIRST_PERSON || if (camera->mode == CAMERA_FIRST_PERSON ||
@ -300,30 +310,68 @@ void CameraMoveRight(Camera3D *camera, float distance) {
right = Vector3Normalize(right); right = Vector3Normalize(right);
} }
// Scale by distance
right = Vector3Scale(right, distance); right = Vector3Scale(right, distance);
// Move position and target
camera->position = Vector3Add(camera->position, right); camera->position = Vector3Add(camera->position, right);
camera->target = Vector3Add(camera->target, right); camera->target = Vector3Add(camera->target, right);
} }
// Rotates the camera around its current up vector // Moves the camera position closer/farther to/from the camera target
void CameraZoom(Camera3D *camera, float delta)
{
float distance = Vector3Distance(camera->position, camera->target);
// Apply delta
distance += delta;
// Distance must be greater than 0
if (distance < 0) distance = 0.001f;
// Set new distance by moving the position along the forward vector
Vector3 forward = GetCameraForward(camera);
camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance));
}
// Rotates the camera around its up vector
// Yaw is "looking left and right" // Yaw is "looking left and right"
// Note: angle must be provided in radians // Note: angle must be provided in radians
void CameraYaw(Camera3D *camera, float angle) { void CameraYaw(Camera3D *camera, float angle)
{
// Rotation axis // Rotation axis
Vector3 up = GetCameraUp(camera); Vector3 up = GetCameraUp(camera);
// View vector
Vector3 target_position = Vector3Subtract(camera->target, camera->position); Vector3 target_position = Vector3Subtract(camera->target, camera->position);
// Rotate target // Rotate view vector around up axis
target_position = Vector3RotateAxis(target_position, up, angle); target_position = Vector3RotateAxis(target_position, up, angle);
camera->target = Vector3Add(camera->position, target_position);
if (camera->mode == CAMERA_FREE ||
camera->mode == CAMERA_FIRST_PERSON)
{
// Move target relative to position
camera->target = Vector3Add(camera->position, target_position);
}
else if (camera->mode == CAMERA_THIRD_PERSON ||
camera->mode == CAMERA_ORBITAL)
{
// Move position relative to target
camera->position = Vector3Subtract(camera->target, target_position);
}
} }
// Rotates the camera around its current right vector // Rotates the camera around its right vector
// Pitch is "looking up and down" // Pitch is "looking up and down"
// Note: angle must be provided in radians // Note: angle must be provided in radians
void CameraPitch(Camera3D *camera, float angle) { void CameraPitch(Camera3D *camera, float angle)
{
// Up direction
Vector3 up = GetCameraUp(camera);
// View vector
Vector3 target_position = Vector3Subtract(camera->target, camera->position);
if (camera->mode == CAMERA_FIRST_PERSON || if (camera->mode == CAMERA_FIRST_PERSON ||
camera->mode == CAMERA_THIRD_PERSON || camera->mode == CAMERA_THIRD_PERSON ||
@ -331,44 +379,67 @@ void CameraPitch(Camera3D *camera, float angle) {
{ {
// In these camera modes we clamp the Pitch angle // In these camera modes we clamp the Pitch angle
// to allow only viewing straight up or down. // to allow only viewing straight up or down.
// i.e. prevent somersaults
// TODO // Clamp view up
float max_angle_up = Vector3Angle(up, target_position);
max_angle_up -= 0.001f; // avoid numerical errors
if (angle > max_angle_up) angle = max_angle_up;
// Clamp view down
float max_angle_down = Vector3Angle(Vector3Negate(up), target_position);
max_angle_down *= -1.0f; // downwards angle is negative
max_angle_down += 0.001f; // avoid numerical errors
if (angle < max_angle_down) angle = max_angle_down;
} }
// Rotation axis // Rotation axis
Vector3 right = GetCameraRight(camera); Vector3 right = GetCameraRight(camera);
Vector3 target_position = Vector3Subtract(camera->target, camera->position); // Rotate view vector around right axis
// Rotate target
target_position = Vector3RotateAxis(target_position, right, angle); target_position = Vector3RotateAxis(target_position, right, angle);
camera->target = Vector3Add(camera->position, target_position);
// Rotate up direction if (camera->mode == CAMERA_FREE)
camera->up = Vector3RotateAxis(camera->up, right, angle); {
// Move target relative to position
camera->target = Vector3Add(camera->position, target_position);
// Rotate up direction around right axis
camera->up = Vector3RotateAxis(camera->up, right, angle);
}
else if (camera->mode == CAMERA_FIRST_PERSON)
{
// Move target relative to position
camera->target = Vector3Add(camera->position, target_position);
}
else if (camera->mode == CAMERA_THIRD_PERSON ||
camera->mode == CAMERA_ORBITAL)
{
// Move position relative to target
camera->position = Vector3Subtract(camera->target, target_position);
}
} }
// Rotates the camera around its current forward vector // Rotates the camera around its forward vector
// Roll is "turning your head sideways to the left or right" // Roll is "turning your head sideways to the left or right"
// Note: angle must be provided in radians // Note: angle must be provided in radians
void CameraRoll(Camera3D *camera, float angle) { void CameraRoll(Camera3D *camera, float angle)
{
// Rotation axis // Rotation axis
Vector3 forward = GetCameraForward(camera); Vector3 forward = GetCameraForward(camera);
// Rotate up direction // Rotate up direction around forward axis
camera->up = Vector3RotateAxis(camera->up, forward, angle); camera->up = Vector3RotateAxis(camera->up, forward, angle);
} }
// Returns the current camera view matrix // Returns the camera view matrix
Matrix GetCameraViewMatrix(Camera3D* camera) { Matrix GetCameraViewMatrix(Camera3D *camera)
// Note: MatrixLookAt normalizes up internally {
// TODO review up needs to be perpendicular?
return MatrixLookAt(camera->position, camera->target, camera->up); return MatrixLookAt(camera->position, camera->target, camera->up);
} }
// Returns the current camera projection matrix // Returns the camera projection matrix
Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect) { Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect)
{
if (camera->projection == CAMERA_PERSPECTIVE) if (camera->projection == CAMERA_PERSPECTIVE)
{ {
return MatrixPerspective(camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); return MatrixPerspective(camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
@ -383,48 +454,40 @@ Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect) {
return MatrixIdentity(); return MatrixIdentity();
} }
static bool on_init = true; static int init_frames = 3;
void UpdateCamera(Camera3D* camera) { void UpdateCamera(Camera3D *camera)
{
// TODO review
const float CAMERA_MOVE_SPEED = 0.03f;
// TODO Input detection is raylib-dependant
// Avoid inital mouse "jump" // Avoid inital mouse "jump"
if (on_init) { if (init_frames > 0) {
SetMousePosition(0, 0); SetMousePosition(0, 0);
on_init = false; init_frames--;
return;
} }
Vector2 mousePositionDelta = GetMouseDelta(); Vector2 mousePositionDelta = GetMouseDelta();
// Camera movement // Camera movement
if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED * 3); if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED * 3); if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED * 3); if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED * 3); if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED * 3); if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED * 3); if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED);
// Camera rotation // Camera rotation
if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_MOVE_SPEED); if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_MOVE_SPEED); if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_MOVE_SPEED); if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_MOVE_SPEED); if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_MOVE_SPEED); if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_MOVE_SPEED); if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
CameraYaw(camera, mousePositionDelta.x * -CAMERA_MOUSE_MOVE_SENSITIVITY); CameraYaw(camera, mousePositionDelta.x * -CAMERA_MOUSE_MOVE_SENSITIVITY);
CameraPitch(camera, mousePositionDelta.y * -CAMERA_MOUSE_MOVE_SENSITIVITY); CameraPitch(camera, mousePositionDelta.y * -CAMERA_MOUSE_MOVE_SENSITIVITY);
#if 0 // Zoom target distance
CameraZoom(camera, -GetMouseWheelMove());
// Adjust camera target_distance if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraZoom(camera, 2.0f);
camera->target_distance -= GetMouseWheelMove(); if (IsKeyPressed(KEY_KP_ADD)) CameraZoom(camera, -2.0f);
if (IsKeyPressed(KEY_KP_SUBTRACT)) camera->target_distance -= 1.0f;
if (IsKeyPressed(KEY_KP_ADD)) camera->target_distance += 1.0f;
// Switch camera mode // Switch camera mode
if (IsKeyPressed(KEY_ONE)) SetCameraMode(camera, CAMERA_FREE); if (IsKeyPressed(KEY_ONE)) SetCameraMode(camera, CAMERA_FREE);
@ -436,24 +499,32 @@ void UpdateCamera(Camera3D* camera) {
if (IsKeyPressed(KEY_P)) { if (IsKeyPressed(KEY_P)) {
if (camera->projection == CAMERA_PERSPECTIVE) { if (camera->projection == CAMERA_PERSPECTIVE) {
// Create isometric view // Create isometric view
InitializeCamera(camera, camera->aspect);
camera->mode = CAMERA_THIRD_PERSON; camera->mode = CAMERA_THIRD_PERSON;
// Note: The target distance is related to the render distance in the orthographic projection
camera->position = (Vector3){ 0.0f, 2.0f, -100.0f };
camera->target = (Vector3){ 0.0f, 2.0f, 0.0f };
camera->up = (Vector3){ 0.0f, 1.0f, 0.0f };
camera->projection = CAMERA_ORTHOGRAPHIC; camera->projection = CAMERA_ORTHOGRAPHIC;
camera->fovy = 20.0f; // near plane width in orthografic camera->fovy = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
camera->target_distance = 100.0f; // influences only clip distance
CameraYaw(camera, -135 * DEG2RAD); CameraYaw(camera, -135 * DEG2RAD);
CameraPitch(camera, 45 * DEG2RAD); CameraPitch(camera, -45 * DEG2RAD);
} }
else if (camera->projection == CAMERA_ORTHOGRAPHIC) { else if (camera->projection == CAMERA_ORTHOGRAPHIC)
// Reset default view {
InitializeCamera(camera, camera->aspect); // Reset to default view
camera->mode = CAMERA_THIRD_PERSON;
// Note: The target distance is related to the render distance in the orthographic projection
camera->position = (Vector3){ 0.0f, 2.0f, 10.0f };
camera->target = (Vector3){ 0.0f, 2.0f, 0.0f };
camera->up = (Vector3){ 0.0f, 1.0f, 0.0f };
camera->projection = CAMERA_PERSPECTIVE;
camera->fovy = 60.0f;
} }
} }
#endif
} }
// TODO can we provide compatibility with the old rcamera usage? // TODO how can we provide compatibility with the old rcamera usage?
#if 0 #if 0
// Set camera pan key to combine with mouse movement (free camera) // Set camera pan key to combine with mouse movement (free camera)