const Frustum& Camera::GetFrustum() const { // Use projection_ instead of GetProjection() so that Y-flip has no effect. Update first if necessary if (projectionDirty_) UpdateProjection(); if (frustumDirty_) { if (customProjection_) frustum_.Define(projection_ * GetView()); else { // If not using a custom projection, prefer calculating frustum from projection parameters instead of matrix // for better accuracy if (!orthographic_) frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), GetFarClip(), GetEffectiveWorldTransform()); else frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), GetFarClip(), GetEffectiveWorldTransform()); } frustumDirty_ = false; } return frustum_; }
Frustum Camera::GetViewSpaceFrustum() const { Frustum ret; if (!orthographic_) ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_); else ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_); return ret; }
const Frustum& Camera::GetFrustum() const { if (frustumDirty_) { const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY; if (!orthographic_) frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform); else frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform); frustumDirty_ = false; } return frustum_; }
void Camera::GetFrustumSize(Vector3& near, Vector3& far) const { near.z_ = GetNearClip(); far.z_ = farClip_; if (!orthographic_) { float halfViewSize = tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_; near.y_ = near.z_ * halfViewSize; near.x_ = near.y_ * aspectRatio_; far.y_ = far.z_ * halfViewSize; far.x_ = far.y_ * aspectRatio_; } else { float halfViewSize = orthoSize_ * 0.5f / zoom_; near.y_ = far.y_ = halfViewSize; near.x_ = far.x_ = near.y_ * aspectRatio_; } if (flipVertical_) { near.y_ = -near.y_; far.y_ = -far.y_; } }
const Frustum& Camera::GetFrustum() const { if (frustumDirty_) { Matrix3x4 worldTransform = GetEffectiveWorldTransform(); if (!orthographic_) frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform); else frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform); frustumDirty_ = false; } return frustum_; }
Vector3 Camera::ScreenToWorldPoint(const Vector3& screenPos) const { Ray ray = GetScreenRay(screenPos.x_, screenPos.y_); Vector3 viewSpaceDir = (GetView() * Vector4(ray.direction_, 0.0f)); float rayDistance = (Max(screenPos.z_ - GetNearClip(), 0.0f) / viewSpaceDir.z_); return ray.origin_ + ray.direction_ * rayDistance; }
bool Camera::ObjectFrustumCulling( const RenderObject& obj ) { const AABB& aabb = obj.m_worldAABB; //物体坐标转换到相机空间进行裁减 VEC4 pos(aabb.GetCenter(), 1.0f); Common::Transform_Vec4_By_Mat44(pos, pos, GetViewMatrix()); float n = GetNearClip(); float f = GetFarClip(); float fov = GetFov(); float half_w = n * std::tan(fov/2); float half_h = half_w / GetAspectRatio(); //检测前后面 if(-pos.z+aabb.m_boundingRadius <= n || -pos.z-aabb.m_boundingRadius >= f) return true; //检测左右面 float planeX = half_w * pos.z / -n; if(pos.x - planeX >= aabb.m_boundingRadius || pos.x + aabb.m_boundingRadius <= -planeX) return true; //检测上下面 float planeY = half_h * pos.z / -n; if(pos.y - planeY >= aabb.m_boundingRadius || pos.y + aabb.m_boundingRadius <= -planeY) return true; return false; }
Frustum Camera::GetViewSpaceFrustum() const { if (projectionDirty_) UpdateProjection(); Frustum ret; if (customProjection_) ret.Define(projection_); else { if (!orthographic_) ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), GetFarClip()); else ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), GetFarClip()); } return ret; }
void Camera::_BuildProjMatrix() { /* 这是第一个版本的透视投影矩阵,即"蛮干"求解法. 它的缺陷在于为了变换出xy坐标都在[-1, 1]的CVV空间, 必须满足以下条件: 1.视距d=1. 2.fov=90度. 3.视口AspectRatio=1. 否则变换不出CVV. MatProj = ( 1, 0, 0, 0 0, 1, 0, 0 0, 0, 1, 0 0, 0, 1/d, 0 ) 投影变换加齐次除法后: x' = x * d / z, y' = y * d / z */ //普适版投影矩阵.推导见: http://blog.csdn.net/popy007/article/details/1797121 float r,l,t,b; r = m_nearClip*tanf(m_fov/2); l = -r; t = r/m_aspectRatio; b= -t; m_matProj.m00 = 2*m_nearClip/(r-l); m_matProj.m01 = 0; m_matProj.m02 = (r+l)/(r-l); m_matProj.m03 = 0; m_matProj.m10 = 0; m_matProj.m11 = 2*m_nearClip/(t-b); m_matProj.m12 = (t+b)/(t-b); m_matProj.m13 = 0; m_matProj.m20 = 0; m_matProj.m21 = 0; m_matProj.m22 = -(m_farClip+m_nearClip)/(m_farClip-m_nearClip); m_matProj.m23 = -2*m_farClip*m_nearClip/(m_farClip-m_nearClip); m_matProj.m30 = 0; m_matProj.m31 = 0; m_matProj.m32 = -1; m_matProj.m33 = 0; m_matInvProj = m_matProj.Inverse(); m_imagePlane_r = GetNearClip() * tanf(GetFov() / 2); m_imagePlane_t = m_imagePlane_r / GetAspectRatio(); }
Frustum Camera::GetViewSpaceSplitFrustum(float nearClip, float farClip) const { Frustum ret; nearClip = Max(nearClip, GetNearClip()); farClip = Min(farClip, farClip_); if (farClip < nearClip) farClip = nearClip; if (!orthographic_) ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip); else ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip); return ret; }
Frustum Camera::GetSplitFrustum(float nearClip, float farClip) const { Frustum ret; Matrix3x4 worldTransform = GetEffectiveWorldTransform(); nearClip = Max(nearClip, GetNearClip()); farClip = Min(farClip, farClip_); if (farClip < nearClip) farClip = nearClip; if (!orthographic_) ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, worldTransform); else ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, worldTransform); return ret; }
Frustum Camera::GetSplitFrustum(float nearClip, float farClip) const { Frustum ret; const Matrix3x4& worldTransform = node_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY; nearClip = Max(nearClip, GetNearClip()); farClip = Min(farClip, farClip_); if (farClip < nearClip) farClip = nearClip; if (!orthographic_) ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, worldTransform); else ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, worldTransform); return ret; }
bool Camera::IsProjectionValid() const { return farClip_ > GetNearClip(); }
Matrix4 Camera::GetProjection(bool apiSpecific) const { Matrix4 ret(Matrix4::ZERO); // Whether to construct matrix using OpenGL or Direct3D clip space convention #ifdef URHO3D_OPENGL bool openGLFormat = apiSpecific; #else bool openGLFormat = false; #endif if (!orthographic_) { float nearClip = GetNearClip(); float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_; float w = h / aspectRatio_; float q, r; if (openGLFormat) { q = (farClip_ + nearClip) / (farClip_ - nearClip); r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip); } else { q = farClip_ / (farClip_ - nearClip); r = -q * nearClip; } ret.m00_ = w; ret.m02_ = projectionOffset_.x_ * 2.0f; ret.m11_ = h; ret.m12_ = projectionOffset_.y_ * 2.0f; ret.m22_ = q; ret.m23_ = r; ret.m32_ = 1.0f; } else { // Disregard near clip, because it does not affect depth precision as with perspective projection float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_; float w = h / aspectRatio_; float q, r; if (openGLFormat) { q = 2.0f / farClip_; r = -1.0f; } else { q = 1.0f / farClip_; r = 0.0f; } ret.m00_ = w; ret.m03_ = projectionOffset_.x_ * 2.0f; ret.m11_ = h; ret.m13_ = projectionOffset_.y_ * 2.0f; ret.m22_ = q; ret.m23_ = r; ret.m33_ = 1.0f; } if (flipVertical_) ret = flipMatrix * ret; return ret; }
Matrix4 Camera::GetProjection(bool apiSpecific) const { Matrix4 ret(Matrix4::ZERO); if (!orthographic_) { float nearClip = GetNearClip(); float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_; float w = h / aspectRatio_; float q, r; if (apiSpecific) { #ifdef USE_OPENGL q = (farClip_ + nearClip) / (farClip_ - nearClip); r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip); #else q = farClip_ / (farClip_ - nearClip); r = -q * nearClip; #endif } else { q = farClip_ / (farClip_ - nearClip); r = -q * nearClip; } ret.m00_ = w; ret.m02_ = projectionOffset_.x_ * 2.0f; ret.m11_ = h; ret.m12_ = projectionOffset_.y_ * 2.0f; ret.m22_ = q; ret.m23_ = r; ret.m32_ = 1.0f; } else { // Disregard near clip, because it does not affect depth precision as with perspective projection float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_; float w = h / aspectRatio_; float q, r; if (apiSpecific) { #ifdef USE_OPENGL q = 2.0f / farClip_; r = -1.0f; #else q = 1.0f / farClip_; r = 0.0f; #endif } else { q = 1.0f / farClip_; r = 0.0f; } ret.m00_ = w; ret.m03_ = projectionOffset_.x_ * 2.0f; ret.m11_ = h; ret.m13_ = projectionOffset_.y_ * 2.0f; ret.m22_ = q; ret.m23_ = r; ret.m33_ = 1.0f; } if (flipVertical_) ret = flipMatrix * ret; return ret; }