diff --git a/src/camera.cpp b/src/camera.cpp index 894b807f..d5d453c5 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -31,6 +31,14 @@ Camera::Camera() m_gamegroup = GAMEGROUP_BEFORE; m_drawgroup = DRAWGROUP_CAMERA; + ivec2 screen_size = Video::GetSize(); + m_fov = 45.f; + m_near = -1000.f; + m_far = 1000.f; + m_screen_size = (float)screen_size.x; + m_screen_ratio = (float)screen_size.x / (float)screen_size.y; + m_is_shifted = false; + /* Create a default perspective */ SetProjection(mat4::perspective(45.f, 800.f, 600.f, -1000.f, 1000.f)); SetView(mat4::lookat(vec3(0.f, 50.f, 50.f), @@ -42,6 +50,9 @@ Camera::~Camera() { } +//----------------------------------------------------------------------------- +//View functions +//-- void Camera::SetView(mat4 const &view) { m_view_matrix = view; @@ -52,6 +63,12 @@ void Camera::SetView(vec3 eye, vec3 target, vec3 up) { m_view_matrix = mat4::lookat(eye, target, up); m_position = eye; + m_target_distance = length(target - m_position); +} + +void Camera::SetView(vec3 pos, vec3 rot) +{ + SetView(pos, quat::fromeuler_xyz(rot)); } void Camera::SetView(vec3 pos, quat rot) @@ -60,16 +77,44 @@ void Camera::SetView(vec3 pos, quat rot) pos + rot.transform(vec3(0.f, 0.f, -1.f)), rot.transform(vec3(0.f, 1.f, 0.f))); m_position = pos; + m_target_distance = .0f; +} + +mat4 Camera::GetView() +{ + return m_view_matrix; } +//----------------------------------------------------------------------------- +//Projections functions +//-- void Camera::SetProjection(mat4 const &proj) { m_proj_matrix = proj; } -mat4 Camera::GetView() +void Camera::SetProjection(float fov, float near, float far) { - return m_view_matrix; + SetProjection(fov, near, far, m_screen_size, m_screen_ratio); +} + +void Camera::SetProjection(float fov, float near, float far, float screen_size, float screen_ratio) +{ + m_fov = fov; + m_near = near; + m_far = far; + m_screen_size = screen_size; + m_screen_ratio = screen_ratio; + + if (m_fov > .0f) + { + if (m_is_shifted) + SetProjection(mat4::shifted_perspective(m_fov, screen_size, screen_ratio, m_far - m_near)); + else + SetProjection(mat4::perspective(m_fov, screen_size, screen_size * screen_ratio, m_near, m_far)); + } + else + SetProjection(mat4::ortho(screen_size, screen_size * screen_ratio, m_near, m_far)); } mat4 Camera::GetProjection() @@ -77,11 +122,117 @@ mat4 Camera::GetProjection() return m_proj_matrix; } +//----------------------------------------------------------------------------- +//Projections manipulation functions +//-- +void Camera::SetFov(float fov) +{ + SetProjection(fov, m_near, m_far, m_screen_size, m_screen_ratio); +} + +void Camera::SetScreenInfos(float screen_size) +{ + SetScreenInfos(screen_size, m_screen_ratio); +} + +void Camera::SetScreenInfos(float screen_size, float screen_ratio) +{ + SetProjection(m_fov, m_near, m_far, screen_size, screen_ratio); +} + +void Camera::SetDrawInfos(float far) +{ + SetDrawInfos(m_near, far); +} + +void Camera::SetDrawInfos(float near, float far) +{ + SetProjection(m_fov, near, far, m_screen_size, m_screen_ratio); +} + +void Camera::UseShift(bool should_shift) +{ + m_is_shifted = should_shift; + SetProjection(m_fov, m_near, m_far, m_screen_size, m_screen_ratio); +} + + +//----------------------------------------------------------------------------- +//camera manipulation Functions +//-- +void Camera::SetPosition(vec3 pos) +{ + if (m_target_distance > .0f) + { + vec4 up = m_view_matrix * vec4(0.f, 1.f, 0.f, 0.f); + vec4 target = m_view_matrix * vec4(0.f, 0.f, -m_target_distance, 0.f); + SetView(m_position, m_position + target.xyz, up.xyz); + } + else + m_view_matrix = m_view_matrix * mat4::translate(pos - m_position); + m_position = pos; +} + +void Camera::SetTarget(vec3 target) +{ + vec4 up = inverse(m_view_matrix) * vec4(0.f, 1.f, 0.f, 0.f); + SetView(m_position, target, up.xyz); +} + +void Camera::SetUp(vec3 up) +{ + vec4 target = inverse(m_view_matrix) * vec4(0.f, 0.f, -max(m_target_distance, 1.f), 0.f); + SetView(m_position, m_position + target.xyz, up); +} + +void Camera::SetRotation(vec3 rot) +{ + SetRotation(quat::fromeuler_xyz(rot)); +} + +void Camera::SetRotation(quat rot) +{ + SetView(m_position, rot); +} + +//-- vec3 Camera::GetPosition() { return m_position; } +vec3 Camera::GetTarget() +{ + return m_position + (inverse(m_view_matrix) * vec4(0.f, 0.f, -max(m_target_distance, 1.f), 0.f)).xyz; +} + +vec3 Camera::GetUp() +{ + return (inverse(m_view_matrix) * vec4(0.f, 1.f, 0.f, 0.f)).xyz; +} + +vec3 Camera::GetRotationEuler() +{ + return vec3::toeuler(GetRotation()); +} + +quat Camera::GetRotation() +{ + return quat(inverse(m_view_matrix)); +} + +// Calculate the frustum height at a given distance from the camera. +float Camera::GetFrustumHeightAtDistance(float distance, float fov) +{ + return 2.f * distance * lol::tan(fov * .5f * (F_PI / 180.f)); +} + +// Calculate the FOV needed to get a given frustum height at a given distance. +float Camera::GetFOVForHeightAndDistance(float distance, float height) +{ + return 2.f * lol::atan(height * .5f / distance) * (180.f / F_PI); +} + void Camera::TickGame(float seconds) { WorldEntity::TickGame(seconds); diff --git a/src/camera.h b/src/camera.h index a2fe41ad..91a4ad24 100644 --- a/src/camera.h +++ b/src/camera.h @@ -29,26 +29,74 @@ public: char const *GetName() { return ""; } + //View functions void SetView(mat4 const &view); void SetView(vec3 eye, vec3 target, vec3 up); + void SetView(vec3 pos, vec3 rot); void SetView(vec3 pos, quat rot); + mat4 GetView(); + + //Projections functions +//private: void SetProjection(mat4 const &proj); +public: + void SetProjection(float fov, float near, float far); + void SetProjection(float fov, float near, float far, float screen_size, float screen_ratio); - mat4 GetView(); mat4 GetProjection(); + //Projections manipulation functions + void SetFov(float fov); + void SetScreenInfos(float screen_size); + void SetScreenInfos(float screen_size, float screen_ratio); + void SetDrawInfos(float far); + void SetDrawInfos(float near, float far); + void UseShift(bool should_shift); + + float GetFov() { return m_fov; } + float GetScreenSize() { return m_screen_size; } + float GetScreenRatio() { return m_screen_ratio; } + float GetNear() { return m_near; } + float GetFar() { return m_far; } + bool IsShifted() { return m_is_shifted; } + + //camera manipulation Functions + void SetPosition(vec3 pos); + void SetTarget(vec3 target); + void SetUp(vec3 up); + void SetRotation(vec3 rot); + void SetRotation(quat rot); + vec3 GetPosition(); + vec3 GetTarget(); + vec3 GetUp(); + vec3 GetRotationEuler(); + quat GetRotation(); + + //Convenience functions + float GetFrustumHeightAtDistance(float distance, float fov); + float GetFOVForHeightAndDistance(float distance, float height); protected: virtual void TickGame(float seconds); virtual void TickDraw(float seconds); private: - mat4 m_view_matrix, m_proj_matrix; + //Work datas + mat4 m_view_matrix; + mat4 m_proj_matrix; + + //Datas used to create above matrix + float m_target_distance; + float m_fov; + float m_screen_size; + float m_screen_ratio; + float m_near; + float m_far; + bool m_is_shifted; }; } /* namespace lol */ #endif /* __CAMERA_H__ */ - diff --git a/src/math/vector.cpp b/src/math/vector.cpp index 59c9de26..be9e90b2 100644 --- a/src/math/vector.cpp +++ b/src/math/vector.cpp @@ -768,6 +768,7 @@ template<> mat4 mat4::frustum(float left, float right, float bottom, return ret; } +//Returns a standard perspective matrix template<> mat4 mat4::perspective(float fov_y, float width, float height, float near, float far) { @@ -779,6 +780,7 @@ template<> mat4 mat4::perspective(float fov_y, float width, return frustum(-near * t1, near * t1, -near * t2, near * t2, near, far); } +//Returns a perspective matrix with the camera location shifted to be on the near plane template<> mat4 mat4::shifted_perspective(float fov_y, float screen_size, float screen_ratio_xy, float draw_distance) { @@ -787,7 +789,8 @@ template<> mat4 mat4::shifted_perspective(float fov_y, float screen_size, float near = (screen_size * .5f) / tanf(new_fov_y * .5f); float far = near + draw_distance; - return mat4::perspective(fov_y, screen_size * screen_ratio_xy, screen_size, near - .000001f, far) * mat4::translate(.0f, .0f, -near); + return mat4::perspective(fov_y, screen_size * screen_ratio_xy, screen_size, near - .000001f, far) * + mat4::translate(.0f, .0f, -near); } } /* namespace lol */ diff --git a/test/btphystest.cpp b/test/btphystest.cpp index 750d7907..9b621737 100644 --- a/test/btphystest.cpp +++ b/test/btphystest.cpp @@ -38,6 +38,7 @@ using namespace lol::phys; #define ZERO_SPEED 3.5f #define JUMP_HEIGHT 30.f #define JUMP_STRAFE .5f +#define TARGET_TIMER 10.f + (rand(4.f) - 2.f) int gNumObjects = 64; @@ -83,12 +84,14 @@ BtPhysTest::BtPhysTest(bool editor) m_camera->SetView(vec3(70.f, 50.f, 0.f), vec3(0.f, 0.f, 0.f), vec3(0, 1, 0)); - m_camera->SetProjection(mat4::perspective(60.f, (float)Video::GetSize().x, (float)Video::GetSize().y, .1f, 1000.f)); + m_camera->SetProjection(60.f, .1f, 1000.f, (float)Video::GetSize().x, (float)Video::GetSize().y / (float)Video::GetSize().x); + m_target_timer = TARGET_TIMER; + m_cam_target = -1; #else m_camera->SetView(vec3(50.f, 50.f, 0.f), vec3(0.f, 0.f, 0.f), vec3(0, 1, 0)); - m_camera->SetProjection(mat4::perspective(45.f, (float)Video::GetSize().x, (float)Video::GetSize().y, .1f, 1000.f)); + m_camera->SetProjection(45.f, .1f, 1000.f, (float)Video::GetSize().x, (float)Video::GetSize().y / (float)Video::GetSize().x); #endif g_scene->PushCamera(m_camera); @@ -304,10 +307,19 @@ void BtPhysTest::TickGame(float seconds) vec3 cam_center(0.f); float cam_factor = .0f; vec2 screen_min_max[2] = { vec2(FLT_MAX), vec2(-FLT_MAX) }; - vec3 cam_min_max[2] = { vec3(FLT_MAX), vec3(-FLT_MAX) }; mat4 world_cam = g_scene->GetCamera()->GetView(); mat4 cam_screen = g_scene->GetCamera()->GetProjection(); + m_target_timer -= seconds; + if (m_target_timer < .0f) + { + m_target_timer = TARGET_TIMER; + if (m_cam_target == -1) + m_cam_target = rand(m_physobj_list.Count()); + else + m_cam_target = -1; + } + for (int i = 0; i < m_physobj_list.Count(); i++) { PhysicsObject* PhysObj = m_physobj_list[i].m1; @@ -315,22 +327,33 @@ void BtPhysTest::TickGame(float seconds) vec3 obj_loc = PhysObj->GetPhysic()->GetTransform().v3.xyz; - cam_center += obj_loc; - cam_factor += 1.f; + if (m_cam_target == -1 || m_cam_target == i) + { + cam_center += obj_loc; + cam_factor += 1.f; - mat4 LocalPos = mat4::translate(obj_loc); - vec3 vpos; + mat4 LocalPos = mat4::translate(obj_loc); + vec3 vpos; - LocalPos = world_cam * LocalPos; - vpos = LocalPos.v3.xyz; - cam_min_max[0] = min(vpos.xyz, cam_min_max[0]); - cam_min_max[1] = max(vpos.xyz, cam_min_max[1]); + LocalPos = world_cam * LocalPos; + mat4 LocalPos0 = LocalPos; - LocalPos = cam_screen * LocalPos; - vpos = (LocalPos.v3 / LocalPos.v3.w).xyz; - screen_min_max[0] = min(vpos.xy, screen_min_max[0]); - screen_min_max[1] = max(vpos.xy, screen_min_max[1]); + int j = 2; + while (j-- > 0) + { + if (j == 1) + LocalPos = mat4::translate(vec3(-4.f)) * LocalPos0; + else + LocalPos = mat4::translate(vec3(4.f)) * LocalPos0; + + LocalPos = cam_screen * LocalPos; + vpos = (LocalPos.v3 / LocalPos.v3.w).xyz; + screen_min_max[0] = min(vpos.xy, screen_min_max[0]); + screen_min_max[1] = max(vpos.xy, screen_min_max[1]); + } + } + //Jump handling //if (length(PhysObj->GetPhysic()->GetLinearVelocity()) < ZERO_SPEED) if (lol::abs(PhysObj->GetPhysic()->GetLinearVelocity().y) < ZERO_SPEED) Timer -= seconds; @@ -345,16 +368,29 @@ void BtPhysTest::TickGame(float seconds) } } - vec3 min_max_diff = (cam_min_max[1] - cam_min_max[0]); - float screen_size = max(max(lol::abs(min_max_diff.x), lol::abs(min_max_diff.y)), - max( lol::abs(min_max_diff.x), lol::abs(min_max_diff.y))); float fov_ratio = max(max(lol::abs(screen_min_max[0].x), lol::abs(screen_min_max[0].y)), max(lol::abs(screen_min_max[1].x), lol::abs(screen_min_max[1].y))); - //m_camera->SetProjection(mat4::perspective(30.f * fov_ratio * 1.1f, 1280.f, 960.f, .1f, 1000.f)); + vec3 new_target = cam_center / cam_factor; + float fov_dp = .0f; + float loc_dp = .0f; + + //ideally fov is on the target + if (lol::abs(fov_ratio - 1.f) < .2f) + fov_dp = ((m_cam_target == -1)?(.7f):(.2f)); + else + fov_dp = ((m_cam_target == -1)?(1.7f):(.9f)); + + //ideally loc is on the target + if (length(new_target - m_camera->GetTarget()) < 6.f) + loc_dp = ((m_cam_target == -1)?(.5f):(.03f)); + else + loc_dp = ((m_cam_target == -1)?(.9f):(.5f)); + + m_camera->SetFov(damp(m_camera->GetFov(), m_camera->GetFov() * fov_ratio * 1.1f, fov_dp, seconds)); + vec3 tmp = damp(m_camera->GetTarget(), new_target, loc_dp, seconds); m_camera->SetView((mat4::rotate(10.f * seconds, vec3(.0f, 1.f, .0f)) * vec4(m_camera->GetPosition(), 1.0f)).xyz, - //vec3(70.f, 30.f, 0.f), - cam_center / cam_factor, vec3(0, 1, 0)); + tmp, vec3(0, 1, 0)); #endif //USE_BODIES #endif //CAT_MODE diff --git a/test/btphystest.h b/test/btphystest.h index bfd442a9..8480d7cc 100644 --- a/test/btphystest.h +++ b/test/btphystest.h @@ -73,6 +73,8 @@ private: Array m_stairs_list; float m_loop_value; + float m_target_timer; + int m_cam_target; }; #endif // __BTPHYSTEST_H__ diff --git a/test/front_camera_sprite.lolfx b/test/front_camera_sprite.lolfx index 01d56513..aa8da80f 100644 --- a/test/front_camera_sprite.lolfx +++ b/test/front_camera_sprite.lolfx @@ -77,7 +77,7 @@ void main(void) vec4 color = texture2D(in_texture, texcoord) * pass_color; //need 130 : ivec2 tex_size = textureSize(in_texture, 0); - int sample_nb = 5; + int sample_nb = 2; if (color.a < 0.9) { for (int x = -sample_nb; x <= sample_nb; x++)