bool IntersectRayAABB(const Ray& r, const AABB& a, float* out_tmin, float3* out_pos, float3* out_nor) { const float3& p = r.pos; const float3& d = r.direction; float tmin = -FLT_MAX; float tmax = FLT_MAX; float3 minNorm, maxNorm; // check vs. all three 'slabs' of the aabb for(int i = 0; i < 3; ++i) { if(abs(d[i]) < Epsilon) { // ray is parallel to slab, no hit if origin not within slab if(p[i] < a.Min()[i] || p[i] > a.Max()[i] ) { return false; } } else { // compute intersection t values of ray with near and far plane of slab float ood = 1.0f / d[i]; float t1 = (a.Min()[i] - p[i]) * ood; float t2 = (a.Max()[i] - p[i]) * ood; tmin = maximize(tmin, minimize(t1, t2)); tmax = minimize(tmax, maximize(t1, t2)); // exit with no collision as soon as slab intersection becomes empty if(tmin > tmax) { return false; } } } if(tmax < 0.f) { // entire bounding box is behind us return false; } else if(tmin < 0.f) { // we are inside the bounding box *out_tmin = 0.f; *out_pos = p; *out_nor = normalize(a.GetCenter() - (*out_pos)); // use 'sphere' type normal calculation to approximate. return true; } else { // ray intersects all 3 slabs. return point and normal of intersection *out_tmin = tmin; *out_pos = p + d * tmin; *out_nor = normalize(a.GetCenter() - (*out_pos)); // use 'sphere' type normal calculation to approximate. return true; } }
//------------------------------------------------------------------------ void SKillEffect::Activate(EntityId targetId, EntityId ownerId, EntityId weaponId, const char *effect, const char *defaultEffect) { CActor *pActor = (CActor *)gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(targetId); if (pActor) { //Execute particle effect and kill the actor GameWarning("Explosion effect: %s (Actor)", effect); // TODO: make work in MP... IParticleEffect *pEffect = gEnv->p3DEngine->FindParticleEffect(effect); if (pEffect) { int effectId = 0; effectId = pActor->GetEntity()->LoadParticleEmitter(-1,pEffect); AABB box; pActor->GetEntity()->GetLocalBounds(box); Matrix34 tm = IParticleEffect::ParticleLoc(box.GetCenter()); pActor->GetEntity()->SetSlotLocalTM(effectId, tm); } HitInfo info(ownerId, targetId, weaponId, 1000.0f, 0.0f, 0, 0, 0); g_pGame->GetGameRules()->ServerHit(info); } else if(!pActor && targetId) { // TODO: make work in MP... //No actor, but we have an entity IEntity* pEntity = gEnv->pEntitySystem->GetEntity(targetId); if(pEntity) { //Execute particle effect and kill the actor GameWarning("Explosion effect: %s (Entity)", defaultEffect); IParticleEffect *pEffect = gEnv->p3DEngine->FindParticleEffect(defaultEffect); if (pEffect) { int effectId = 0; effectId = pEntity->LoadParticleEmitter(-1,pEffect); AABB box; pEntity->GetLocalBounds(box); Matrix34 tm = IParticleEffect::ParticleLoc(box.GetCenter()); pEntity->SetSlotLocalTM(effectId, tm); } } } }
bool AABBInHalfSpace(const AABB & box, const float * plane) { /* Main Idea: -> Separating-axis test with only normal of the plane. */ float radius = box.GetExtent(0) * abs(plane[0]) + box.GetExtent(1) * abs(plane[1]) + box.GetExtent(2) * abs(plane[2]); float signed_distance = box.GetCenter()[0] * plane[0] + box.GetCenter()[1] * plane[1] + box.GetCenter()[2] * plane[2] + plane[3]; return signed_distance + radius >= 0; //Only test if box is in positive side of plane. }
void CTacticalManager::Ping(const ETacticalEntityType type, const float fPingDistance) { const Vec3& clientPos = CHUDUtils::GetClientPos(); AABB entityBox; const float pingDistanceSq = fPingDistance*fPingDistance; TInterestPoints& points = GetTacticalPoints(type); TInterestPoints::iterator pointsIt = points.begin(); TInterestPoints::iterator pointsItEnd = points.end(); for(; pointsIt!=pointsItEnd; ++pointsIt) { STacticalInterestPoint &entry = (*pointsIt); IEntity* pEntity = gEnv->pEntitySystem->GetEntity(entry.m_entityId); if (!pEntity) continue; if(pEntity->IsHidden()) continue; pEntity->GetWorldBounds(entityBox); if(clientPos.GetSquaredDistance(entityBox.GetCenter()) > pingDistanceSq) // Outside ping range continue; if (entry.m_pinged != true) { entry.m_pinged = true; } } }
//----------------------------------------------------------------------------- // AABB vs Frustum test. // // Return values: 0 = no intersection, // 1 = intersection, // 2 = box is completely inside frustum // //----------------------------------------------------------------------------- int FrustumAABBIntersect(const Frustum& frustum, const AABB& box) { float3 c = box.GetCenter(); float3 r = box.Max() - c; bool intersects = false; for(int i = 0; i < 6; ++i) { const Plane& plane = frustum[i]; // test plane and AABB intersection. float e = r.x * abs(plane.normal.x) + r.y * abs(plane.normal.y) + r.z * abs(plane.normal.z); float s = plane.Eval(c); // assert(e > 0); // the box is in positive half-space. if((s - e) > 0) continue; // if box is completely in negative side of the plain // then the box is outside frustum. if( (s + e) < 0) return 0; // no intersection, early exit. intersects = true; } if(intersects) return 1; return 2; // either intersects or completely inside frustum }
bool Enemy::SeekBehavior() { auto PlayerPtr = GetStage()->GetSharedGameObject<Player>(L"Player"); auto PlayerPos = PlayerPtr->GetComponent<Transform>()->GetPosition(); auto MyPos = GetComponent<Transform>()->GetPosition(); auto MapPtr = m_CelMap.lock(); if (MapPtr) { if (SearchPlayer()) { auto PtrSeek = GetBehavior<SeekSteering>(); if (m_NextCellIndex == 0) { auto PtrRigid = GetComponent<Rigidbody>(); auto Velo = PtrRigid->GetVelocity(); Velo *= 0.95f; PtrRigid->SetVelocity(Velo); PlayerPos.y = m_StartPosition.y; PtrSeek->Execute(PlayerPos); } else { if (length(MyPos - PlayerPos) <= 3.0f){ auto PtrRigid = GetComponent<Rigidbody>(); auto Velo = PtrRigid->GetVelocity(); Velo *= 0.95f; PtrRigid->SetVelocity(Velo); } AABB ret; MapPtr->FindAABB(m_CellPath[m_NextCellIndex], ret); auto Pos = ret.GetCenter(); Pos.y = m_StartPosition.y; PtrSeek->Execute(Pos); } return true; } else { auto PtrSeek = GetBehavior<SeekSteering>(); CellIndex PlayerCell; if (MapPtr->FindCell(PlayerPos, PlayerCell)) { AABB ret; MapPtr->FindAABB(PlayerCell, ret); auto Pos = ret.GetCenter(); Pos.y = m_StartPosition.y; PtrSeek->Execute(Pos); return true; } } } return false; }
bool BasicPrimitiveTests::IntersectingRayAgainstAABB(const Ray & ray, const AABB & aabb) { const Eigen::Vector3f & ray_d_aabb = ray.GetDirection(); Eigen::Vector3f ray_o_aabb = ray.GetOrigin() - aabb.GetCenter(); return 0; }
bool BasicPrimitiveTests::IntersectingRayAgainstAABB(const Ray & ray, const AABB & aabb, float & rtn_t) { /* Main Idea: -> Uses slab representation for box. -> Finds intersection of ray/segment with each slab. Then compares intersection times for overlap in all slabs. -> Keep track of: -> A: The farthest of all entries into a slab -> B: The closest of all exits out of a slab. -> If A > B at anytime, exit with no intersection. Intersecting slabs: -> Intersect slabs by inserting ray equation into plane equations for slab. -> Solve for t -> Must handle case when ray parallel to slab separately. -> To avoid division by zero. Can test for intersection without calculating intersection point: -> Choose coordinate system where box is axis aligned and centered at origin: AABB: -> Translate segment and AABB to origin. OBB: -> Transform Segment to OBB space, then translate both segment and OBB to origin. -> Do separating axis test with 6 axes: -> Three principle axes. -> Three cross products of box face normals and segment direction vector. */ rtn_t = 0.0f; float tmax = FLT_MAX; Eigen::Vector3f aabb_min = aabb.GetCenter() - aabb.GetExtents(); Eigen::Vector3f aabb_max = aabb.GetCenter() + aabb.GetExtents(); for (int i = 0; i < 3; ++i) { if (abs(ray.GetDirection()[i]) < EPSILON) { //Ray is parallel to slab. Not hit if origin not within slab. if (ray.GetOrigin()[i] < aabb_min[i] || ray.GetOrigin()[i] > aabb_max[i]) { return false; } } else { float one_over_direction = 1.0f / ray.GetDirection()[i]; float t1 = (aabb_min[i] - ray.GetOrigin()[i]) * one_over_direction; float t2 = (aabb_max[i] - ray.GetOrigin()[i]) * one_over_direction; if (t1 > t2) Swap(t1, t2); if (t1 > rtn_t) rtn_t = t1; if (t2 > tmax) tmax = t2; if (rtn_t > tmax) return false; } } return true; }
int BasicPrimitiveTests::IntersectingSegmentAgainstAABB(const LineSegment & segment, const AABB & aabb) { Eigen::Vector3f segment_a_aabb = segment.GetPointA() - aabb.GetCenter(); Eigen::Vector3f segment_b_aabb = segment.GetPointB() - aabb.GetCenter(); Eigen::Vector3f segment_m_aabb = (segment_a_aabb + segment_b_aabb) * 0.5f; return 0; }
const Vec3& CTacticalManager::GetTacticalIconCenterBBoxWorldPos(IEntity* pTacticalEntity) { CRY_ASSERT(pTacticalEntity != NULL); AABB box; pTacticalEntity->GetWorldBounds(box); m_tempVec3 = box.GetCenter(); return m_tempVec3; }
int BasicPrimitiveTests::IntersectingSegmentAgainstAABB(const LineSegment & segment, const AABB & aabb, float & rtn_t1, float & rtn_t2) { rtn_t1 = 0.0f; rtn_t2 = FLT_MAX; Eigen::Vector3f aabb_min = aabb.GetCenter() - aabb.GetExtents(); Eigen::Vector3f aabb_max = aabb.GetCenter() + aabb.GetExtents(); Eigen::Vector3f segment_direction = segment.GetPointB() - segment.GetPointA(); for (int i = 0; i < 3; ++i) { if (abs(segment_direction[i]) < EPSILON) { //Ray is parallel to slab. Not hit if origin not within slab. if (segment.GetPointA()[i] < aabb_min[i] || segment.GetPointA()[i] > aabb_max[i]) { return 0; } } else { float one_over_direction = 1.0f / segment_direction[i]; float t1 = (aabb_min[i] - segment.GetPointA()[i]) * one_over_direction; float t2 = (aabb_max[i] - segment.GetPointA()[i]) * one_over_direction; if (t1 > 1.0f && t2 > 1.0f) { return 0; } if (t1 > t2) Swap(t1, t2); if (t1 > rtn_t1) rtn_t1 = t1; if (t2 > rtn_t2) rtn_t2 = t2; if (rtn_t1 > rtn_t2) return 0; } } if (rtn_t1 >= 0.0f && rtn_t1 <= 1.0f) { if (rtn_t2 >= 0.0f && rtn_t2 <= 1.0f) { return 2; } else { return 1; } } else { Swap(rtn_t1, rtn_t2); if (rtn_t1 >= 0.0f && rtn_t1 <= 1.0f) { return 1; } return 0; } }
//----------------------------------------------------------------------------- // Plane vs AABB test. // // Return values: // 0 = (Front) There is no intersection, and the box is in // the positive half-space of the Plane. // // 1 = (Back) There is no intersection, and the box is in // the negative half-space of the Plane. // 2 = (Intersecting) the box intersects the plane. //----------------------------------------------------------------------------- int PlaneAABBIntersection(const Plane& plane, const AABB& box) { float3 c = box.GetCenter(); float3 r = box.Max() - c; float e = r.x * abs(plane.normal.x) + r.y * abs(plane.normal.y) + r.z * abs(plane.normal.z); float s = plane.Eval(c); if((s - e) > 0) return 0; // front side if((s + e) < 0) return 1; // back side return 2; // Intersecting }
void CAICorpseManager::RemoveSomeCorpses() { const uint32 corspeCount = (uint32)m_corpsesArray.size(); assert(corspeCount > AI_CORPSES_MINIMUM); const uint32 maxCorpsesToRemove = MIN((corspeCount / AI_CORPSES_MINIMUM), 8); assert(maxCorpsesToRemove > 0); std::vector<SCorpseRemovalScore> corpseScoresInfo; corpseScoresInfo.reserve( corspeCount ); const CCamera& viewCamera = gEnv->pSystem->GetViewCamera(); const Vec3 cameraPosition = viewCamera.GetPosition(); const float farAway = (g_pGameCVars->g_aiCorpses_ForceDeleteDistance * 0.85f); const float kUpCloseThreshold = (15.0f * 15.0f); //Gives non-removal priority to corpses near the player const float kFarAwayThreshold = max((farAway * farAway), kUpCloseThreshold * 2.0f); //Gives removal priority to corpses far away from the player for(uint32 i = 0; i < corspeCount; ++i) { CorpseInfo& corpseInfo = m_corpsesArray[i]; SCorpseRemovalScore removalScore(corpseInfo.corpseId); CAICorpse* pCorpse = corpseInfo.GetCorpse(); if(pCorpse != NULL) { AABB corpseBounds; pCorpse->GetEntity()->GetWorldBounds(corpseBounds); corpseBounds.Expand( Vec3(0.1f, 0.1f, 0.1f) ); const float distanceSqr = (cameraPosition - corpseBounds.GetCenter()).len2(); removalScore.distance = distanceSqr; removalScore.upClose = (distanceSqr < kUpCloseThreshold); removalScore.farAway = (distanceSqr > kFarAwayThreshold); removalScore.visible = viewCamera.IsAABBVisible_F(corpseBounds); removalScore.priority = pCorpse->GetPriority(); } corpseScoresInfo.push_back(removalScore); } std::sort(corpseScoresInfo.begin(), corpseScoresInfo.end()); assert(maxCorpsesToRemove < corpseScoresInfo.size()); const uint32 corpseScoresCount = corpseScoresInfo.size(); for(uint32 i = 0; i < maxCorpsesToRemove; ++i) { RemoveCorpse(corpseScoresInfo[i].corpseId); } }
void OBB::Create(const AABB& aabb, const Matrix4x4& mat) { // Note: must be coherent with Rotate() aabb.GetCenter(mCenter); aabb.GetExtents(mExtents); // Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity). // So following what's done in Rotate: // - x-form the center mCenter *= mat; // - combine rotation with identity, i.e. just use given matrix mRot = mat; }
bool CPersistantDebug::GetEntityParams(EntityId entityId, Vec3& baseCenterPos, float& height) { IEntity *ent = gEnv->pEntitySystem->GetEntity(entityId); if (ent) { AABB bounds; ent->GetWorldBounds(bounds); baseCenterPos = bounds.GetCenter(); baseCenterPos.z = bounds.min.z; height = bounds.GetSize().z; return true; } return false; }
bool CPhysBody::Create(AABB boundingbox, Vec3 position, bool dynamic) { NxActorDesc actorDesc; NxBodyDesc bodyDesc; NxBoxShapeDesc boxDesc; //set size //boxDesc.dimensions.set(boundingbox.GetExtent(0), boundingbox.GetExtent(1), boundingbox.GetExtent(2)); boxDesc.dimensions.set((boundingbox.max.x - boundingbox.min.x)/2, (boundingbox.max.y - boundingbox.min.y)/2, (boundingbox.max.z - boundingbox.min.z)/2); //set local position within the body boxDesc.localPose.t = NxVec3(boundingbox.GetCenter(0), boundingbox.GetCenter(1), boundingbox.GetCenter(2)); //boxDesc.localPose.t = NxVec3(0.0f, 0.0f, 0.0f); actorDesc.shapes.pushBack(&boxDesc); if(dynamic) actorDesc.body = &bodyDesc; else actorDesc.body = 0; //set actor's global position actorDesc.globalPose.t = NxVec3(position.x, position.y, position.z); actorDesc.density = 10; m_pActor = g_pPhysScene->createActor(actorDesc); m_pActor->userData = new sNxActorUserData; return true; }
//----------------------------------------------------------------------------- // AABB vs frustum test. // // Return values: false = no intersection, // true = either the box intersections or it is fully containt. // note: this test is fast but not 100% accurate (it is good for viewfrustum culling) //----------------------------------------------------------------------------- bool TestFrustumAABB(const Frustum& frustum, const AABB& box) { float3 c = box.GetCenter(); float3 r = box.Max() - c; for(int i = 0; i < 6; ++i) { const Plane& plane = frustum[i]; // test plane and AABB intersection. float e = r.x * abs(plane.normal.x) + r.y * abs(plane.normal.y) + r.z * abs(plane.normal.z); float s = plane.Eval(c); // if box is completely in negative side of the plain // then the box is outside frustum. if( (s + e) < 0) return false; // no intersection, early exit. } return true; // either intersects or completely inside frustum }
Vec3 GetTargetPos( SActivationInfo* pActInfo ) { EntityId targetId = GetPortEntityId(pActInfo, IN_TARGETID); Vec3 targetPos(0,0,0); if (targetId) { IEntity* pTarget = gEnv->pEntitySystem->GetEntity(targetId); if (pTarget) { AABB box; pTarget->GetWorldBounds(box); targetPos = box.GetCenter(); } } else { targetPos = GetPortVec3(pActInfo, IN_TARGETPOS); } return targetPos; }
void Update(float elapsed) { float maxTime = GetPortFloat(&m_actInfo, EIP_Duration); float percent = maxTime > FLT_EPSILON ? elapsed / maxTime : 1.0f; if(percent >= 1.0f) { m_actInfo.pGraph->SetRegularlyUpdated(m_actInfo.myID, false); m_triggered = false; return; } Vec3 N = GetPortVec3(&m_actInfo, EIP_Normal); float rangeMin = GetPortFloat(&m_actInfo, EIP_RangeMin); float rangeMax = GetPortFloat(&m_actInfo, EIP_RangeMax); const float range = rangeMax - rangeMin; Vec3 boxDim(rangeMax, rangeMax, rangeMax); Vec3 ptmin = m_effectCenter - boxDim; Vec3 ptmax = m_effectCenter + boxDim; float speed = GetPortFloat(&m_actInfo, EIP_Speed); float waveFront = elapsed * speed; float decay = GetPortFloat(&m_actInfo, EIP_Decay); if(decay > FLT_EPSILON) decay = 1.0f / decay; float force = GetPortFloat(&m_actInfo, EIP_Force); force = pow_tpl(force * (1-percent), decay); float amplitude = GetPortFloat(&m_actInfo, EIP_Amplitude); amplitude = pow_tpl(amplitude * (1-percent), decay); if (gEnv->bMultiplayer) // Turned off for performance and network issues { return; } IPhysicalEntity** pEntityList = NULL; static const int iObjTypes = ent_rigid | ent_sleeping_rigid | ent_living;// | ent_allocate_list; int numEntities = gEnv->pPhysicalWorld->GetEntitiesInBox(ptmin, ptmax, pEntityList, iObjTypes); AABB bounds; for(int i=0; i<numEntities; ++i) { IPhysicalEntity* pPhysicalEntity = pEntityList[i]; IEntity* pEntity = static_cast<IEntity*>(pPhysicalEntity->GetForeignData(PHYS_FOREIGN_ID_ENTITY)); // Has the entity already been affected? if(pEntity) { bool affected = stl::find(m_entitiesAffected, pEntity->GetId()); if(!affected) { IEntityPhysicalProxy* pPhysicalProxy = static_cast<IEntityPhysicalProxy*>(pEntity->GetProxy(ENTITY_PROXY_PHYSICS)); if(pPhysicalProxy) { pPhysicalProxy->GetWorldBounds(bounds); Vec3 p = bounds.GetCenter(); Vec3 v = p - m_effectCenter; float distFromCenter = v.GetLength() + FLT_EPSILON; if(distFromCenter < rangeMax) { if(waveFront > distFromCenter) // has the wavefront passed the entity? { //pPhysicalEntity->GetStatus(&dyn); // normalize v, cheaper than another sqrt v /= distFromCenter; Vec3 dir = N + v * force; static bool usePos = false; float impulse = 1.0f - (max(0.0f, distFromCenter - rangeMin) / range); impulse = impulse * amplitude;// / dyn.mass; if(impulse > FLT_EPSILON) { pPhysicalProxy->AddImpulse(-1, p, dir * impulse, usePos, 1.0f); m_entitiesAffected.push_back(pEntity->GetId()); } } } } } } } }
void KDTree::BuildTreeHelper(KDNode& CurrentNode, uint32_t Depth, uint32_t MinObjectsPerNode) { if (Depth == 0 || CurrentNode.ObjectList.size() <= MinObjectsPerNode) return; const uint32_t& DividingAxis = CurrentNode.Axis; auto& CurrentObjects = CurrentNode.ObjectList; const size_t PrimitiveListSize = CurrentNode.ObjectList.size(); const size_t DividingObjectIndex = PrimitiveListSize / 2; // sort all objects by splitting axis std::partial_sort(CurrentObjects.begin(), CurrentObjects.begin() + DividingObjectIndex, CurrentObjects.end(), [DividingAxis](const std::unique_ptr<IDrawable>& lhs, const std::unique_ptr<IDrawable>& rhs) -> bool { return lhs->GetWorldAABB().GetCenter()[DividingAxis] < rhs->GetWorldAABB().GetCenter()[DividingAxis]; }); auto& DividingObject = CurrentObjects[DividingObjectIndex]; AABB DividingAABB = DividingObject->GetWorldAABB(); // offset the dividing axis value to just after the median objects AABB const float DividingAxisValue = DividingAABB.GetCenter()[DividingAxis] + DividingAABB.GetDeminsions()[DividingAxis] + 0.1f; CurrentNode.SplitValue = DividingAxisValue; std::vector<std::unique_ptr<IDrawable>> StraddlingPrimitives; CurrentNode.Child[0] = std::unique_ptr<KDNode>(new KDNode()); CurrentNode.Child[1] = std::unique_ptr<KDNode>(new KDNode()); // check for objects straddling the dividing axis, if so, add them to array for (int i = DividingObjectIndex; i >= 0; i--) { const AABB& CurrentBBox = CurrentObjects[i]->GetWorldAABB(); const float AxisRange = CurrentBBox.GetDeminsions()[DividingAxis]; const float DividedRange = std::abs(CurrentBBox.Min[DividingAxis] - DividingAxisValue); if (AxisRange > DividedRange) StraddlingPrimitives.push_back(std::move(CurrentObjects[i])); else { // add non straddling to near child CurrentNode.Child[0]->ObjectList.push_back(std::move(CurrentObjects[i])); } } for (size_t i = DividingObjectIndex + 1; i < PrimitiveListSize; i++) { const AABB& CurrentBBox = CurrentObjects[i]->GetWorldAABB(); float AxisRange = CurrentBBox.GetDeminsions()[DividingAxis]; float DividedRange = CurrentBBox.Max[DividingAxis] - DividingAxisValue; if (AxisRange > DividedRange) StraddlingPrimitives.push_back(std::move(CurrentObjects[i])); else { // add non straddling to far child CurrentNode.Child[1]->ObjectList.push_back(std::move(CurrentObjects[i])); } } CurrentNode.Child[0]->ObjectList.shrink_to_fit(); CurrentNode.Child[1]->ObjectList.shrink_to_fit(); // increment axis for children CurrentNode.Child[0]->Axis = CurrentNode.Child[1]->Axis = (DividingAxis + 1) % 3; // add all straddling objects to this node CurrentNode.ObjectList.clear(); CurrentNode.ObjectList = std::move(StraddlingPrimitives); BuildTreeHelper(*CurrentNode.Child[0], Depth - 1, MinObjectsPerNode); BuildTreeHelper(*CurrentNode.Child[1], Depth - 1, MinObjectsPerNode); }
void CClaymore::Update(SEntityUpdateContext &ctx, int updateSlot) { CProjectile::Update(ctx, updateSlot); bool debug = (g_pGameCVars->g_debugMines != 0); if(gEnv->bServer) { if(m_armed) { CGameRules* pGR = g_pGame->GetGameRules(); if(pGR) { for(std::list<EntityId>::iterator it = m_targetList.begin(); it != m_targetList.end(); ++it) { IEntity* pEntity = gEnv->pEntitySystem->GetEntity(*it); if(!pEntity) continue; // if this is a team game, claymores aren't set off by their own team... if(pGR->GetTeamCount() > 0 && (m_teamId != 0 && pGR->GetTeam(pEntity->GetId()) == m_teamId)) continue; // otherwise, not set off by the player who dropped them. if(pGR->GetTeamCount() == 0 && m_ownerId == pEntity->GetId()) continue; IPhysicalEntity *pPhysics = pEntity->GetPhysics(); if(pPhysics) { pe_status_dynamics physStatus; if(0 != pPhysics->GetStatus(&physStatus) && physStatus.v.GetLengthSquared() > 0.01f) { // now check angle between this claymore and approaching object // to see if it is within the angular range m_triggerAngle. // If it is, then check distance is less than m_triggerRange, // and also check line-of-sight between the two entities. IRenderAuxGeom * pRAG = gEnv->pRenderer->GetIRenderAuxGeom(); pRAG->SetRenderFlags( e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeNone ); AABB entityBBox; pEntity->GetWorldBounds(entityBBox); if(debug) { pRAG->DrawAABB( entityBBox, true, ColorF(1,0,0,0.4f), eBBD_Faceted ); } Vec3 enemyDir = entityBBox.GetCenter() - GetEntity()->GetPos(); Vec3 checkDir = enemyDir; checkDir.z = 0; float distanceSq = enemyDir.GetLengthSquared(); // for players a simple distance check is fine, but for vehicles use a better intersection check // so any corner of the vehicle going inside the zone sets off the claymore. static float playerRadius = 2.5f; bool inside = false; if(entityBBox.GetRadius() < playerRadius) { inside = (distanceSq < (m_triggerRadius * m_triggerRadius)); } else { static ray_hit hit; if(gEnv->pPhysicalWorld->CollideEntityWithBeam(pEntity->GetPhysics(), GetEntity()->GetWorldPos(), enemyDir, m_triggerRadius, &hit)) { inside = true; enemyDir = hit.pt - GetEntity()->GetWorldPos(); } } if(inside) { enemyDir.NormalizeSafe(); checkDir.NormalizeSafe(); float dotProd = checkDir.Dot(m_triggerDirection); if(debug) { pRAG->DrawLine(GetEntity()->GetPos(), ColorF(1,0,0,1), GetEntity()->GetPos() + Matrix33::CreateRotationZ(m_triggerAngle/2.0f)*m_triggerDirection*m_triggerRadius, ColorF(1,0,0,1), 5.0f); pRAG->DrawLine(GetEntity()->GetPos(), ColorF(1,0,0,1), GetEntity()->GetPos() + Matrix33::CreateRotationZ(-m_triggerAngle/2.0f)*m_triggerDirection*m_triggerRadius, ColorF(1,0,0,1), 5.0f); ColorF clr; clr.a = 0.3f; clr.b = 0.4f; clr.g = 0.1f; clr.r = 1.0f; pRAG->DrawLine(GetEntity()->GetPos(), clr, GetEntity()->GetPos() + (enemyDir * m_triggerRadius), clr, 5.0f); } if(dotProd > cry_cosf(m_triggerAngle/2.0f)) { static const int objTypes = ent_all&(~ent_terrain); static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; ray_hit hit; int col = gEnv->pPhysicalWorld->RayWorldIntersection(GetEntity()->GetPos(), (enemyDir * m_triggerRadius * 1.5f), objTypes, flags, &hit, 1, GetEntity()->GetPhysics()); bool bang = false; if (!col) bang = true; else if (entityBBox.IsContainPoint(hit.pt)) bang = true; else if (hit.pt.GetSquaredDistance(GetEntity()->GetWorldPos()) >= distanceSq) bang = true; if (bang) { // pass in the explosion normal, which is -m_triggerDirection Explode(true, false, Vec3(0,0,0), -m_triggerDirection); if(debug) { ColorF clr; clr.a = 0.3f; clr.g = 0.1f; clr.r = 1.0f; clr.b = 1.0f; pRAG->DrawLine(GetEntity()->GetPos(), clr, GetEntity()->GetPos() + (enemyDir * m_triggerRadius), clr, 5.0f); } } } } } } } } } else { m_timeToArm -= gEnv->pTimer->GetFrameTime(); if(m_timeToArm <= 0.0f) { m_armed = true; IEntityTriggerProxy *pTriggerProxy = (IEntityTriggerProxy*)(GetEntity()->GetProxy(ENTITY_PROXY_TRIGGER)); if (!pTriggerProxy) { GetEntity()->CreateProxy(ENTITY_PROXY_TRIGGER); pTriggerProxy = (IEntityTriggerProxy*)GetEntity()->GetProxy(ENTITY_PROXY_TRIGGER); } if(pTriggerProxy) { // create a trigger volume a couple of metres bigger than we need, to ensure we catch vehicles. // Checks above will still make sure the entity is within the radius before detonating though. float radius = m_triggerRadius + 2.0f; AABB boundingBox = AABB(Vec3(-radius,-radius,-radius), Vec3(radius,radius,radius)); pTriggerProxy->SetTriggerBounds(boundingBox); } } } } if(debug && m_armed) { IRenderAuxGeom * pRAG = gEnv->pRenderer->GetIRenderAuxGeom(); ColorF clr; clr.a = 0.3f; clr.b = 0.4f; clr.g = 0.1f; clr.r = 1.0f; pRAG->SetRenderFlags( e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeNone ); pRAG->DrawCylinder(GetEntity()->GetPos(), Vec3(0, 0, 1), m_triggerRadius, m_triggerRadius * 2.0f, clr); Vec3 size(m_triggerRadius + 2.0f, m_triggerRadius + 2.0f, m_triggerRadius + 2.0f); AABB box(GetEntity()->GetPos() - size, GetEntity()->GetPos() + size); pRAG->DrawAABB(box, false, ColorF(0.1f, 0.1f, 0.1f, 0.1f), eBBD_Faceted); pRAG->DrawLine(GetEntity()->GetPos(), clr, GetEntity()->GetPos() + m_triggerDirection, clr, 5.0f); } }
void CSpammer::UpdatePotentialTargets() { const float minLockOnDistance = m_fireParams->spammerParams.minLockOnDistance; const float maxLockOnDistance = m_fireParams->spammerParams.maxLockOnDistance; const float maxAngleCos = cry_cosf(DEG2RAD(m_fireParams->spammerParams.targetingTolerance)); const CAutoAimManager& autoAimManager = g_pGame->GetAutoAimManager(); const TAutoaimTargets& aaTargets = autoAimManager.GetAutoAimTargets(); const int targetCount = aaTargets.size(); const Vec3 probableHit = Vec3Constants<float>::fVec3_Zero; const Vec3 weaponPos = GetWeaponPosition(probableHit); const Vec3 weaponFwd = GetWeaponDirection(weaponPos, probableHit); m_potentialTargets.Clear(); CPlayerVisTable::SVisibilityParams queryTargetParams(0); const bool flat2DMode = m_fireParams->spammerParams.targetingFlatMode; for (int i = 0; i < targetCount; ++i) { const SAutoaimTarget& target = aaTargets[i]; CRY_ASSERT(target.entityId != m_pWeapon->GetOwnerId()); if (!target.HasFlagSet(eAATF_AIHostile)) continue; IEntity* pTargetEntity = gEnv->pEntitySystem->GetEntity(target.entityId); if (!pTargetEntity) continue; CActor* pActor = target.pActorWeak.lock().get(); AABB bounds; pTargetEntity->GetWorldBounds(bounds); Vec3 targetPos = bounds.GetCenter(); Vec3 targetDistVec = (targetPos - weaponPos).normalized(); float distance = targetPos.GetDistance(weaponPos); if (distance <= minLockOnDistance || distance >= maxLockOnDistance) continue; float alignment; if (!flat2DMode) { alignment = weaponFwd * targetDistVec; } else { const CCamera& viewCamera = gEnv->pSystem->GetViewCamera(); if (!viewCamera.IsPointVisible(targetPos)) continue; alignment = Vec3(weaponFwd.x, weaponFwd.y, 0.0f).GetNormalizedSafe() * Vec3(targetDistVec.x, targetDistVec.y, 0.0f).GetNormalizedSafe(); } if (alignment <= maxAngleCos) continue; const SpammerTarget finalTargetInfo = GetVisibilityTestTarget(pTargetEntity, target.entityId, pActor, bounds); const int kAutoaimVisibilityLatency = 0; queryTargetParams.targetEntityId = finalTargetInfo.targetId; if (!g_pGame->GetPlayerVisTable()->CanLocalPlayerSee(queryTargetParams, kAutoaimVisibilityLatency)) continue; float priority = 1.0f; priority *= finalTargetInfo.radius; priority /= m_targetsAssigned.GetNumLockOns(target.entityId)+1; const float m = 1.0f / (1.0f - maxAngleCos); priority *= m * alignment + (1.0f - m); priority *= 0.1f; priority = min(priority, 1.0f); m_potentialTargets.AddTarget(target.entityId, priority); } float n = 0.0f; size_t num = m_potentialTargets.m_potentialTargets.size(); for (size_t i = 0; i < num; ++i) { n = max(n, m_potentialTargets.m_potentialTargets[i].m_probability); } m_potentialTargets.m_totalProbability = 0.0f; for (size_t i = 0; num && i < m_potentialTargets.m_potentialTargets.size(); ++i) { m_potentialTargets.m_potentialTargets[i].m_probability /= n + FLT_EPSILON; m_potentialTargets.m_totalProbability += m_potentialTargets.m_potentialTargets[i].m_probability; } }
//---------------------------------------------------------------------------------------------------------------------------------- /// Init dynamics //---------------------------------------------------------------------------------------------------------------------------------- void CARDYNAMICS::Init( class SETTINGS* pSet1, class Scene* pScene1, class FluidsXml* pFluids1, COLLISION_WORLD & world, const MODEL & chassisModel, const MODEL & wheelModelFront, const MODEL & wheelModelRear, const MATHVECTOR<Dbl,3> & position, const QUATERNION<Dbl> & orientation) { pSet = pSet1; pScene = pScene1; pFluids = pFluids1; this->world = &world; MATHVECTOR<Dbl,3> zero(0, 0, 0); body.SetPosition(position); body.SetOrientation(orientation); body.SetInitialForce(zero); body.SetInitialTorque(zero); // init engine engine.SetInitialConditions(); // init chassis btTransform tr; tr.setIdentity(); AABB <float> box = chassisModel.GetAABB(); for (int i = 0; i < 4; i++) { MATHVECTOR<float,3> wheelpos = GetLocalWheelPosition(WHEEL_POSITION(i), 0); const MODEL * wheelmodel = &wheelModelFront; if (i > 1) wheelmodel = &wheelModelRear; AABB <float> wheelaabb; float sidefactor = 1.0; if (i == 1 || i == 3) sidefactor = -1.0; wheelaabb.SetFromCorners( wheelpos - wheelmodel->GetAABB().GetSize() * 0.5 * sidefactor, wheelpos + wheelmodel->GetAABB().GetSize() * 0.5 * sidefactor); box.CombineWith(wheelaabb); } /// chassis shape --------------------------------------------------------- const MATHVECTOR<Dbl,3> verticalMargin(0, 0, 0.3); btVector3 origin = ToBulletVector(box.GetCenter() + verticalMargin - center_of_mass); btVector3 size = ToBulletVector(box.GetSize() - verticalMargin); //btCompoundShape * chassisShape = new btCompoundShape(false); #if 0 //btBoxShape * hull = new btBoxShape( btVector3(1.8,0.8,0.5) ); btBoxShape * hull = new btBoxShape( btVector3(1.7,0.7,0.3) ); tr.setOrigin(origin + btVector3(0,0,0.2)); chassisShape->addChildShape(tr, hull); #else /// todo: all params in .car // y| length x- width z^ height btScalar w = size.getX()*0.2, r = size.getZ()*0.3, h = 0.45; /// spheres btScalar l0 = 0.f, w0 = 0.f, h0 = 0.f; if (coll_R > 0.f) r = coll_R; l0 = coll_Lofs; if (coll_W > 0.f) w = coll_W; w0 = coll_Wofs; if (coll_H > 0.f) h = coll_H; h0 = coll_Hofs; origin = btVector3(l0, w0, h0); btScalar r2 = r*0.6; btScalar l1 = coll_posLfront, l2 = coll_posLback, l1m = l1*0.5, l2m = l2*0.5; //LogO("Car shape dims: r="+toStr(r)+" w="+toStr(w)+" h="+toStr(h)+" h0="+toStr(h0)); //LogO("Car offset: x="+toStr(origin.x())+" y="+toStr(origin.y())+" z="+toStr(origin.z())); const int numSph = 14; int i = 0; btScalar rad[numSph]; btVector3 pos[numSph]; pos[i] = btVector3( l1 , -w, -h); rad[i] = r2; ++i; // front pos[i] = btVector3( l1 , w, -h); rad[i] = r2; ++i; pos[i] = btVector3( l1m, -w, -h); rad[i] = r; ++i; // front near pos[i] = btVector3( l1m, w, -h); rad[i] = r; ++i; pos[i] = btVector3( l2m, -w, -h); rad[i] = r; ++i; // rear near pos[i] = btVector3( l2m, w, -h); rad[i] = r; ++i; pos[i] = btVector3( l2 , -w, -h); rad[i] = r2; ++i; // rear pos[i] = btVector3( l2 , w, -h); rad[i] = r2; ++i; pos[i] = btVector3( 0.4, -w*0.8, h*0.2); rad[i] = r2; ++i; // top pos[i] = btVector3( 0.4, w*0.8, h*0.2); rad[i] = r2; ++i; pos[i] = btVector3(-0.3, -w*0.8, h*0.4); rad[i] = r2; ++i; pos[i] = btVector3(-0.3, w*0.8, h*0.4); rad[i] = r2; ++i; pos[i] = btVector3(-1.1, -w*0.8, h*0.2); rad[i] = r2; ++i; // top rear pos[i] = btVector3(-1.1, w*0.8, h*0.2); rad[i] = r2; ++i; for (i=0; i < numSph; ++i) pos[i] += origin; btMultiSphereShape* chassisShape = new btMultiSphereShape(pos, rad, numSph); //chassisShape->setMargin(0.2f); #endif Dbl chassisMass = body.GetMass();// * 0.4; // Magic multiplier makes collisions better - problem: mud is very different MATRIX3 <Dbl> inertia = body.GetInertia(); btVector3 chassisInertia(inertia[0], inertia[4], inertia[8]); btTransform transform; transform.setOrigin(ToBulletVector(position)); transform.setRotation(ToBulletQuaternion(orientation)); btDefaultMotionState * chassisState = new btDefaultMotionState(); chassisState->setWorldTransform(transform); btRigidBody::btRigidBodyConstructionInfo info(chassisMass, chassisState, chassisShape, chassisInertia); info.m_angularDamping = ang_damp; info.m_restitution = 0.0; //... info.m_friction = coll_friction; /// 0.4~ 0.7 /// chasis^ chassis = world.AddRigidBody(info, true, pSet->game.collis_cars); chassis->setActivationState(DISABLE_DEACTIVATION); chassis->setUserPointer(new ShapeData(ST_Car, this, 0)); ///~~ world.AddAction(this); /// join chassis and wheel triggers //________________________________________________________ { for (int w=0; w < 4; ++w) { WHEEL_POSITION wp = WHEEL_POSITION(w); Dbl whR = GetWheel(wp).GetRadius() * 1.2; //bigger par.. MATHVECTOR<float,3> wheelpos = GetWheelPosition(wp, 0); //par wheelpos[0] += coll_Lofs; wheelpos[2] += coll_flTrig_H; btSphereShape* whSph = new btSphereShape(whR); //btCylinderShapeX* whSph = new btCylinderShapeX(btVector3(whR,whR,whR));//todo.. whTrigs = new btRigidBody(0.001f, 0, whSph); whTrigs->setUserPointer(new ShapeData(ST_Wheel, this, 0, w)); ///~~ whTrigs->setActivationState(DISABLE_DEACTIVATION); whTrigs->setCollisionFlags(whTrigs->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); world.world->addRigidBody(whTrigs); world.shapes.push_back(whSph); //todo: collision mask only to fluid triggers //todo: optimize- 1 constr only or none? //todo: cylinders? fixed constr\_ /*btTransform f1,f2; f1.setIdentity(); f2.setIdentity(); f1.setOrigin(ToBulletVector(wheelpos)); btGeneric6DofConstraint* constr = new btGeneric6DofConstraint(*chassis, *whTrigs, f1, f2, true); constr->setLimit(0,0,0); constr->setLimit(1,0,1); constr->setLimit(2,0,0); //constr->setLimit(3,0,0); //constr->setLimit(4,0,0); constr->setLimit(5,0,0);/*??*/ btTypedConstraint* constr = new btPoint2PointConstraint(*chassis, *whTrigs, ToBulletVector(wheelpos), btVector3(0,0,0)); world.world->addConstraint(constr, true); world.constraints.push_back(constr); } /// init poly for buoyancy computations //________________________________________________________ if (poly == NULL) { poly = new Polyhedron(); poly->numVerts = 8; poly->numFaces = 12; poly->verts = new Vec3[8]; poly->faces = new Face[12]; float hx = 1.2f, hy = 0.7f, hz = 0.4f; // box dim poly->verts[0] = Vec3(-hx,-hy,-hz); poly->verts[1] = Vec3(-hx,-hy, hz); poly->verts[2] = Vec3(-hx, hy,-hz); poly->verts[3] = Vec3(-hx, hy, hz); poly->verts[4] = Vec3( hx,-hy,-hz); poly->verts[5] = Vec3( hx,-hy, hz); poly->verts[6] = Vec3( hx, hy,-hz); poly->verts[7] = Vec3( hx, hy, hz); poly->faces[0] = Face(0,1,3); poly->faces[1] = Face(0,3,2); poly->faces[2] = Face(6,3,7); poly->faces[3] = Face(6,2,3); poly->faces[4] = Face(4,6,5); poly->faces[5] = Face(6,7,5); poly->faces[6] = Face(4,5,0); poly->faces[7] = Face(0,5,1); poly->faces[8] = Face(5,7,1); poly->faces[9] = Face(7,3,1); poly->faces[10]= Face(0,6,4); poly->faces[11]= Face(0,2,6); poly->length = 1.0f; // approx. length-? poly->volume = ComputeVolume(*poly); body_mass = 1900.0f * 2.688; //poly->volume; // car density body_inertia = (4.0f * body_mass / 12.0f) * btVector3(hy*hz, hx*hz, hx*hy); } } //------------------------------------------------------------- // init wheels, suspension for (int i = 0; i < WHEEL_POSITION_SIZE; i++) { wheel[WHEEL_POSITION(i)].SetInitialConditions(); wheel_velocity[i].Set(0.0); wheel_position[i] = GetWheelPositionAtDisplacement(WHEEL_POSITION(i), 0); wheel_orientation[i] = orientation * GetWheelSteeringAndSuspensionOrientation(WHEEL_POSITION(i)); } AlignWithGround();//-- }
void CVehicleDamageBehaviorBlowTire::DamagePlayers() { // check for the nasty case when the player is shooting at the vehicle tires while prone // under or behind the car, In that case the player should get killed by the vehicle, // otherwise he gets stuck forever. Note that he should only get killed when the tier // is actually destroyed and not by collision resulting by the impulse added by just // shooting at the tiers. Unfortunately using physics for doing this check is not reliable // enough so we have to check it explicitly IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy*)m_pVehicle->GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS); if (!pPhysicsProxy) return; AABB bbox; pPhysicsProxy->GetWorldBounds( bbox ); IPhysicalWorld *pWorld = gEnv->pSystem->GetIPhysicalWorld(); IPhysicalEntity **ppColliders; // check entities in collision with the car int cnt = pWorld->GetEntitiesInBox( bbox.min,bbox.max, ppColliders,ent_living); for (int i = 0; i < cnt; i++) { IEntity *pEntity = gEnv->pEntitySystem->GetEntityFromPhysics( ppColliders[i] ); if (!pEntity) continue; // skip the vehicle itself if (pEntity==m_pVehicle->GetEntity()) continue; IPhysicalEntity *pPhysEnt = pEntity->GetPhysics(); if (!pPhysEnt) continue; IActor* pActor = gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId()); if(!pActor) continue; //Jan M.: the player is killed when he entered the vehicle while prone although he is still passenger! if(m_pVehicle == pActor->GetLinkedVehicle()) continue; //the player must be prone under the vehicle IAnimatedCharacter * animatedCharacter=pActor->GetAnimatedCharacter(); if (!animatedCharacter) continue; int stance = animatedCharacter->GetCurrentStance(); if (stance!=STANCE_PRONE) continue; pe_player_dimensions dim; if (!pPhysEnt->GetParams(&dim)) continue; // position returned is at entity's feet, add head position from physics Vec3 vPos1=pEntity->GetPos(); vPos1.z = vPos1.z + dim.heightHead; float fZ=bbox.GetCenter().z; if (vPos1.z>fZ) continue; // not under the vehicle // at this point we have a collision with the car moving down and the guy prone under the car, it is safe // to assume he has been squished so let's kill him. if (gEnv->bServer && pActor->GetHealth()>0) { // adding a server hit to make it working in MP IGameRules *pGameRules = gEnv->pGame->GetIGameFramework()->GetIGameRulesSystem()->GetCurrentGameRules(); if (pGameRules) { HitInfo hit; EntityId shooterId=m_pVehicle->GetEntityId(); if (m_pVehicle->GetDriver()) shooterId=m_pVehicle->GetDriver()->GetEntityId(); hit.targetId = pEntity->GetId(); hit.shooterId = shooterId; hit.weaponId = m_pVehicle->GetEntityId(); hit.damage = 1000.f; hit.type = 0; hit.pos = pActor->GetEntity()->GetWorldPos(); pGameRules->ServerHit(hit); } } } //i }
//----------------------------------------------------------------------- void gkAuxRenderer::AuxRenderAABB( const AABB& aabb, ColorF& color /*= ColorF(1.0,1.0,1.0,1.0)*/, bool ignoreZ ) { //Vec3 vecAABB = aabb.GetCenter(); AuxRender3DBoxFrame( aabb.GetCenter(), aabb.GetSize(), color, ignoreZ ); }
/// Used to update any time dependent state (such as timeouts) void CFlowNode_FeatureTest::Update(float deltaTime) { if(m_running) { m_timeRunning += deltaTime; CryWatch("$7[FG FeatureTest]$o Running test '%s'", Name()); const string &description = GetPortString(&m_actInfo, eInputPorts_Description); if(!description.empty()) CryWatch("$7[FG FeatureTest]$o %s", description.c_str()); const float maxTime = GetPortFloat(&m_actInfo, eInputPorts_MaxTime); IEntity *pFollowEntity = NULL; // Firstly, attempt to get the camera entity (index: -1) bool bHasEntry = GetEntityAtIndex(-1, pFollowEntity); if(!bHasEntry && !pFollowEntity) { // If there's an entity being tested, force the view camera to follow it (if no camera entity defined) // This needs to be implemented in a cleaner way and allow other options for non-entity based tests. bHasEntry = GetEntityAtIndex(m_entitySeqIndex, pFollowEntity); // If no sequence entity defined if(!bHasEntry && !pFollowEntity) { // Look for another suitable (active) entity to follow for(int i = 0; i < SEQ_ENTITY_COUNT; ++i) { GetEntityAtIndex(i, pFollowEntity); if(pFollowEntity && pFollowEntity->IsActive()) { break; } } } } if(pFollowEntity) { CCamera &viewCamera = gEnv->pSystem->GetViewCamera(); Vec3 vPos(0,0,0); Vec3 vDir(0,0,0); AABB bounds; pFollowEntity->GetWorldBounds(bounds); Vec3 vTarget; vTarget = bounds.GetCenter(); vPos = vTarget + (pFollowEntity->GetForwardDir().GetNormalizedSafe() * -2.5f) + Vec3(0.0f, 0.0f, 1.0f); vDir = (vTarget - vPos).GetNormalizedSafe(); float fRoll(0.0f); viewCamera.SetMatrix(CCamera::CreateOrientationYPR(CCamera::CreateAnglesYPR(vDir, fRoll))); viewCamera.SetPosition(vPos); } // If a valid max time has been set if(maxTime > 0.0f) { // If test has exceeded max time if(m_timeRunning >= maxTime) { OnTestResult(false, string().Format("Test failed: Test exceeded maximum time (%f).", maxTime).c_str()); } } } }
void CGame::Draw() { Vector vecForward = m_hPlayer->GetGlobalView(); Vector vecUp(0, 1, 0); // Cross-product http://www.youtube.com/watch?v=FT7MShdqK6w Vector vecRight = vecUp.Cross(vecForward).Normalized(); CRenderer* pRenderer = GetRenderer(); // Tell the renderer how to set up the camera. pRenderer->SetCameraPosition(m_hPlayer->GetGlobalOrigin() - vecForward * 6 + vecUp * 3 - vecRight * 0.5f); pRenderer->SetCameraDirection(vecForward); pRenderer->SetCameraUp(Vector(0, 1, 0)); pRenderer->SetCameraFOV(90); pRenderer->SetCameraNear(0.1f); pRenderer->SetCameraFar(1000); // This rendering context is a tool for rendering things to the screen. // All of our drawing commands are part of it. CRenderingContext r(pRenderer); // Clear the depth buffer and set a background color. r.ClearDepth(); r.ClearColor(Color(210, 230, 255)); // CRenderer::StartRendering() - This function sets up OpenGL with the // camera information that we passed it before. pRenderer->StartRendering(&r); m_oFrameFrustum = CFrustum(r.GetProjection() * r.GetView()); // First tell OpenGL what "shader" or "program" to use. r.UseProgram("model"); // Set the sunlight direction. The y component is -1 so the light is pointing down. Vector vecSunlight = Vector(1, -1, 1).Normalized(); // Uncomment this code to make the sunlight rotate: //Vector vecSunlight = Vector(cos(Game()->GetTime()), -1, sin(Game()->GetTime())).Normalized(); r.SetUniform("vecSunlight", vecSunlight); r.SetUniform("bLighted", false); r.SetUniform("bDiffuse", false); // Render the ground. r.SetUniform("vecColor", Vector4D(0.6f, 0.7f, 0.9f, 1)); r.SetUniform("vecCameraPosition", GetRenderer()->GetCameraPosition()); r.BeginRenderTriFan(); r.Normal(Vector(0, 1, 0)); r.Tangent(Vector(1, 0, 0)); r.Bitangent(Vector(0, 0, 1)); r.TexCoord(Vector2D(0, 1)); r.Vertex(Vector(-30, 0, -30)); r.TexCoord(Vector2D(0, 0)); r.Vertex(Vector(-30, 0, 30)); r.TexCoord(Vector2D(1, 0)); r.Vertex(Vector(30, 0, 30)); r.TexCoord(Vector2D(1, 1)); r.Vertex(Vector(30, 0, -30)); r.EndRender(); r.SetUniform("bLighted", true); // Prepare a list of entities to render. m_apRenderOpaqueList.clear(); m_apRenderTransparentList.clear(); for (size_t i = 0; i < MAX_CHARACTERS; i++) { CCharacter* pCharacter = GetCharacterIndex(i); if (!pCharacter) continue; // We need to scale the AABB using the character's scale values before we can use it to calculate our center/radius. AABB aabbSizeWithScaling = pCharacter->m_aabbSize * pCharacter->m_vecScaling; Vector vecCharacterCenter = pCharacter->GetGlobalOrigin() + aabbSizeWithScaling.GetCenter(); float flCharacterRadius = aabbSizeWithScaling.GetRadius(); // If the entity is outside the viewing frustum then the player can't see it - don't draw it. // http://youtu.be/4p-E_31XOPM if (!m_oFrameFrustum.SphereIntersection(vecCharacterCenter, flCharacterRadius)) continue; if (pCharacter->m_bDrawTransparent) m_apRenderTransparentList.push_back(pCharacter); else m_apRenderOpaqueList.push_back(pCharacter); } // Draw all opaque characters first. DrawCharacters(m_apRenderOpaqueList, false); for (size_t i = 0; i < MAX_CHARACTERS; i++) { CCharacter* pCharacter = GetCharacterIndex(i); if (!pCharacter) continue; if (!pCharacter->m_bEnemyAI) continue; float flRadius = 3.5f; Vector vecIndicatorOrigin = NearestPointOnSphere(m_hPlayer->GetGlobalOrigin(), flRadius, pCharacter->GetGlobalOrigin()); float flBoxSize = 0.1f; r.SetUniform("vecColor", Color(255, 0, 0, 255)); r.RenderBox(vecIndicatorOrigin - Vector(1, 1, 1)*flBoxSize, vecIndicatorOrigin + Vector(1, 1, 1)*flBoxSize); } // Sort the transparent render list so that we paint the items farther from the camera first. http://youtu.be/fEjZrwDKdi8 MergeSortTransparentRenderList(); // Now draw all transparent characters, sorted by distance from the camera. DrawCharacters(m_apRenderTransparentList, true); r.SetUniform("bDiffuse", false); // Render any bullet tracers that may have been created. float flBulletTracerTime = 0.1f; for (size_t i = 0; i < Game()->GetTracers().size(); i++) { if (Game()->GetTime() < Game()->GetTracers()[i].flTimeCreated + flBulletTracerTime) { Vector vecStart = Game()->GetTracers()[i].vecStart; Vector vecEnd = Game()->GetTracers()[i].vecEnd; r.SetUniform("vecColor", Vector4D(1, 0.9f, 0, 1)); r.BeginRenderLines(); r.Normal(Vector(0, 1, 0)); r.Vertex(vecStart); r.Vertex(vecEnd); r.EndRender(); } } // Render any puffs that may have been created. float flPuffTime = 0.3f; for (size_t i = 0; i < Game()->GetPuffs().size(); i++) { if (Game()->GetTime() < Game()->GetPuffs()[i].flTimeCreated + flPuffTime) { float flTimeCreated = Game()->GetPuffs()[i].flTimeCreated; float flTimeOver = Game()->GetPuffs()[i].flTimeCreated + flPuffTime; float flStartSize = 0.2f; float flEndSize = 2.0f; float flSize = Remap(Game()->GetTime(), flTimeCreated, flTimeOver, flStartSize, flEndSize); Vector vecOrigin = Game()->GetPuffs()[i].vecOrigin; int iOrange = (int)Remap(Game()->GetTime(), flTimeCreated, flTimeOver, 0, 255); r.SetUniform("vecColor", Color(255, iOrange, 0, 255)); r.RenderBox(vecOrigin - Vector(1, 1, 1)*flSize, vecOrigin + Vector(1, 1, 1)*flSize); } } GraphDraw(); pRenderer->FinishRendering(&r); // Call this last. Your rendered stuff won't appear on the screen until you call this. Application()->SwapBuffers(); }
void CAutoAimManager::UpdateTargetInfo(SAutoaimTarget& aaTarget, float fFrameTime) { IEntity * pTargetEntity = gEnv->pEntitySystem->GetEntity(aaTarget.entityId); if(pTargetEntity) { CActorPtr pTargetActor = aaTarget.pActorWeak.lock(); if (pTargetActor) { Vec3 characterPos; Quat characterRot; //Need this because of decouple catch-up movement if (IAnimatedCharacter* pAnimatedCharacter = pTargetActor->GetAnimatedCharacter()) { const QuatT& animationLocation = pAnimatedCharacter->GetAnimLocation(); characterPos = animationLocation.t; characterRot = animationLocation.q; } else { const Matrix34& targetWorldTM = pTargetEntity->GetWorldTM(); //Fallback to entity position characterPos = targetWorldTM.GetTranslation(); characterRot = Quat(targetWorldTM); } Vec3 primaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); Vec3 secondaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); if (aaTarget.primaryBoneId >= 0) { if (pTargetActor->HasBoneID(aaTarget.primaryBoneId)) { primaryOffset = pTargetActor->GetBoneTransform(aaTarget.primaryBoneId).t; } else { GameWarning("CAutoAimManager: Character %s missing primary boneID: %s", pTargetEntity->GetName(), s_BONE_ID_NAME[aaTarget.primaryBoneId]); aaTarget.primaryBoneId = -1; } } if (aaTarget.secondaryBoneId >= 0) { if (pTargetActor->HasBoneID(aaTarget.secondaryBoneId)) { secondaryOffset = pTargetActor->GetBoneTransform(aaTarget.secondaryBoneId).t; } else { GameWarning("CAutoAimManager: Character %s missing secondary boneID: %s", pTargetEntity->GetName(), s_BONE_ID_NAME[aaTarget.secondaryBoneId]); aaTarget.secondaryBoneId = -1; } } aaTarget.primaryAimPosition = characterPos + (characterRot * primaryOffset); aaTarget.secondaryAimPosition = characterPos + (characterRot * secondaryOffset); //Update hostility (changes during gameplay) if (!gEnv->bMultiplayer) { uint8 targetFaction = (aaTarget.aiFaction != IFactionMap::InvalidFactionID) ? aaTarget.aiFaction : GetTargetFaction(*pTargetEntity); if (gEnv->pAISystem->GetFactionMap().GetReaction(GetLocalPlayerFaction(), aaTarget.aiFaction) == IFactionMap::Hostile) { aaTarget.SetFlag(eAATF_AIHostile); } else { aaTarget.RemoveFlag(eAATF_AIHostile); } aaTarget.aiFaction = targetFaction; } } else if(aaTarget.hasSkeleton) { //Not an actor but has a skeleton (and so can use bone offsets) ISkeletonPose* pSkeletonPose = pTargetEntity->GetCharacter(0)->GetISkeletonPose(); const Matrix34& characterMat = pTargetEntity->GetWorldTM(); const Vec3 characterPos = characterMat.GetTranslation(); const Quat characterRot(characterMat); Vec3 primaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); Vec3 secondaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); if (aaTarget.primaryBoneId >= 0) { primaryOffset = pSkeletonPose->GetAbsJointByID(aaTarget.primaryBoneId).t; } if (aaTarget.secondaryBoneId >= 0) { secondaryOffset = pSkeletonPose->GetAbsJointByID(aaTarget.secondaryBoneId).t; } aaTarget.primaryAimPosition = characterPos + (characterRot * primaryOffset); aaTarget.secondaryAimPosition = characterPos + (characterRot * secondaryOffset); } else { //Must be an object const Matrix34& entityWorldTM = pTargetEntity->GetWorldTM(); Vec3 primaryPosition = entityWorldTM.GetTranslation(); Vec3 secondaryPosition = entityWorldTM.TransformPoint(Vec3(0.0f, 0.0f, 0.5f)); AABB entityLocalBBox; pTargetEntity->GetLocalBounds(entityLocalBBox); if (!entityLocalBBox.IsEmpty()) { const Vec3 offset (0.0f, 0.0f, entityLocalBBox.GetRadius() * 0.2f); const Vec3 objectCenter = entityLocalBBox.GetCenter(); primaryPosition = entityWorldTM.TransformPoint((objectCenter - offset)); secondaryPosition = entityWorldTM.TransformPoint((objectCenter + offset)); } aaTarget.primaryAimPosition = primaryPosition; aaTarget.secondaryAimPosition = secondaryPosition; } //The physics drags the render proxy and entity behind it. If we auto aim at the render position, // we will handicap the console players by failing to let them aim ahead of the target. if(IPhysicalEntity * pPhysicalEntity = pTargetEntity->GetPhysics()) { pe_status_dynamics dyn; if(pPhysicalEntity->GetStatus(&dyn)) { Vec3 lookAhead = (dyn.v * fFrameTime); aaTarget.primaryAimPosition = aaTarget.primaryAimPosition + lookAhead; aaTarget.secondaryAimPosition = aaTarget.secondaryAimPosition + lookAhead; } } } }
bool CDialogActorContext::DoLocalPlayerChecks(const float dt) { // don't check this every frame, but only every .2 secs m_checkPlayerTimeOut-=dt; if (m_checkPlayerTimeOut <= 0.0f) { do // a dummy loop to use break { float awareDistance; float awareDistanceSq; float awareAngle; m_pSession->GetPlayerAwarenessValues(awareDistance, awareAngle); awareDistanceSq=awareDistance*awareDistance; m_checkPlayerTimeOut = PLAYER_CHECKTIME; const float spotAngleCos = cos_tpl(DEG2RAD(awareAngle)); const CDialogSession::TActorContextMap& contextMap = m_pSession->GetAllContexts(); if (contextMap.size() == 1 && contextMap.begin()->first == m_actorID) { m_bIsAware = true; break; } // early out, when we don't have to do any checks if (awareDistance <= 0.0f && awareAngle <= 0.0f) { m_bIsAware = true; break; } IEntity* pThisEntity = m_pSession->GetActorEntity(m_actorID); if (!pThisEntity) { assert (false); m_bIsAware = true; break; } IMovementController* pMC = (m_pIActor != NULL) ? m_pIActor->GetMovementController() : NULL; if (!pMC) { assert (false); m_bIsAware = true; break; } SMovementState moveState; pMC->GetMovementState(moveState); Vec3 viewPos = moveState.eyePosition; Vec3 viewDir = moveState.eyeDirection; viewDir.z = 0.0f; viewDir.NormalizeSafe(); // check the player's position // check the player's view direction AABB groupBounds; groupBounds.Reset(); CDialogSession::TActorContextMap::const_iterator iter = contextMap.begin(); CDialogScript::SActorSet lookingAt = 0; while (iter != contextMap.end()) { if (iter->first != m_actorID) { IEntity* pActorEntity = m_pSession->GetActorEntity(iter->first); if (pActorEntity) { Vec3 vEntityPos = pActorEntity->GetWorldPos(); AABB worldBounds; pActorEntity->GetWorldBounds(worldBounds); groupBounds.Add(worldBounds); // calc if we look at it somehow Vec3 vEntityDir = vEntityPos - viewPos; vEntityDir.z = 0.0f; vEntityDir.NormalizeSafe(); if (viewDir.IsUnit() && vEntityDir.IsUnit()) { const float dot = clamp_tpl(viewDir.Dot(vEntityDir),-1.0f,+1.0f); // clamping should not be needed if (spotAngleCos <= dot) lookingAt.SetActor(iter->first); DiaLOG::Log(DiaLOG::eDebugC, "Angle to actor %d is %f deg", iter->first, RAD2DEG(acos_tpl(dot))); } } } ++iter; } const float distanceSq = pThisEntity->GetWorldPos().GetSquaredDistance(groupBounds.GetCenter()); CCamera& camera=gEnv->pSystem->GetViewCamera(); const bool bIsInAABB = camera.IsAABBVisible_F(groupBounds); const bool bIsInRange = distanceSq <= awareDistanceSq; const bool bIsLooking = contextMap.empty() || lookingAt.NumActors() > 0; m_bIsAwareLooking = awareAngle <= 0.0f || (bIsInAABB || bIsLooking); m_bIsAwareInRange = awareDistance <= 0.0f || bIsInRange; m_bIsAware = m_bIsAwareLooking && m_bIsAwareInRange; DiaLOG::Log(DiaLOG::eDebugB, "[DIALOG] LPC: %s awDist=%f awAng=%f AABBVis=%d IsLooking=%d InRange=%d [Distance=%f LookingActors=%d] Final=%saware", m_pSession->GetDebugName(), awareDistance, awareAngle, bIsInAABB, bIsLooking, bIsInRange, sqrt_tpl(distanceSq), lookingAt.NumActors(), m_bIsAware ? "" : "not "); } while (false); } if (m_bIsAware) { m_playerAwareTimeOut = m_pSession->GetPlayerAwarenessGraceTime(); } else { m_playerAwareTimeOut-= dt; if (m_playerAwareTimeOut <= 0) { return false; } } return true; }
void ShadowSystem::ProcessEntity(ECS::Entity* p_entity) { Transform* transform = m_transforms.Get(p_entity); Shadowcaster* shadowcaster = m_shadowcasters.Get(p_entity); Render::Shadowcaster sc; Orientation tOr = transform->m_orientation; tOr.Yaw(180.0f); glm::mat4 tempWorldMatrix; tempWorldMatrix = glm::translate(glm::mat4(1.0f), transform->m_position); tempWorldMatrix = glm::rotate(tempWorldMatrix, tOr.GetAngle(), tOr.GetAxis()); tempWorldMatrix = glm::scale(tempWorldMatrix, transform->m_scale); glm::mat4 lightSpace = glm::inverse(tempWorldMatrix); m_maxWorldX = -99999; m_minWorldX = 99999; m_maxWorldY = -99999; m_minWorldY = 99999; m_maxWorldZ = -99999; m_minWorldZ = 99999; for(int i = 0; i < 8; i++) { glm::vec4 cornerInLightSpace = lightSpace * glm::vec4(worldCorners[i], 1.0f); if(cornerInLightSpace.x < m_minWorldX) { m_minWorldX = cornerInLightSpace.x; } if(cornerInLightSpace.x > m_maxWorldX) { m_maxWorldX = cornerInLightSpace.x; } if(cornerInLightSpace.y < m_minWorldY) { m_minWorldY = cornerInLightSpace.y; } if(cornerInLightSpace.y > m_maxWorldY) { m_maxWorldY = cornerInLightSpace.y; } if(cornerInLightSpace.z < m_minWorldZ) { m_minWorldZ = cornerInLightSpace.z; } if(cornerInLightSpace.z > m_maxWorldZ) { m_maxWorldZ = cornerInLightSpace.z; } } glm::mat4 lazyOrthoAroundMap = glm::ortho(m_minWorldX, m_maxWorldX, m_minWorldY, m_maxWorldY, -m_maxWorldZ, -m_minWorldZ); // Get the eye camera. ECS::Entity* cameraEntity = m_world->GetTagManager()->GetEntityByTag("Camera"); RootForce::Camera* camera = m_world->GetEntityManager()->GetComponent<RootForce::Camera>(cameraEntity); Frustum frustum = camera->m_frustum; glm::vec4 frustumCorners[8]; frustumCorners[0] = glm::vec4(frustum.ntl, 1.0f); frustumCorners[1] = glm::vec4(frustum.ntr, 1.0f); frustumCorners[2] = glm::vec4(frustum.nbl, 1.0f); frustumCorners[3] = glm::vec4(frustum.nbr, 1.0f); frustumCorners[4] = glm::vec4(frustum.ftl, 1.0f); frustumCorners[5] = glm::vec4(frustum.ftr, 1.0f); frustumCorners[6] = glm::vec4(frustum.fbl, 1.0f); frustumCorners[7] = glm::vec4(frustum.fbr, 1.0f); // Convert camera frustrum to view space. for(int i = 0; i < 8; i++) { frustumCorners[i] = camera->m_viewMatrix * frustumCorners[i]; } // Calculate directions. glm::vec3 directions[4]; for(int i = 0; i < 4; i++) { directions[i].x = glm::normalize(frustumCorners[i+4].x - frustumCorners[i].x); directions[i].y = glm::normalize(frustumCorners[i+4].y - frustumCorners[i].y); directions[i].z = glm::normalize(frustumCorners[i+4].z - frustumCorners[i].z); } static glm::vec4 localOBB[8] = { glm::vec4(-1.0f, -1.0f, -1.0f, 1.0f), glm::vec4(1.0f, -1.0f, -1.0f, 1.0f), glm::vec4(1.0f, 1.0f, -1.0f, 1.0f), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), glm::vec4(-1.0f, 1.0f, -1.0f, 1.0f), glm::vec4(-1.0f, 1.0f, 1.0f, 1.0f), glm::vec4(-1.0f, -1.0f, 1.0f, 1.0f), glm::vec4(1.0f, -1.0f, 1.0f, 1.0f) }; if(RENDER_SHADOW_CASCADES >= 4) { // Define near/far planes for the sub frustrums. float _near[4]; _near[0] = camera->m_frustum.m_near; _near[1] = 8.0f; //Daniel's 2k-values: 15, 60, 200 _near[2] = 40.0f; _near[3] = 150.0f; float _far[4]; _far[0] = _near[1]; _far[1] = _near[2]; _far[2] = _near[3]; _far[3] = camera->m_frustum.m_far; // Create cascades. for(int i = 0; i < RENDER_SHADOW_CASCADES; i++) { AABB boundingbox; for(int p = 0; p < 4; p++) { glm::vec3 nearCorner; nearCorner = glm::swizzle<glm::X, glm::Y, glm::Z>(frustumCorners[p]); boundingbox.Expand(nearCorner + directions[p] * _near[i]); boundingbox.Expand(nearCorner + directions[p] * _far[i]); } glm::vec3 center = boundingbox.GetCenter(); glm::vec3 centerInWorldSpace = glm::swizzle<glm::X, glm::Y, glm::Z>(glm::inverse(camera->m_viewMatrix) * glm::vec4(center, 1.0f)); glm::vec4 centerInViewSpace = lightSpace * glm::vec4(centerInWorldSpace, 1.0f); float nearPlane = 1.0f; float lookAtDistance = glm::length(centerInViewSpace - 2000.0f) + nearPlane; float radius = glm::length(center - glm::vec3(boundingbox.m_maxX, boundingbox.m_maxY, boundingbox.m_maxZ)); float farPlane = lookAtDistance + radius; sc.m_projectionMatrices[i] = glm::ortho(-radius, radius, -radius, radius, nearPlane, farPlane); sc.m_viewMatrices[i] = glm::lookAt(centerInWorldSpace + tOr.GetFront() * lookAtDistance, centerInWorldSpace - tOr.GetFront() * lookAtDistance, tOr.GetUp()); sc.m_viewProjections[i] = sc.m_projectionMatrices[i] * sc.m_viewMatrices[i]; } sc.m_projectionMatrices[RENDER_SHADOW_CASCADES-1] = OrthoProjectionFromFrustum(&camera->m_frustum, lightSpace); sc.m_viewMatrices[RENDER_SHADOW_CASCADES-1] = lightSpace; sc.m_viewProjections[RENDER_SHADOW_CASCADES-1] = sc.m_projectionMatrices[RENDER_SHADOW_CASCADES-1] * sc.m_viewMatrices[RENDER_SHADOW_CASCADES-1]; } else { sc.m_projectionMatrices[RENDER_SHADOW_CASCADES-1] = lazyOrthoAroundMap; sc.m_viewMatrices[RENDER_SHADOW_CASCADES-1] = lightSpace; sc.m_viewProjections[RENDER_SHADOW_CASCADES-1] = sc.m_projectionMatrices[RENDER_SHADOW_CASCADES-1] * sc.m_viewMatrices[RENDER_SHADOW_CASCADES-1]; } g_engineContext.m_renderer->AddShadowcaster(sc, (int)shadowcaster->m_directionalLightSlot); }