From 5ecee69088f1f3c90803a6924ba6df3cc43bfbd3 Mon Sep 17 00:00:00 2001 From: Max Danielsson Date: Sat, 24 Mar 2018 23:31:06 +0100 Subject: [PATCH 1/5] Add 3d orthographic projection mode --- src/core.c | 73 +++++++++++++++++++++++++++++++++++++++++++++------- src/raylib.h | 11 ++++++-- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/core.c b/src/core.c index 0532c3c4c..7f7c02c2d 100644 --- a/src/core.c +++ b/src/core.c @@ -919,13 +919,26 @@ void Begin3dMode(Camera camera) rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlLoadIdentity(); // Reset current matrix (PROJECTION) - // Setup perspective projection - float aspect = (float)screenWidth/(float)screenHeight; - double top = 0.01*tan(camera.fovy*0.5*DEG2RAD); - double right = top*aspect; + if(camera.type == CAMERA_PERSPECTIVE) + { + // Setup perspective projection + float aspect = (float)screenWidth/(float)screenHeight; + double top = 0.01*tan(camera.fovy*0.5*DEG2RAD); + double right = top*aspect; + + rlFrustum(-right, right, -top, top, 0.01, 1000.0); + } + else if(camera.type == CAMERA_ORTHOGRAPHIC) + { + // Setup orthographic projection + float aspect = (float)screenWidth/(float)screenHeight; + double top = camera.fovy/2.0; + double right = top*aspect; + + rlOrtho(-right,right,-top,top, 0.01, 1000.0); + } // NOTE: zNear and zFar values are important when computing depth buffer values - rlFrustum(-right, right, -top, top, 0.01, 1000.0); rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -1013,22 +1026,48 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) TraceLog(LOG_DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); - // Calculate projection matrix from perspective - Matrix matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); - // Calculate view matrix from camera look at Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + Matrix matProj; + + if(camera.type == CAMERA_PERSPECTIVE) + { + // Calculate projection matrix from perspective + matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); + } + else if(camera.type == CAMERA_ORTHOGRAPHIC) + { + float aspect = (float)screenWidth/(float)screenHeight; + 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); + } + // Unproject far/near points Vector3 nearPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); Vector3 farPoint = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); + // Unproject the mouse cursor in the near plane. + // We need this as the source position because orthographic projects, compared to perspect doesn't have a + // convergence point, meaning that the "eye" of the camera is more like a plane than a point. + Vector3 cameraPlanePointerPos = rlUnproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView); + // Calculate normalized direction vector Vector3 direction = Vector3Subtract(farPoint, nearPoint); direction = Vector3Normalize(direction); + if(camera.type == CAMERA_PERSPECTIVE) + { + ray.position = camera.position; + } + else if(camera.type == CAMERA_ORTHOGRAPHIC) + { + ray.position = cameraPlanePointerPos; + } + // Apply calculated vectors to ray - ray.position = camera.position; ray.direction = direction; return ray; @@ -1038,7 +1077,21 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) Vector2 GetWorldToScreen(Vector3 position, Camera camera) { // Calculate projection matrix (from perspective instead of frustum - Matrix matProj = MatrixPerspective(camera.fovy*DEG2RAD, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0); + Matrix matProj; + + if(camera.type == CAMERA_PERSPECTIVE) + { + // Calculate projection matrix from perspective + matProj = MatrixPerspective(camera.fovy*DEG2RAD, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); + } + else if(camera.type == CAMERA_ORTHOGRAPHIC) + { + float aspect = (float)screenWidth/(float)screenHeight; + 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); + } // Calculate view matrix from camera look at (and transpose it) Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); diff --git a/src/raylib.h b/src/raylib.h index c94f44777..f40124e9b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -398,12 +398,19 @@ typedef struct SpriteFont { CharInfo *chars; // Characters info data } SpriteFont; +// Camera projection modes +typedef enum { + CAMERA_PERSPECTIVE = 0, + CAMERA_ORTHOGRAPHIC +} CameraType; + // Camera type, defines a camera position/orientation in 3d space typedef struct Camera { 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) + float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic + CameraType type; // Camera type, controlling projection type, either CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC. } Camera; // Camera2D type, defines a 2d camera @@ -726,7 +733,7 @@ RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes RLAPI void EndTextureMode(void); // Ends drawing to render texture // Screen-space-related functions -RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position +RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) From d91179f8ab50b608b2dfc04bccbddbd2cd9b68e5 Mon Sep 17 00:00:00 2001 From: Max Danielsson Date: Sun, 25 Mar 2018 18:49:15 +0200 Subject: [PATCH 2/5] Add orthographic projection example --- .../models/models_orthographic_projection.c | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 examples/models/models_orthographic_projection.c diff --git a/examples/models/models_orthographic_projection.c b/examples/models/models_orthographic_projection.c new file mode 100644 index 000000000..214fc969f --- /dev/null +++ b/examples/models/models_orthographic_projection.c @@ -0,0 +1,109 @@ +/******************************************************************************************* +* +* raylib [models] example - Show the difference between perspective and orthographic projection +* +* This program is heavily based on the geometric objects example +* +* This example has been created using raylib 1.0 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + bool view_ortho = true; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes"); + + // Define the camera to look into our 3d world + Camera camera; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + // + + // Input + //---------------------------------------------------------------------------------- + if(IsKeyPressed(KEY_SPACE)) + { + view_ortho = !view_ortho; + } + + + // Draw + //---------------------------------------------------------------------------------- + + if(view_ortho) + { + camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 10.0f, CAMERA_ORTHOGRAPHIC }; + } + else + { + camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, CAMERA_PERSPECTIVE }; + } + + BeginDrawing(); + + ClearBackground(RAYWHITE); + + Begin3dMode(camera); + + DrawCube((Vector3){-4.0f, 0.0f, 2.0f}, 2.0f, 5.0f, 2.0f, RED); + DrawCubeWires((Vector3){-4.0f, 0.0f, 2.0f}, 2.0f, 5.0f, 2.0f, GOLD); + DrawCubeWires((Vector3){-4.0f, 0.0f, -2.0f}, 3.0f, 6.0f, 2.0f, MAROON); + + DrawSphere((Vector3){-1.0f, 0.0f, -2.0f}, 1.0f, GREEN); + DrawSphereWires((Vector3){1.0f, 0.0f, 2.0f}, 2.0f, 16, 16, LIME); + + DrawCylinder((Vector3){4.0f, 0.0f, -2.0f}, 1.0f, 2.0f, 3.0f, 4, SKYBLUE); + DrawCylinderWires((Vector3){4.0f, 0.0f, -2.0f}, 1.0f, 2.0f, 3.0f, 4, DARKBLUE); + DrawCylinderWires((Vector3){4.5f, -1.0f, 2.0f}, 1.0f, 1.0f, 2.0f, 6, BROWN); + + DrawCylinder((Vector3){1.0f, 0.0f, -4.0f}, 0.0f, 1.5f, 3.0f, 8, GOLD); + DrawCylinderWires((Vector3){1.0f, 0.0f, -4.0f}, 0.0f, 1.5f, 3.0f, 8, PINK); + + DrawGrid(10, 1.0f); // Draw a grid + + End3dMode(); + + DrawFPS(10, 10); + + DrawText("Press Spacebar to switch camera type", 10, 40, 24, BLACK); + + if(view_ortho) + { + DrawText("Orthographic", 10, 65, 24, BLACK); + } + else + { + DrawText("Perspective", 10, 65, 24, BLACK); + } + + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} From e38d28543a6bcb451a3b1176a159d4fc0ff15326 Mon Sep 17 00:00:00 2001 From: Max Danielsson Date: Tue, 27 Mar 2018 19:58:42 +0200 Subject: [PATCH 3/5] Remove state bool in camera projection type example. Changes made based on commentary in pull request 513 --- .../models/models_orthographic_projection.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/models/models_orthographic_projection.c b/examples/models/models_orthographic_projection.c index 214fc969f..b28aa0aef 100644 --- a/examples/models/models_orthographic_projection.c +++ b/examples/models/models_orthographic_projection.c @@ -19,12 +19,13 @@ int main() //-------------------------------------------------------------------------------------- int screenWidth = 800; int screenHeight = 450; - bool view_ortho = true; InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes"); + const Camera perspective_camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, CAMERA_PERSPECTIVE }; + const Camera orthographic_camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 10.0f, CAMERA_ORTHOGRAPHIC }; // Define the camera to look into our 3d world - Camera camera; + Camera camera = perspective_camera; SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -42,21 +43,20 @@ int main() //---------------------------------------------------------------------------------- if(IsKeyPressed(KEY_SPACE)) { - view_ortho = !view_ortho; + if(camera.type == CAMERA_PERSPECTIVE) + { + camera = orthographic_camera; + } + else + { + camera = perspective_camera; + } } // Draw //---------------------------------------------------------------------------------- - if(view_ortho) - { - camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 10.0f, CAMERA_ORTHOGRAPHIC }; - } - else - { - camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, CAMERA_PERSPECTIVE }; - } BeginDrawing(); @@ -86,11 +86,11 @@ int main() DrawText("Press Spacebar to switch camera type", 10, 40, 24, BLACK); - if(view_ortho) + if(camera.type == CAMERA_ORTHOGRAPHIC) { DrawText("Orthographic", 10, 65, 24, BLACK); } - else + else if(camera.type == CAMERA_PERSPECTIVE) { DrawText("Perspective", 10, 65, 24, BLACK); } From 6c049fdd76296cb321761b6fa430c9addf58e02b Mon Sep 17 00:00:00 2001 From: Max Danielsson Date: Tue, 27 Mar 2018 19:59:54 +0200 Subject: [PATCH 4/5] Move deduplicate aspect variable in begin render. Changes motivated by commentary in pull request 513 --- src/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.c b/src/core.c index 7f7c02c2d..823181cf1 100644 --- a/src/core.c +++ b/src/core.c @@ -919,10 +919,11 @@ void Begin3dMode(Camera camera) rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlLoadIdentity(); // Reset current matrix (PROJECTION) + float aspect = (float)screenWidth/(float)screenHeight; + if(camera.type == CAMERA_PERSPECTIVE) { // Setup perspective projection - float aspect = (float)screenWidth/(float)screenHeight; double top = 0.01*tan(camera.fovy*0.5*DEG2RAD); double right = top*aspect; @@ -931,7 +932,6 @@ void Begin3dMode(Camera camera) else if(camera.type == CAMERA_ORTHOGRAPHIC) { // Setup orthographic projection - float aspect = (float)screenWidth/(float)screenHeight; double top = camera.fovy/2.0; double right = top*aspect; From 42e64e931b27a27795f471817dc93551f4f752e8 Mon Sep 17 00:00:00 2001 From: Max Danielsson Date: Tue, 27 Mar 2018 21:16:25 +0200 Subject: [PATCH 5/5] Simplify camera data switch in orthographic 3d example --- examples/models/models_orthographic_projection.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/models/models_orthographic_projection.c b/examples/models/models_orthographic_projection.c index b28aa0aef..2c2a89d10 100644 --- a/examples/models/models_orthographic_projection.c +++ b/examples/models/models_orthographic_projection.c @@ -13,6 +13,9 @@ #include "raylib.h" +#define FOVY_PERSPECTIVE 45.0f +#define WIDTH_ORTHOGRAPHIC 10.0f + int main() { // Initialization @@ -22,10 +25,8 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes"); - const Camera perspective_camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, CAMERA_PERSPECTIVE }; - const Camera orthographic_camera = (Camera){{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 10.0f, CAMERA_ORTHOGRAPHIC }; // Define the camera to look into our 3d world - Camera camera = perspective_camera; + Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, FOVY_PERSPECTIVE, CAMERA_PERSPECTIVE }; SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -45,11 +46,13 @@ int main() { if(camera.type == CAMERA_PERSPECTIVE) { - camera = orthographic_camera; + camera.fovy = WIDTH_ORTHOGRAPHIC; + camera.type = CAMERA_ORTHOGRAPHIC; } else { - camera = perspective_camera; + camera.fovy = FOVY_PERSPECTIVE; + camera.type = CAMERA_PERSPECTIVE; } }