void CLaserBeam::UpdateLaserGeometry( IEntity& laserEntity ) { // Scale the laser based on the distance. const float assetLengthInv = 0.5f; const float bias = g_pGameCVars->i_laser_hitPosOffset; const float finalLaserLen = m_hasHitData ? max(0.f, m_lastLaserUpdatePosition.GetDistance(GetLastHit()) - bias) : 0.001f; const float scale = finalLaserLen * assetLengthInv; const float thickness = m_pLaserParams->laser_thickness[GetIndexFromGeometrySlot()]; const Quat inverseWorldQuat(laserEntity.GetWorldRotation().GetInverted()); Vec3 localSpaceDirection = inverseWorldQuat * m_lastLaserUpdateDirection; const Vec3 finalHitPos = localSpaceDirection * finalLaserLen; const Matrix34 localLaserMatrix = Matrix33::CreateOrientation(localSpaceDirection, Vec3(0.f, 0.f, 1.f), 0.f) * Matrix34::CreateScale(Vec3(thickness, scale, thickness)); laserEntity.SetSlotLocalTM(m_laserGeometrySlot, localLaserMatrix); // Set Dot matrix if (m_hitSolid) { const Matrix34 mt = Matrix34::CreateTranslationMat(finalHitPos); laserEntity.SetSlotLocalTM(m_laserDotSlot, mt); } else { Matrix34 scaleMatrix; scaleMatrix.SetIdentity(); scaleMatrix.SetScale(Vec3(0.001f,0.001f,0.001f)); laserEntity.SetSlotLocalTM(m_laserDotSlot, scaleMatrix); } }
//------------------------------------------------------------------- void CLam::UpdateLaserScale(float scaleLenght,IEntity* pLaserEntity) { if(pLaserEntity) { Matrix34 tm; tm.SetIdentity(); tm.SetScale(Vec3(1.0f,scaleLenght,1.0f)); pLaserEntity->SetLocalTM(tm); } }
//------------------------------------------------------------------ void CLam::UpdateTPLaser(float frameTime, CItem* parent) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); const int frameId = gEnv->pRenderer->GetFrameID(); if (s_lastUpdateFrameId != frameId) { // Check how many LAMs to update this frame. float dt = frameTime; // + s_laserUpdateTimeError; const int n = s_lasers.size(); int nActive = 0; for (int i = 0; i < n; ++i) { if (!s_lasers[i]->IsLaserActivated() && !s_lasers[i]->IsLightActivated()) continue; nActive++; } float updatedPerSecond = (nActive / LASER_UPDATE_TIME) + s_laserUpdateTimeError; int updateCount = (int)floorf(updatedPerSecond * dt); if(dt==0.0f) s_laserUpdateTimeError = 0.0f; else s_laserUpdateTimeError = updatedPerSecond - updateCount/dt; s_curLaser %= n; for (int i = 0, j = 0; i < n && j < updateCount ; ++i) { s_curLaser = (s_curLaser + 1) % n; if (!s_lasers[s_curLaser]->IsLaserActivated() && !s_lasers[s_curLaser]->IsLightActivated()) continue; s_lasers[s_curLaser]->SetAllowUpdate(); ++j; } s_lastUpdateFrameId = frameId; } IEntity* pRootEnt = GetEntity(); if (!pRootEnt) return; IEntity *pLaserEntity = m_pEntitySystem->GetEntity(m_pLaserEntityId); // if(!pLaserEntity) // return; const CCamera& camera = gEnv->pRenderer->GetCamera(); Vec3 lamPos = pRootEnt->GetWorldPos(); //pLaserEntity->GetParent()->GetWorldPos(); Vec3 dir = pRootEnt->GetWorldRotation().GetColumn1(); //pLaserEntity->GetParent()->GetWorldRotation().GetColumn1(); bool charNotVisible = false; float dsg1Scale = 1.0f; //If character not visible, laser is not correctly updated if(parent) { if(CActor* pOwner = parent->GetOwnerActor()) { ICharacterInstance* pCharacter = pOwner->GetEntity()->GetCharacter(0); if(pCharacter && !pCharacter->IsCharacterVisible()) charNotVisible = true; } if(parent->GetEntity()->GetClass()==CItem::sDSG1Class) dsg1Scale = 3.0f; } // if (!pLaserEntity->GetParent()) // return; Vec3 hitPos(0,0,0); float laserLength = 0.0f; // HACK??: Use player movement controller locations, or else the laser // pops all over the place when character out of the screen. CActor *pActor = parent->GetOwnerActor(); if (pActor && (!pActor->IsPlayer() || charNotVisible)) { if (IMovementController* pMC = pActor->GetMovementController()) { SMovementState state; pMC->GetMovementState(state); if(!charNotVisible) lamPos = state.weaponPosition; else { float oldZPos = lamPos.z; lamPos = state.weaponPosition; if(m_lastZPos>0.0f) lamPos.z = m_lastZPos; //Stabilize somehow z position (even if not accurate) else lamPos.z = oldZPos; } const float angleMin = DEG2RAD(3.0f); const float angleMax = DEG2RAD(7.0f); const float thr = cosf(angleMax); float dot = dir.Dot(state.aimDirection); if (dot > thr) { float a = acos_tpl(dot); float u = 1.0f - clamp((a - angleMin) / (angleMax - angleMin), 0.0f, 1.0f); dir = dir + u * (state.aimDirection - dir); dir.Normalize(); } } } if(!charNotVisible) m_lastZPos = lamPos.z; lamPos += (dir*0.10f); if (m_allowUpdate) { m_allowUpdate = false; IPhysicalEntity* pSkipEntity = NULL; if(parent->GetOwner()) pSkipEntity = parent->GetOwner()->GetPhysics(); const float range = m_lamparams.laser_range[eIGS_ThirdPerson]*dsg1Scale; // Use the same flags as the AI system uses for visbility. const int objects = ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_independent; //ent_living; const int flags = (geom_colltype_ray << rwi_colltype_bit) | rwi_colltype_any | (10 & rwi_pierceability_mask) | (geom_colltype14 << rwi_colltype_bit); ray_hit hit; if (gEnv->pPhysicalWorld->RayWorldIntersection(lamPos, dir*range, objects, flags, &hit, 1, &pSkipEntity, pSkipEntity ? 1 : 0)) { laserLength = hit.dist; m_lastLaserHitPt = hit.pt; m_lastLaserHitSolid = true; } else { m_lastLaserHitSolid = false; m_lastLaserHitPt = lamPos + dir * range; laserLength = range + 0.1f; } // Hit near plane if (dir.Dot(camera.GetViewdir()) < 0.0f) { Plane nearPlane; nearPlane.SetPlane(camera.GetViewdir(), camera.GetPosition()); nearPlane.d -= camera.GetNearPlane()+0.15f; Ray ray(lamPos, dir); Vec3 out; m_lastLaserHitViewPlane = false; if (Intersect::Ray_Plane(ray, nearPlane, out)) { float dist = Distance::Point_Point(lamPos, out); if (dist < laserLength) { laserLength = dist; m_lastLaserHitPt = out; m_lastLaserHitSolid = true; m_lastLaserHitViewPlane = true; } } } hitPos = m_lastLaserHitPt; } else { laserLength = Distance::Point_Point(m_lastLaserHitPt, lamPos); hitPos = lamPos + dir * laserLength; } if (m_smoothLaserLength < 0.0f) m_smoothLaserLength = laserLength; else { if (laserLength < m_smoothLaserLength) m_smoothLaserLength = laserLength; else m_smoothLaserLength += (laserLength - m_smoothLaserLength) * min(1.0f, 10.0f * frameTime); } float laserAIRange = 0.0f; if (m_laserActivated && pLaserEntity) { // Orient the laser towards the point point. Matrix34 parentTMInv; parentTMInv = pRootEnt->GetWorldTM().GetInverted(); Vec3 localDir = parentTMInv.TransformPoint(hitPos); float finalLaserLen = localDir.NormalizeSafe(); Matrix33 rot; rot.SetIdentity(); rot.SetRotationVDir(localDir); pLaserEntity->SetLocalTM(rot); laserAIRange = finalLaserLen; const float assetLength = 2.0f; finalLaserLen = CLAMP(finalLaserLen,0.01f,m_lamparams.laser_max_len*dsg1Scale); float scale = finalLaserLen / assetLength; // Scale the laser based on the distance. if (m_laserEffectSlot >= 0) { Matrix33 scl; scl.SetIdentity(); scl.SetScale(Vec3(1,scale,1)); pLaserEntity->SetSlotLocalTM(m_laserEffectSlot, scl); } if (m_dotEffectSlot >= 0) { if (m_lastLaserHitSolid) { Matrix34 mt = Matrix34::CreateTranslationMat(Vec3(0,finalLaserLen,0)); if(m_lastLaserHitViewPlane) mt.Scale(Vec3(0.2f,0.2f,0.2f)); pLaserEntity->SetSlotLocalTM(m_dotEffectSlot, mt); } else { Matrix34 scaleMatrix; scaleMatrix.SetIdentity(); scaleMatrix.SetScale(Vec3(0.001f,0.001f,0.001f)); pLaserEntity->SetSlotLocalTM(m_dotEffectSlot, scaleMatrix); } } } float lightAIRange = 0.0f; if (m_lightActivated) { float range = clamp(m_smoothLaserLength, 0.5f, m_lamparams.light_range[eIGS_ThirdPerson]); lightAIRange = range * 1.5f; if (m_lightID[eIGS_ThirdPerson] && m_smoothLaserLength > 0.0f) { CItem* pLightEffect = this; if (IItem *pOwnerItem = m_pItemSystem->GetItem(GetParentId())) pLightEffect = (CItem *)pOwnerItem; pLightEffect->SetLightRadius(range, m_lightID[eIGS_ThirdPerson]); } } if (laserAIRange > 0.0001f || lightAIRange > 0.0001f) UpdateAILightAndLaser(lamPos, dir, lightAIRange, m_lamparams.light_fov[eIGS_ThirdPerson], laserAIRange); }
//------------------------------------------------------------------ void CLam::UpdateFPLaser(float frameTime, CItem* parent) { Vec3 lamPos, dir; if (m_laserActivated) AdjustLaserFPDirection(parent,dir,lamPos); else { // Lam Light lamPos = parent->GetSlotHelperPos(eIGS_FirstPerson,m_laserHelperFP.c_str(),true); Quat lamRot = Quat(parent->GetSlotHelperRotation(eIGS_FirstPerson,m_laserHelperFP.c_str(),true)); dir = lamRot.GetColumn1(); } // float len = m_lamparams.laser_range[eIGS_FirstPerson]; dir.Normalize(); const float nearClipPlaneLimit = 10.0f; Vec3 hitPos(0,0,0); float laserLength = 0.0f; float dotScale = 1.0f; { IPhysicalEntity* pSkipEntity = NULL; if(parent->GetOwner()) pSkipEntity = parent->GetOwner()->GetPhysics(); const int objects = ent_all; const int flags = (geom_colltype_ray << rwi_colltype_bit) | rwi_colltype_any | (10 & rwi_pierceability_mask) | (geom_colltype14 << rwi_colltype_bit); ray_hit hit; if (gEnv->pPhysicalWorld->RayWorldIntersection(lamPos, dir*m_lamparams.laser_range[eIGS_FirstPerson], objects, flags, &hit, 1, &pSkipEntity, pSkipEntity?1:0)) { //Clamp distance below near clip plane limits, if not dot will be overdrawn during rasterization if(hit.dist>nearClipPlaneLimit) { laserLength = nearClipPlaneLimit; m_lastLaserHitPt = lamPos + (nearClipPlaneLimit*dir); } else { laserLength = hit.dist; m_lastLaserHitPt = hit.pt; } m_lastLaserHitSolid = true; if(parent->GetOwnerActor() && parent->GetOwnerActor()->GetActorParams()) dotScale *= max(0.3f,parent->GetOwnerActor()->GetActorParams()->viewFoVScale); } else { m_lastLaserHitSolid = false; m_lastLaserHitPt = lamPos - (dir*3.0f); laserLength = 3.0f; } hitPos = m_lastLaserHitPt; if(g_pGameCVars->i_debug_projectiles!=0) gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(hitPos, 0.2f, ColorB(255,0,0)); } if (m_laserActivated && m_dotEffectSlot >= 0) { Matrix34 worldMatrix = GetEntity()->GetWorldTM(); if(laserLength<=0.7f) hitPos = lamPos+(0.7f*dir); CWeapon* pWep = static_cast<CWeapon*>(parent->GetIWeapon()); if(pWep && pWep->IsWeaponLowered()) { hitPos = lamPos+(2.0f*dir); laserLength = 2.0f; } if(laserLength<=2.0f) dotScale *= min(1.0f,(0.35f + ((laserLength-0.7f)*0.5f))); IEntity* pDotEntity = m_pEntitySystem->GetEntity(m_pLaserEntityId); if(pDotEntity) { Matrix34 finalMatrix = Matrix34::CreateTranslationMat(hitPos-(0.2f*dir)); pDotEntity->SetWorldTM(finalMatrix); Matrix34 localScale = Matrix34::CreateIdentity(); localScale.SetScale(Vec3(dotScale,dotScale,dotScale)); pDotEntity->SetSlotLocalTM(m_dotEffectSlot,localScale); } } if (m_laserActivated || m_lightActivated) { float laserAIRange = m_laserActivated ? laserLength : 0.0f; float lightAIRange = m_lightActivated ? min(laserLength, m_lamparams.light_range[eIGS_FirstPerson] * 1.5f) : 0.0f; UpdateAILightAndLaser(lamPos, dir, lightAIRange, m_lamparams.light_fov[eIGS_FirstPerson], laserAIRange); } }
//---------------------------------------------------- void CRocketLauncher::UpdateTPLaser(float frameTime) { m_lastUpdate -= frameTime; bool allowUpdate = true; if(m_lastUpdate<=0.0f) m_lastUpdate = m_Timeout; else allowUpdate = false; const CCamera& camera = gEnv->pRenderer->GetCamera(); //If character not visible, laser is not correctly updated if(CActor* pOwner = GetOwnerActor()) { ICharacterInstance* pCharacter = pOwner->GetEntity()->GetCharacter(0); if(pCharacter && !pCharacter->IsCharacterVisible()) return; } Vec3 offset(-0.06f,0.28f,0.115f); //To match scope position in TP LAW model Vec3 pos = GetEntity()->GetWorldTM().TransformPoint(offset); Vec3 dir = GetEntity()->GetWorldRotation().GetColumn1(); Vec3 hitPos(0,0,0); float laserLength = 0.0f; if(allowUpdate) { IPhysicalEntity* pSkipEntity = NULL; if(GetOwner()) pSkipEntity = GetOwner()->GetPhysics(); const float range = m_LaserRangeTP; // Use the same flags as the AI system uses for visibility. const int objects = ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_independent; //ent_living; const int flags = (geom_colltype_ray << rwi_colltype_bit) | rwi_colltype_any | (10 & rwi_pierceability_mask) | (geom_colltype14 << rwi_colltype_bit); ray_hit hit; if (gEnv->pPhysicalWorld->RayWorldIntersection(pos, dir*range, objects, flags, &hit, 1, &pSkipEntity, pSkipEntity ? 1 : 0)) { laserLength = hit.dist; m_lastLaserHitPt = hit.pt; m_lastLaserHitSolid = true; } else { m_lastLaserHitSolid = false; m_lastLaserHitPt = pos + dir * range; laserLength = range + 0.1f; } // Hit near plane if (dir.Dot(camera.GetViewdir()) < 0.0f) { Plane nearPlane; nearPlane.SetPlane(camera.GetViewdir(), camera.GetPosition()); nearPlane.d -= camera.GetNearPlane()+0.15f; Ray ray(pos, dir); Vec3 out; m_lastLaserHitViewPlane = false; if (Intersect::Ray_Plane(ray, nearPlane, out)) { float dist = Distance::Point_Point(pos, out); if (dist < laserLength) { laserLength = dist; m_lastLaserHitPt = out; m_lastLaserHitSolid = true; m_lastLaserHitViewPlane = true; } } } hitPos = m_lastLaserHitPt; } else { laserLength = Distance::Point_Point(m_lastLaserHitPt, pos); hitPos = pos + dir * laserLength; } if (m_smoothLaserLength < 0.0f) m_smoothLaserLength = laserLength; else { if (laserLength < m_smoothLaserLength) m_smoothLaserLength = laserLength; else m_smoothLaserLength += (laserLength - m_smoothLaserLength) * min(1.0f, 10.0f * frameTime); } const float assetLength = 2.0f; m_smoothLaserLength = CLAMP(m_smoothLaserLength,0.01f,m_LaserRangeTP); float scale = m_smoothLaserLength / assetLength; // Scale the laser based on the distance. Matrix34 scl; scl.SetIdentity(); scl.SetScale(Vec3(1,scale,1)); scl.SetTranslation(offset); GetEntity()->SetSlotLocalTM( eIGS_Aux1, scl); if (m_dotEffectSlot >= 0) { if (m_lastLaserHitSolid) { Matrix34 dotMatrix = Matrix34::CreateTranslationMat(Vec3(0,m_smoothLaserLength,0)); dotMatrix.AddTranslation(offset); if(m_lastLaserHitViewPlane) dotMatrix.Scale(Vec3(0.2f,0.2f,0.2f)); GetEntity()->SetSlotLocalTM(m_dotEffectSlot,dotMatrix); } else { Matrix34 scaleMatrix; scaleMatrix.SetIdentity(); scaleMatrix.SetScale(Vec3(0.001f,0.001f,0.001f)); GetEntity()->SetSlotLocalTM(m_dotEffectSlot, scaleMatrix); } } }