#include "Camera.hpp" #include "elements/Transformable.hpp" #include "interfaces/IRenderer.hpp" TSE::Camera* TSE::Camera::mainCamera = nullptr; float TSE::Camera::GetRenderScale() const { return RenderScale; } TSE::ProjectionType TSE::Camera::GetProjection() const { return projection; } float TSE::Camera::GetNearClippingPlane() const { return nearClippingPlane; } float TSE::Camera::GetFarClippingPlane() const { return farClippingPlane; } float TSE::Camera::GetFov() const { return fov; } TSE::Vector3 TSE::Camera::SceenPositionToGamePosition(Vector2 screenPos) { float x = 2.0f * screenPos.x / lastRtSize.x -1.0f; float y = 1.0f - 2.0f * screenPos.y / lastRtSize.y; float z = -1.0f; Vector4 ndc(x,y,x,1); Matrix4x4 InversProj = Matrix4x4(*projectionMatrix); InversProj.Invert(); Vector4 camSpace = InversProj * ndc; camSpace = camSpace / camSpace.w; Vector3 relativPos(camSpace); relativPos.z = 0; return baseObject->LocalToGlobalPosition(relativPos); } void TSE::Camera::SetRenderScale(float v) { RenderScale = v; RecalculateProjMatrix(); } void TSE::Camera::SetProjection(ProjectionType v) { projection = v; RecalculateProjMatrix(); } void TSE::Camera::SetNearClippingPlane(float v) { nearClippingPlane = v; RecalculateProjMatrix(); } void TSE::Camera::SetFarClippingPlane(float v) { farClippingPlane = v; RecalculateProjMatrix(); } void TSE::Camera::SetFov(float v) { fov = v; RecalculateProjMatrix(); } TSE::Camera::Camera() { } TSE::Camera::~Camera() { delete(projectionMatrix); if(mainCamera == this) mainCamera = nullptr; } void TSE::Camera::OnResize(float width, float height, IResizable *wnd) { lastRtSize = {width, height}; RecalculateProjMatrix(); } void TSE::Camera::SetRenderTarget(IRenderTarget *target) { if(rt != nullptr) rt->RemoveResizeNotifiable(this); if(target != nullptr) target->AddResizeNotifiable(this); rt = target; RecalculateProjMatrix(); } TSE::IRenderTarget *TSE::Camera::GetRenderTarget() { return rt; } void TSE::Camera::RecalculateProjMatrix() { if(projectionMatrix) delete(projectionMatrix); if(projection == ProjectionType::Orthographic) { float x = lastRtSize.x / RenderScale; float y = lastRtSize.y / RenderScale; float mx = -x; float my = -y; projectionMatrix = new Matrix4x4(Matrix4x4::Orthographic(mx, x, my, y, nearClippingPlane, farClippingPlane)); } else if(projection == ProjectionType::Perspective) { float x = lastRtSize.x / RenderScale; float y = lastRtSize.y / RenderScale; float aspectRatio = x / y; projectionMatrix = new Matrix4x4(Matrix4x4::Perspective(fov, aspectRatio, nearClippingPlane, farClippingPlane)); } } void TSE::Camera::OnUpdate() { if(mainCamera == nullptr && baseObject->name != ".EditorCamera") { mainCamera = this; } if(rt != nullptr) IRenderer::camerasToRenderWith.push_back(this); } void TSE::Camera::Start() { if(mainCamera == nullptr && baseObject->name != ".EditorCamera") { mainCamera = this; } } TSE::Matrix4x4 BuildView_Zplus_RH(const TSE::Matrix4x4& world) { using namespace TSE; // Welt-Position (w=1) Vector3 pos = Vector3(world * Vector4(0,0,0,1)); // Richtungsachsen in Welt (w=0, KEINE Translation!) Vector3 fwdWS = Vector3(world * Vector4(0,0,1,0)); // +Z vorwärts in Welt Vector3 upWS = Vector3(world * Vector4(0,1,0,0)); // +Y oben in Welt // Orthonormale Basis aufbauen (X+ soll "right" sein) Vector3 f = Vector3::Normalize(fwdWS); Vector3 r = Vector3::Normalize(Vector3::Cross(upWS, f)); // right = up × forward => (+1,0,0) im Identity-Fall Vector3 u = Vector3::Cross(f, r); // re-orthonormalisiertes up Matrix4x4 view(1.0f); // Identität als Basis // Row-major befüllen (Zeilen = r,u,-f), letzte Spalte = -dot(row, pos) bzw. +dot(f,pos) view.m[0][0] = r.x; view.m[0][1] = r.y; view.m[0][2] = r.z; view.m[0][3] = -Vector3::Dot(r, pos); view.m[1][0] = u.x; view.m[1][1] = u.y; view.m[1][2] = u.z; view.m[1][3] = -Vector3::Dot(u, pos); view.m[2][0] = -f.x; view.m[2][1] = -f.y; view.m[2][2] = -f.z; view.m[2][3] = Vector3::Dot(f, pos); view.m[3][0] = 0.0f; view.m[3][1] = 0.0f; view.m[3][2] = 0.0f; view.m[3][3] = 1.0f; return view; } void TSE::Camera::PreDraw(IShader *shader) { rt->Bind(); shader->SetUniform("prMatrix", projectionMatrix); auto worlmatrix = baseObject->GetGlobalMatrix(); viewMatrix = BuildView_Zplus_RH(worlmatrix); shader->SetUniform("camMatrix", &viewMatrix); } void TSE::Camera::PostDraw() { rt->Unbind(); } void TSE::Camera::Bind() { rt->Bind(); } void TSE::Camera::Unbind() { rt->Unbind(); } void TSE::Camera::UpdateRenderTarget() { rt->Update(); }