diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c index 4f5652351..80b93c61e 100644 --- a/examples/core/core_3d_camera_first_person.c +++ b/examples/core/core_3d_camera_first_person.c @@ -10,6 +10,7 @@ ********************************************************************************************/ #include "raylib.h" +#include "raymath.h" #define MAX_COLUMNS 20 @@ -25,13 +26,14 @@ int main(void) InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person"); - // Define the camera to look into our 3d world (position, target, up vector) - Camera camera = { 0 }; - camera.position = (Vector3){ 4.0f, 2.0f, 4.0f }; - camera.target = (Vector3){ 0.0f, 1.8f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; - camera.fovy = 60.0f; - camera.projection = CAMERA_PERSPECTIVE; + // Define the camera to look into our 3d world + Camera3D camera = {0}; + InitializeCamera(&camera, (double)screenWidth / (double)screenHeight); + camera.target_position = (Vector3){ 0.0f, 2.0f, 0.0f }; // This is the eye position in FREE (and FIRST_PERSON) mode + //SetCameraMode(camera, CAMERA_THIRD_PERSON); // Set a different camera mode + + // Catch curser + DisableCursor(); // Generates some random columns float heights[MAX_COLUMNS] = { 0 }; @@ -41,12 +43,10 @@ int main(void) for (int i = 0; i < MAX_COLUMNS; i++) { heights[i] = (float)GetRandomValue(1, 12); - positions[i] = (Vector3){ (float)GetRandomValue(-15, 15), heights[i]/2.0f, (float)GetRandomValue(-15, 15) }; + positions[i] = (Vector3){ (float)GetRandomValue(-15, 15), heights[i] / 2.0f, (float)GetRandomValue(-15, 15) }; colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 }; } - SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set a first person camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -62,30 +62,53 @@ int main(void) //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); + ClearBackground(RAYWHITE); - BeginMode3D(camera); + BeginMode3D(camera); - DrawPlane((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector2){ 32.0f, 32.0f }, LIGHTGRAY); // Draw ground - DrawCube((Vector3){ -16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, BLUE); // Draw a blue wall - DrawCube((Vector3){ 16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, LIME); // Draw a green wall - DrawCube((Vector3){ 0.0f, 2.5f, 16.0f }, 32.0f, 5.0f, 1.0f, GOLD); // Draw a yellow wall + // Draw player + if (camera.target_distance > 1.0f) { + DrawCube(camera.target_position, 0.5f, 0.5f, 0.5f, DARKGREEN); + DrawCubeWires(camera.target_position, 0.5f, 0.5f, 0.5f, LIME); + } - // Draw some cubes around - for (int i = 0; i < MAX_COLUMNS; i++) - { - DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]); - DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, MAROON); - } + DrawPlane((Vector3) { 0.0f, 0.0f, 0.0f }, (Vector2) { 32.0f, 32.0f }, LIGHTGRAY); // Draw ground + DrawCube((Vector3) { -16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, BLUE); // Draw a blue wall + DrawCube((Vector3) { 16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, LIME); // Draw a green wall + DrawCube((Vector3) { 0.0f, 2.5f, 16.0f }, 32.0f, 5.0f, 1.0f, GOLD); // Draw a yellow wall - EndMode3D(); + // Draw some columns + for (int i = 0; i < MAX_COLUMNS; i++) + { + DrawCube(positions[i], 2.0f, heights[i], 2.0f, colors[i]); + DrawCubeWires(positions[i], 2.0f, heights[i], 2.0f, MAROON); + } - DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f)); - DrawRectangleLines( 10, 10, 220, 70, BLUE); + EndMode3D(); - DrawText("First person camera default controls:", 20, 20, 10, BLACK); - DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY); - DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY); + // Draw info boxes + DrawRectangle(5, 5, 330, 100, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 330, 100, BLUE); + + DrawText("Camera controls:", 15, 15, 10, BLACK); + DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK); + DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK); + DrawText("- Camera mode keys: 1, 2, 3, 4", 15, 60, 10, BLACK); + DrawText("- Target distance keys: num-plus, num-minus or mouse scroll", 15, 75, 10, BLACK); + DrawText("- Camera projection key: P", 15, 90, 10, BLACK); + + DrawRectangle(565, 5, 230, 100, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(565, 5, 230, 100, BLUE); + + DrawText("Camera status:", 575, 20, 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"), 575, 35, 10, BLACK); + DrawText(TextFormat("- Projection: %s", (camera.projection == CAMERA_PERSPECTIVE) ? "PERSPECTIVE" : + (camera.projection == CAMERA_ORTHOGRAPHIC) ? "ORTHOGRAPHIC" : "CUSTOM"), 575, 50, 10, BLACK); + DrawText(TextFormat("- Target position: (%06.3f, %06.3f, %06.3f)", camera.target_position.x, camera.target_position.y, camera.target_position.z), 575, 65, 10, BLACK); + DrawText(TextFormat("- Target distance: %06.3f", camera.target_distance), 575, 80, 10, BLACK); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index e57c71bcd..19d04bf26 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -297,11 +297,13 @@ typedef struct Font { // Camera, defines position/orientation in 3d space typedef struct Camera3D { - Vector3 position; // Camera position - Vector3 target; // Camera target it looks-at - Vector3 up; // Camera up vector (rotation over its axis) - float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + int mode; + Vector3 target_position; // Camera target it looks at + float target_distance; // Camera eye distance to target_position (set to 0 in free/fps mode) + Quaternion orientation; // Camera orientation (its rotation in 3D) + float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic + float aspect; // Camera aspect ratio (typically window_width / window_height) + int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } Camera3D; typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D @@ -1150,8 +1152,10 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pinch ang //------------------------------------------------------------------------------------ // Camera System Functions (Module: rcamera) //------------------------------------------------------------------------------------ +RLAPI void InitializeCamera(Camera3D* camera, float aspect); RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode +RLAPI Vector3 GetCameraFront(Camera* camera); RLAPI void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) diff --git a/src/rcamera.h b/src/rcamera.h index 08c376690..a48e66753 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -2,9 +2,9 @@ * * rcamera - Basic camera system for multiple camera modes * -* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) +* NOTE: Memory footprint of this library is aproximately ??? TODO bytes (global variables) * -* CONFIGURATION: +* CONFIGURATION: TODO * * #define CAMERA_IMPLEMENTATION * Generates the implementation of the library into the included file. @@ -17,6 +17,7 @@ * * CONTRIBUTORS: * Ramon Santamaria: Supervision, review, update and maintenance +* Christoph Wagner: Quaternion-based redesign (2022) * Marc Palau: Initial implementation (2014) * * @@ -44,15 +45,31 @@ #ifndef RCAMERA_H #define RCAMERA_H +// The only dependency // TODO review standalone mode +#include "raymath.h" + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -//... +// NOTE: Raylib (and OpenGL) uses a right-handed coordinate system +// Just invert CAMERA_WORLD_FRONT for a left-handed coordinate system +#define CAMERA_WORLD_FRONT (Vector3) { 0.0f, 0.0f, -1.0f } +#define CAMERA_WORLD_UP (Vector3) { 0.0f, 1.0f, 0.0f } +#define CAMERA_WORLD_RIGHT (Vector3) { 1.0f, 0.0f, 0.0f } + +#if defined(CAMERA_STANDALONE) +#define CAMERA_CULL_DISTANCE_NEAR 0.01 +#define CAMERA_CULL_DISTANCE_FAR 1000.0 +#else +#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR +#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition // NOTE: Below types are required for CAMERA_STANDALONE usage //---------------------------------------------------------------------------------- +// TODO review #if defined(CAMERA_STANDALONE) // Vector2 type typedef struct Vector2 { @@ -103,6 +120,8 @@ // Module Functions Declaration //---------------------------------------------------------------------------------- +// TODO review + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -134,54 +153,24 @@ void SetCameraMoveControls(int keyFront, int keyBack, #if defined(CAMERA_IMPLEMENTATION) -#include // Required for: sinf(), cosf(), sqrtf() - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#ifndef PI - #define PI 3.14159265358979323846 -#endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif +// TODO review all defines + +#define CAMERA_MOVE_SPEED 0.03f // Camera mouse movement sensitivity #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f -// FREE_CAMERA -#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f -#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f -#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f -#define CAMERA_FREE_MIN_CLAMP 85.0f -#define CAMERA_FREE_MAX_CLAMP -85.0f -#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f -#define CAMERA_FREE_PANNING_DIVIDER 5.1f - -// ORBITAL_CAMERA #define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame -// FIRST_PERSON -//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f -#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f -#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f #define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f #define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f #define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f -// THIRD_PERSON -//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f -#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f -#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f -#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } - // PLAYER (used by camera) #define PLAYER_MOVEMENT_SENSITIVITY 20.0f @@ -198,352 +187,301 @@ typedef enum { MOVE_DOWN } CameraMove; -// Camera global state context data [56 bytes] -typedef struct { - unsigned int mode; // Current camera mode - float targetDistance; // Camera distance from position to target - float playerEyesPosition; // Player eyes position from ground (in meters) - Vector2 angle; // Camera angle in plane XZ - Vector2 previousMousePosition; // Previous mouse position - - // Camera movement control keys - int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) - int smoothZoomControl; // Smooth zoom control key - int altControl; // Alternative control key - int panControl; // Pan view control key -} CameraData; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static CameraData CAMERA = { // Global CAMERA state context - .mode = 0, - .targetDistance = 0, - .playerEyesPosition = 1.85f, - .angle = { 0 }, - .previousMousePosition = { 0 }, - .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, - .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL - .altControl = 342, // raylib: KEY_LEFT_ALT - .panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE -}; + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) -// NOTE: Camera controls depend on some raylib input functions -static void EnableCursor() {} // Unlock cursor -static void DisableCursor() {} // Lock cursor -static int IsKeyDown(int key) { return 0; } - -static int IsMouseButtonDown(int button) { return 0;} -static float GetMouseWheelMove() { return 0.0f; } -static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } -#endif //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- +// TODO declare all functions in raylib.h and standalone "header" +void CameraPitch(Camera3D* camera, float angle); +void CameraYaw(Camera3D* camera, float angle); +void CameraRoll(Camera3D* camera, float angle); + + +// Initializes a camera with default values (Can be used to reset a camera) +void InitializeCamera(Camera3D* camera, float aspect) { + camera->mode = CAMERA_FIRST_PERSON; + camera->target_position = (Vector3){ 0.0f, 2.0f, 0.0f }; + camera->target_distance = 0.0f; + camera->orientation = QuaternionIdentity(); + camera->fovy = 60.0f; + camera->aspect = aspect; + camera->projection = CAMERA_PERSPECTIVE; +} + // Select camera mode (multiple camera modes available) -void SetCameraMode(Camera camera, int mode) +void SetCameraMode(Camera3D* camera, int mode) { - Vector3 v1 = camera.position; - Vector3 v2 = camera.target; + camera->mode = mode; - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - - CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target - - // Camera angle calculation - CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) - CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) - - CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position - - CAMERA.previousMousePosition = GetMousePosition(); // Init mouse position - - // Lock cursor for first person and third person cameras - if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); - else EnableCursor(); - - CAMERA.mode = mode; -} - -// Update camera depending on selected mode -// NOTE: Camera controls depend on some raylib functions: -// System: EnableCursor(), DisableCursor() -// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove() -// Keys: IsKeyDown() -void UpdateCamera(Camera *camera) -{ - static int swingCounter = 0; // Used for 1st person swinging movement - - // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) - - // Mouse movement detection - Vector2 mousePositionDelta = { 0.0f, 0.0f }; - Vector2 mousePosition = GetMousePosition(); - float mouseWheelMove = GetMouseWheelMove(); - - // Keys input detection - // TODO: Input detection is raylib-dependant, it could be moved outside the module - bool keyPan = IsMouseButtonDown(CAMERA.panControl); - bool keyAlt = IsKeyDown(CAMERA.altControl); - bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); - bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]), - IsKeyDown(CAMERA.moveControl[MOVE_BACK]), - IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]), - IsKeyDown(CAMERA.moveControl[MOVE_LEFT]), - IsKeyDown(CAMERA.moveControl[MOVE_UP]), - IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; - - if (CAMERA.mode != CAMERA_CUSTOM) + if (mode == CAMERA_FREE) { - mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x; - mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y; - - CAMERA.previousMousePosition = mousePosition; + camera->target_distance = 0.0f; + return; + } + else if (mode == CAMERA_FIRST_PERSON) + { + camera->target_distance = 0.0f; + } + else if (mode == CAMERA_THIRD_PERSON) + { + camera->target_distance = 4.0f; + } + else if (mode == CAMERA_ORBITAL) + { + camera->target_distance = 20.0f; } - // Support for multiple automatic camera modes - // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually - switch (CAMERA.mode) + // Reset roll and fix overrotation (i.e. somersaults) + + Vector3 front = GetCameraFront(camera); + // Reduce numerical errors in the following trig functions + front = Vector3Normalize(front); + + float yaw = atan2f(front.x, CAMERA_WORLD_FRONT.z * front.z); + float pitch = -asinf(front.y); + + camera->orientation = QuaternionIdentity(); + CameraPitch(camera, pitch); + CameraYaw(camera, yaw); +} + +// Returns the cameras current front vector +Vector3 GetCameraFront(Camera3D* camera) { + return Vector3RotateByQuaternion(CAMERA_WORLD_FRONT, QuaternionInvert(camera->orientation)); +} + +// Returns the cameras current up vector +Vector3 GetCameraUp(Camera3D* camera) { + return Vector3RotateByQuaternion(CAMERA_WORLD_UP, QuaternionInvert(camera->orientation)); +} + +// Returns the cameras current right vector +Vector3 GetCameraRight(Camera3D* camera) { + return Vector3RotateByQuaternion(CAMERA_WORLD_RIGHT, QuaternionInvert(camera->orientation)); +} + +// Returns the cameras current eye position +// Note: This is equivalent to target_position if target_distance == 0 +// (i.e. in modes CAMERA_FREE and CAMERA_FIRST_PERSON) +Vector3 GetCameraEyePosition(Camera3D* camera) { + Vector3 back = Vector3Negate(GetCameraFront(camera)); + + Vector3 offset = Vector3Scale(back, camera->target_distance); + + return Vector3Add(camera->target_position, offset); +} + +// Moves the camera in its current front vector direction +void CameraMoveForward(Camera3D *camera, float distance) { + Vector3 front = GetCameraFront(camera); + + if (camera->mode == CAMERA_FIRST_PERSON || + camera->mode == CAMERA_THIRD_PERSON) { - case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme - { - // Camera zoom - if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; - } + // Project vector onto world plane + front.y = 0; + front = Vector3Normalize(front); + } - // Camera looking down - else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; + camera->target_position = Vector3Add(camera->target_position, Vector3Scale(front, distance)); +} - // if (camera->target.y < 0) camera->target.y = -0.001; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - // Camera looking up - else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; +// Moves the camera in its current up vector direction +void CameraMoveUp(Camera3D *camera, float distance) { + Vector3 up = { 0 }; + + if (camera->mode == CAMERA_FREE || + camera->mode == CAMERA_ORBITAL) + { + up = GetCameraUp(camera); + } + else if (camera->mode == CAMERA_FIRST_PERSON || + camera->mode == CAMERA_THIRD_PERSON) + { + up = CAMERA_WORLD_UP; + } - // if (camera->target.y > 0) camera->target.y = 0.001; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } + camera->target_position = Vector3Add(camera->target_position, Vector3Scale(up, distance)); +} - // Input keys checks - if (keyPan) - { - if (keyAlt) // Alternative key behaviour - { - if (szoomKey) - { - // Camera smooth zoom - CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); - } - else - { - // Camera rotation - CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; - CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; +// Moves the camera target in its current right vector direction +void CameraMoveRight(Camera3D *camera, float distance) { + Vector3 right = GetCameraRight(camera); - // Angle clamp - if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; - } - } - else - { - // Camera panning - camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - } - } + if (camera->mode == CAMERA_FIRST_PERSON || + camera->mode == CAMERA_THIRD_PERSON) + { + // Project vector onto world plane + right.y = 0; + right = Vector3Normalize(right); + } - // Update camera position with changes - camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y; - camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; + camera->target_position = Vector3Add(camera->target_position, Vector3Scale(right, distance)); +} - } break; - case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed - { - CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom +// Rotates the camera around its current up vector +// Yaw is "looking left and right" +// Note: angle must be provided in radians +void CameraYaw(Camera3D *camera, float angle) { + Quaternion rotationUp = QuaternionFromAxisAngle(CAMERA_WORLD_UP, angle); - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - // Update camera position with changes - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; - - // Calculate translation matrix - Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER), - 0.0f, 0.0f, 0.0f, 1.0f }; - - // Calculate rotation matrix - Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; - - float cosz = cosf(0.0f); - float sinz = sinf(0.0f); - float cosy = cosf(-(PI*2 - CAMERA.angle.x)); - float siny = sinf(-(PI*2 - CAMERA.angle.x)); - float cosx = cosf(-(PI*2 - CAMERA.angle.y)); - float sinx = sinf(-(PI*2 - CAMERA.angle.y)); - - matRotation.m0 = cosz*cosy; - matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx); - matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx); - matRotation.m1 = sinz*cosy; - matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx); - matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx); - matRotation.m2 = -siny; - matRotation.m6 = cosy*sinx; - matRotation.m10= cosy*cosx; - - // Multiply translation and rotation matrices - Matrix matTransform = { 0 }; - matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12; - matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13; - matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14; - matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15; - matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12; - matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13; - matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14; - matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15; - matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12; - matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13; - matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14; - matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15; - matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12; - matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13; - matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14; - matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15; - - camera->target.x = camera->position.x - matTransform.m12; - camera->target.y = camera->position.y - matTransform.m13; - camera->target.z = camera->position.z - matTransform.m14; - - // If movement detected (some key pressed), increase swinging - for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; } - - // Camera position update - // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' - camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; - - camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - - } break; - case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; - - // Camera zoom - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - - if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_CUSTOM: break; - default: break; + if (camera->mode == CAMERA_FIRST_PERSON|| + camera->mode == CAMERA_THIRD_PERSON || + camera->mode == CAMERA_ORBITAL) + { + // NOTE: The multiplication order is important, not to induce roll from pitch+yaw + camera->orientation = QuaternionMultiply(camera->orientation, rotationUp); + } + else if (camera->mode == CAMERA_FREE) + { + camera->orientation = QuaternionMultiply(rotationUp, camera->orientation); } } +// Rotates the camera around its current right vector +// Pitch is "looking up and down" +// Note: angle must be provided in radians +void CameraPitch(Camera3D *camera, float angle) { + + if (camera->mode == CAMERA_FIRST_PERSON || + camera->mode == CAMERA_THIRD_PERSON || + camera->mode == CAMERA_ORBITAL) + { + // In these camera modes we clamp the Pitch angle + // to allow only viewing straight up or down. + // i.e. prevent somersaults + Vector3 front = GetCameraFront(camera); + + // clamp angle upwards + float max_angle = Vector3Angle(CAMERA_WORLD_UP, front); + max_angle -= 0.00001f; // avoid numerical errors + angle = -1.0f * MIN(-angle, max_angle); + + // clamp angle downwards + max_angle = Vector3Angle(Vector3Negate(CAMERA_WORLD_UP), front); + //max_angle = PI - max_angle; // TODO + max_angle -= 0.00001f; // avoid numerical errors + angle = MIN(angle, max_angle); + } + + Quaternion rotationRight = QuaternionFromAxisAngle(CAMERA_WORLD_RIGHT, angle); + camera->orientation = QuaternionMultiply(rotationRight, camera->orientation); +} + +// Rotates the camera around its current front vector +// Roll is "turning your head sideways to the left or right" +// Note: angle must be provided in radians +void CameraRoll(Camera3D *camera, float angle) { + Quaternion rotationFront = QuaternionFromAxisAngle(CAMERA_WORLD_FRONT, angle); + camera->orientation = QuaternionMultiply(rotationFront, camera->orientation); +} + +// Returns the current camera view matrix +Matrix GetCameraViewMatrix(Camera3D* camera) { + // NOTE: The orientation quaternion de-normalizes over time + // So we re-normalize it once per frame when the view matrix is requested + camera->orientation = QuaternionNormalize(camera->orientation); + + Vector3 eye = GetCameraEyePosition(camera); + + Matrix translation = MatrixTranslate(-eye.x, -eye.y, -eye.z); + Matrix rotation = QuaternionToMatrix(camera->orientation); + + return MatrixMultiply(translation, rotation); +} + +// Returns the current camera projection matrix +Matrix GetCameraProjectionMatrix(Camera3D* camera) { + + if (camera->projection == CAMERA_PERSPECTIVE) + { + return MatrixPerspective(camera->fovy * DEG2RAD, camera->aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); + } + else if (camera->projection == CAMERA_ORTHOGRAPHIC) + { + double top = camera->fovy / 2.0; + double right = top * camera->aspect; + return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR); + } + + return MatrixIdentity(); +} + +static bool on_init = true; +void UpdateCamera(Camera3D* camera) { + + // TODO Input detection is raylib-dependant + + // Avoid inital mouse "jump" + if (on_init) { + SetMousePosition(0, 0); + on_init = false; + } + Vector2 mousePositionDelta = GetMouseDelta(); + + // Camera movement + if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED * 3); + if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED * 3); + if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED * 3); + if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED * 3); + if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED * 3); + if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED * 3); + + // Camera rotation + if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, CAMERA_MOVE_SPEED); + if (IsKeyDown(KEY_UP)) CameraPitch(camera, -CAMERA_MOVE_SPEED); + if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, CAMERA_MOVE_SPEED); + if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, -CAMERA_MOVE_SPEED); + if (IsKeyDown(KEY_Q)) CameraRoll(camera, CAMERA_MOVE_SPEED); + if (IsKeyDown(KEY_E)) CameraRoll(camera, -CAMERA_MOVE_SPEED); + + CameraYaw(camera, mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY); + CameraPitch(camera, mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY); + + // Adjust camera target_distance + camera->target_distance -= GetMouseWheelMove(); + if (IsKeyPressed(KEY_KP_SUBTRACT)) camera->target_distance -= 1.0f; + if (IsKeyPressed(KEY_KP_ADD)) camera->target_distance += 1.0f; + + // Switch camera mode + if (IsKeyPressed(KEY_ONE)) SetCameraMode(camera, CAMERA_FREE); + if (IsKeyPressed(KEY_TWO)) SetCameraMode(camera, CAMERA_FIRST_PERSON); + if (IsKeyPressed(KEY_THREE)) SetCameraMode(camera, CAMERA_THIRD_PERSON); + if (IsKeyPressed(KEY_FOUR)) SetCameraMode(camera, CAMERA_ORBITAL); + + // Switch camera projection + if (IsKeyPressed(KEY_P)) { + if (camera->projection == CAMERA_PERSPECTIVE) { + // Create isometric view + InitializeCamera(camera, camera->aspect); + camera->mode = CAMERA_THIRD_PERSON; + camera->projection = CAMERA_ORTHOGRAPHIC; + camera->fovy = 20.0f; // near plane width in orthografic + camera->target_distance = 100.0f; // influences only clip distance + CameraYaw(camera, -135 * DEG2RAD); + CameraPitch(camera, 45 * DEG2RAD); + } + else if (camera->projection == CAMERA_ORTHOGRAPHIC) { + // Reset default view + InitializeCamera(camera, camera->aspect); + } + } +} + +// TODO can we provide compatibility with the old rcamera usage? +#if 0 + // Set camera pan key to combine with mouse movement (free camera) void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; } @@ -563,5 +501,7 @@ void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, CAMERA.moveControl[MOVE_UP] = keyUp; CAMERA.moveControl[MOVE_DOWN] = keyDown; } +#endif + #endif // CAMERA_IMPLEMENTATION diff --git a/src/rcore.c b/src/rcore.c index fe7914828..e2ab0b06a 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2179,33 +2179,11 @@ void BeginMode3D(Camera3D camera) rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlLoadIdentity(); // Reset current matrix (projection) - - float aspect = (float)CORE.Window.currentFbo.width/(float)CORE.Window.currentFbo.height; - - // NOTE: zNear and zFar values are important when computing depth buffer values - if (camera.projection == CAMERA_PERSPECTIVE) - { - // Setup perspective projection - double top = RL_CULL_DISTANCE_NEAR*tan(camera.fovy*0.5*DEG2RAD); - double right = top*aspect; - - rlFrustum(-right, right, -top, top, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); - } - else if (camera.projection == CAMERA_ORTHOGRAPHIC) - { - // Setup orthographic projection - double top = camera.fovy/2.0; - double right = top*aspect; - - rlOrtho(-right, right, -top,top, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); - } + rlMultMatrixf(MatrixToFloat(GetCameraProjectionMatrix(&camera))); // Multiply projection matrix by projection matrix (camera) rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlLoadIdentity(); // Reset current matrix (modelview) - - // Setup Camera view - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - rlMultMatrixf(MatrixToFloat(matView)); // Multiply modelview matrix by view matrix (camera) + rlMultMatrixf(MatrixToFloat(GetCameraViewMatrix(&camera))); // Multiply modelview matrix by view matrix (camera) rlEnableDepthTest(); // Enable DEPTH_TEST for 3D } @@ -2558,25 +2536,9 @@ Ray GetMouseRay(Vector2 mouse, Camera camera) // Store values in a vector Vector3 deviceCoords = { x, y, z }; - // Calculate view matrix from camera look at - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - - Matrix matProj = MatrixIdentity(); - - if (camera.projection == CAMERA_PERSPECTIVE) - { - // Calculate projection matrix from perspective - matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); - } - else if (camera.projection == CAMERA_ORTHOGRAPHIC) - { - float aspect = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height; - double top = camera.fovy/2.0; - double right = top*aspect; - - // Calculate projection matrix from orthographic - matProj = MatrixOrtho(-right, right, -top, top, 0.01, 1000.0); - } + // Get camera matrices + Matrix matView = GetCameraViewMatrix(&camera); + Matrix matProj = GetCameraProjectionMatrix(&camera); // Unproject far/near points Vector3 nearPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); @@ -2590,7 +2552,7 @@ Ray GetMouseRay(Vector2 mouse, Camera camera) // Calculate normalized direction vector Vector3 direction = Vector3Normalize(Vector3Subtract(farPoint, nearPoint)); - if (camera.projection == CAMERA_PERSPECTIVE) ray.position = camera.position; + if (camera.projection == CAMERA_PERSPECTIVE) ray.position = GetCameraEyePosition(&camera); else if (camera.projection == CAMERA_ORTHOGRAPHIC) ray.position = cameraPlanePointerPos; // Apply calculated vectors to ray @@ -2602,7 +2564,7 @@ Ray GetMouseRay(Vector2 mouse, Camera camera) // Get transform matrix for camera Matrix GetCameraMatrix(Camera camera) { - return MatrixLookAt(camera.position, camera.target, camera.up); + return GetCameraViewMatrix(&camera); } // Get camera 2d transform matrix @@ -2662,8 +2624,8 @@ Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int heigh matProj = MatrixOrtho(-right, right, -top, top, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); } - // Calculate view matrix from camera look at (and transpose it) - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + // Get view matrix from camera + Matrix matView = GetCameraViewMatrix(&camera); // TODO: Why not use Vector3Transform(Vector3 v, Matrix mat)? diff --git a/src/rmodels.c b/src/rmodels.c index 96af9f83f..b30d8857c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3337,7 +3337,7 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector // NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width Vector2 sizeRatio = { size.x*(float)source.height/source.width, size.y }; - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + Matrix matView = GetCameraMatrix(camera); // TODO use GetCameraViewMatrix() Vector3 right = { matView.m0, matView.m4, matView.m8 }; //Vector3 up = { matView.m1, matView.m5, matView.m9 };