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)
Camera camera = { 0 };
camera.position = (Vector3){ 4.0f, 2.0f, 4.0f };
camera.target = (Vector3){ 0.0f, 1.8f, 0.0f };
camera.position = (Vector3){ 0.0f, 2.0f, 4.0f };
camera.target = (Vector3){ 0.0f, 2.0f, 0.0f };
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
camera.fovy = 60.0f;
camera.projection = CAMERA_PERSPECTIVE;
// Set a first person camera mode
SetCameraMode(&camera, CAMERA_FIRST_PERSON);
// Generates some random columns
float heights[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 };
}
SetCameraMode(&camera, CAMERA_FIRST_PERSON); // Set a first person camera mode
// Catch cursor
DisableCursor();
@ -83,14 +84,39 @@ int main(void)
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();
DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f));
DrawRectangleLines( 10, 10, 220, 70, BLUE);
// Draw info boxes
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("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY);
DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY);
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("- 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();
//----------------------------------------------------------------------------------

View File

@ -150,6 +150,9 @@ void SetCameraMoveControls(int keyFront, int keyBack,
// Defines and Macros
//----------------------------------------------------------------------------------
#define CAMERA_MOVE_SPEED 0.09f
#define CAMERA_ROTATION_SPEED 0.03f
// Camera mouse movement sensitivity
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independant of framerate
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
@ -213,6 +216,7 @@ typedef enum {
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
// Rotates the given vector around the given axis
// 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
@ -234,34 +238,34 @@ void SetCameraMode(Camera3D* camera, int mode)
{
camera->mode = mode;
// TODO
// TODO Reset roll and fix overrotation (i.e. somersaults)
// Reset roll
camera->up = (Vector3){ 0.0f, 1.0f, 0.0f };
}
// Returns the cameras current forward vector (normalized)
Vector3 GetCameraForward(Camera3D* camera) {
// Returns the cameras forward vector (normalized)
Vector3 GetCameraForward(Camera3D *camera)
{
return Vector3Normalize(Vector3Subtract(camera->target, camera->position));
}
// Returns the cameras current up vector (normalized)
Vector3 GetCameraUp(Camera3D* camera) {
// Returns the cameras up vector (normalized)
// Note: The up vector might not be perpendicular to the forward vector
Vector3 forward = Vector3Subtract(camera->target, camera->position);
Vector3OrthoNormalize(&forward, &camera->up);
return camera->up;
Vector3 GetCameraUp(Camera3D *camera)
{
return Vector3Normalize(camera->up);
}
// Returns the cameras current right vector (normalized)
Vector3 GetCameraRight(Camera3D* camera) {
// Returns the cameras right vector (normalized)
Vector3 GetCameraRight(Camera3D *camera)
{
Vector3 forward = GetCameraForward(camera);
Vector3 up = GetCameraUp(camera);
return Vector3CrossProduct(forward, up);
}
// Moves the camera in its current forward vector direction
void CameraMoveForward(Camera3D *camera, float distance) {
// Moves the camera in its forward direction
void CameraMoveForward(Camera3D *camera, float distance)
{
Vector3 forward = GetCameraForward(camera);
if (camera->mode == CAMERA_FIRST_PERSON ||
@ -272,24 +276,30 @@ void CameraMoveForward(Camera3D *camera, float distance) {
forward = Vector3Normalize(forward);
}
// Scale by distance
forward = Vector3Scale(forward, distance);
// Move position and target
camera->position = Vector3Add(camera->position, forward);
camera->target = Vector3Add(camera->target, forward);
}
// Moves the camera in its current up vector direction
void CameraMoveUp(Camera3D *camera, float distance) {
// Moves the camera in its up direction
void CameraMoveUp(Camera3D *camera, float distance)
{
Vector3 up = GetCameraUp(camera);
// Scale by distance
up = Vector3Scale(up, distance);
// Move position and target
camera->position = Vector3Add(camera->position, up);
camera->target = Vector3Add(camera->target, up);
}
// Moves the camera target in its current right vector direction
void CameraMoveRight(Camera3D *camera, float distance) {
// Moves the camera target in its current right direction
void CameraMoveRight(Camera3D *camera, float distance)
{
Vector3 right = GetCameraRight(camera);
if (camera->mode == CAMERA_FIRST_PERSON ||
@ -300,30 +310,68 @@ void CameraMoveRight(Camera3D *camera, float distance) {
right = Vector3Normalize(right);
}
// Scale by distance
right = Vector3Scale(right, distance);
// Move position and target
camera->position = Vector3Add(camera->position, 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"
// Note: angle must be provided in radians
void CameraYaw(Camera3D *camera, float angle) {
void CameraYaw(Camera3D *camera, float angle)
{
// Rotation axis
Vector3 up = GetCameraUp(camera);
// View vector
Vector3 target_position = Vector3Subtract(camera->target, camera->position);
// Rotate target
// Rotate view vector around up axis
target_position = Vector3RotateAxis(target_position, up, angle);
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"
// 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 ||
camera->mode == CAMERA_THIRD_PERSON ||
@ -331,44 +379,67 @@ void CameraPitch(Camera3D *camera, float angle) {
{
// In these camera modes we clamp the Pitch angle
// 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
Vector3 right = GetCameraRight(camera);
Vector3 target_position = Vector3Subtract(camera->target, camera->position);
// Rotate target
// Rotate view vector around right axis
target_position = Vector3RotateAxis(target_position, right, angle);
if (camera->mode == CAMERA_FREE)
{
// Move target relative to position
camera->target = Vector3Add(camera->position, target_position);
// Rotate up direction
// 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"
// Note: angle must be provided in radians
void CameraRoll(Camera3D *camera, float angle) {
void CameraRoll(Camera3D *camera, float angle)
{
// Rotation axis
Vector3 forward = GetCameraForward(camera);
// Rotate up direction
// Rotate up direction around forward axis
camera->up = Vector3RotateAxis(camera->up, forward, angle);
}
// Returns the current camera view matrix
Matrix GetCameraViewMatrix(Camera3D* camera) {
// Note: MatrixLookAt normalizes up internally
// TODO review up needs to be perpendicular?
// Returns the camera view matrix
Matrix GetCameraViewMatrix(Camera3D *camera)
{
return MatrixLookAt(camera->position, camera->target, camera->up);
}
// Returns the current camera projection matrix
Matrix GetCameraProjectionMatrix(Camera3D* camera, float aspect) {
// Returns the camera projection matrix
Matrix GetCameraProjectionMatrix(Camera3D *camera, float aspect)
{
if (camera->projection == CAMERA_PERSPECTIVE)
{
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();
}
static bool on_init = true;
void UpdateCamera(Camera3D* camera) {
// TODO review
const float CAMERA_MOVE_SPEED = 0.03f;
// TODO Input detection is raylib-dependant
static int init_frames = 3;
void UpdateCamera(Camera3D *camera)
{
// Avoid inital mouse "jump"
if (on_init) {
if (init_frames > 0) {
SetMousePosition(0, 0);
on_init = false;
init_frames--;
return;
}
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);
if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED);
if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED);
// 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);
if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
CameraYaw(camera, mousePositionDelta.x * -CAMERA_MOUSE_MOVE_SENSITIVITY);
CameraPitch(camera, mousePositionDelta.y * -CAMERA_MOUSE_MOVE_SENSITIVITY);
#if 0
// 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;
// Zoom target distance
CameraZoom(camera, -GetMouseWheelMove());
if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraZoom(camera, 2.0f);
if (IsKeyPressed(KEY_KP_ADD)) CameraZoom(camera, -2.0f);
// Switch camera mode
if (IsKeyPressed(KEY_ONE)) SetCameraMode(camera, CAMERA_FREE);
@ -436,24 +499,32 @@ void UpdateCamera(Camera3D* camera) {
if (IsKeyPressed(KEY_P)) {
if (camera->projection == CAMERA_PERSPECTIVE) {
// Create isometric view
InitializeCamera(camera, camera->aspect);
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->fovy = 20.0f; // near plane width in orthografic
camera->target_distance = 100.0f; // influences only clip distance
camera->fovy = 20.0f; // near plane width in CAMERA_ORTHOGRAPHIC
CameraYaw(camera, -135 * DEG2RAD);
CameraPitch(camera, 45 * DEG2RAD);
CameraPitch(camera, -45 * DEG2RAD);
}
else if (camera->projection == CAMERA_ORTHOGRAPHIC) {
// Reset default view
InitializeCamera(camera, camera->aspect);
else if (camera->projection == CAMERA_ORTHOGRAPHIC)
{
// 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
// Set camera pan key to combine with mouse movement (free camera)