FMatrix OSVRHMDDescription::GetProjectionMatrix(EEye Eye) const { // @TODO: a proper stereo projection matrix should be calculated const float ProjectionCenterOffset = 0.151976421f; const float PassProjectionOffset = (Eye == LEFT_EYE) ? ProjectionCenterOffset : -ProjectionCenterOffset; #if 1 const float HalfFov = FMath::DegreesToRadians(GetFov(Eye).X) / 2.f; const float InWidth = GetDisplaySize(Eye).X; const float InHeight = GetDisplaySize(Eye).Y; const float XS = 1.0f / tan(HalfFov); const float YS = InWidth / tan(HalfFov) / InHeight; #else const float HalfFov = 2.19686294f / 2.f; const float InWidth = 640.f; const float InHeight = 480.f; const float XS = 1.0f / tan(HalfFov); const float YS = InWidth / tan(HalfFov) / InHeight; #endif const float InNearZ = GNearClippingPlane; return FMatrix( FPlane(XS, 0.0f, 0.0f, 0.0f), FPlane(0.0f, YS, 0.0f, 0.0f), FPlane(0.0f, 0.0f, 0.0f, 1.0f), FPlane(0.0f, 0.0f, InNearZ, 0.0f)) * FTranslationMatrix(FVector(PassProjectionOffset, 0, 0)); }
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; }
LUAMTA_FUNCTION(camera, GetFov) { auto self = my->ToCameraPtr(1); my->Push(self->GetFov()); return 1; }
//========================================================= // FInViewCone - returns true is the passed vector is in // the caller's forward view cone. //========================================================= bool CEntity::FInViewCone(Vector *pOrigin, float fov) { if (fov <= 0) fov = GetFov(); Vector forward; GetViewAngles().AngleVectors(&forward); Vector vecLOS = (*pOrigin - GetGunPosition()).Normalize(); float flDot = DotProduct(vecLOS, forward); return (flDot >= cos((fov / 2) * (M_PI / 180))); }
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(); }
bool CBaseBot::FindEnemy() { // check if the health is decreased bool fHealthDecreased = m_iPrevHealth > GetHealth(); m_iPrevHealth = GetHealth(); // store away the current health value float cur_dist; if (m_pEnemy && (!m_pEnemy->IsValid() || !m_pEnemy->IsAlive())) m_pEnemy = NULL; // null out the enemy pointer as it's no longer valid Vector vecHisPos; unsigned char cHit; // see if we can still see the current enemy... if (m_pEnemy) { if (FBoxVisible(m_pEnemy, &vecHisPos, &cHit)) { m_vecEnemy = vecHisPos; m_ucVisibility = cHit; } else { m_pEnemy = NULL; // we can no longer see this enemy } } // if we already have an enemy... if (m_pEnemy) { // don't discard important enemies (bomb/flag/hostage carrier, VIP, etc) if (g_pServer->ClientIsImportant(EnemyClient())) return false; // calculate the distance to the enemy cur_dist = (m_pEnemy->GetOrigin() - GetOrigin()).Length(); } else { cur_dist = FLT_MAX; // just some crazy value } // loop through all the clients... for (int i = 0; i < g_pServer->GetMaxClients(); i++) { if (i == entindex() - 1 || (m_pEnemy && i == m_pEnemy->entindex() - 1)) continue; // skip myself and the current enemy CClient *pClient = g_pServer->m_rgpClients[i]; if (!pClient || !pClient->IsValid() || !pClient->IsAlive()) continue; float dist = (pClient->GetOrigin() - GetOrigin()).Length(); // if this enemy is further away than the current one... if (dist > cur_dist && !g_pServer->ClientIsImportant(pClient)) continue; // skip it if (dist > 900 + 4000 * ((GetDifficulty() - 1) / 4.0)) continue; // enemy is too far if (g_pServer->IsTeamplay() && GetTeam() == g_pServer->GetTeam(pClient)) continue; // skip our teammates float fov; // if the bot's health decreased or the enemy is shooting if (!m_pEnemy && (fHealthDecreased || pClient->IsShooting())) fov = 360; else fov = GetFov() * 2 - (GetFov() - (dist > GetFov() * 9 ? GetFov() * 9 : dist) / 9); // check if enemy is in the view cone if (!FInViewCone(pClient, fov)) continue; // enemy isn't in bot's view cone // check if enemy is visible if (!FBoxVisible(pClient, &vecHisPos, &cHit)) { continue; // skip this enemy } // if the enemy is quite far away, not shooting and the bot is not damaged if (!m_pEnemy && dist > 200 && !fHealthDecreased && !pClient->IsShooting()) { // if the bot isn't in the fov of the enemy and the bot doesn't really want to fight if (!pClient->FInViewCone(this, 120) /*&& BotWantsToRetreat()*/) continue; // skip this enemy } m_pEnemy = pClient; // found a new enemy m_vecEnemy = vecHisPos; m_ucVisibility = cHit; DebugMsg(DEBUG_BOTCOMBAT, "Found new enemy: %s", m_pEnemy->GetNetName()); return true; } return false; // no new enemy is found }