bool CFlashlightEffect::ComputeLightPosAndOrientation( const Vector &vecPos, const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Vector& vecFinalPos, Quaternion& quatOrientation, bool bTracePlayers ) { const float flEpsilon = 0.1f; // Offset flashlight position along vecUp float flDistCutoff = r_flashlighttracedistcutoff.GetFloat(); const float flDistDrag = 0.2; bool bDebugVis = r_flashlightvisualizetrace.GetBool(); C_BasePlayer *pPlayer = UTIL_PlayerByIndex( m_nEntIndex ); if ( !pPlayer ) { pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) { Assert( false ); return false; } } // We will lock some of the flashlight params if player is on a ladder, to prevent oscillations due to the trace-rays bool bPlayerOnLadder = ( pPlayer->GetMoveType() == MOVETYPE_LADDER ); CTraceFilterSkipPlayerAndViewModel traceFilter( pPlayer, bTracePlayers ); // Vector vOrigin = vecPos + r_flashlightoffsety.GetFloat() * vecUp; Vector vecOffset; pPlayer->GetFlashlightOffset( vecForward, vecRight, vecUp, &vecOffset ); Vector vOrigin = vecPos + vecOffset; // Not on ladder...trace a hull if ( !bPlayerOnLadder ) { Vector vecPlayerEyePos = pPlayer->GetRenderOrigin() + pPlayer->GetViewOffset(); trace_t pmOriginTrace; UTIL_TraceHull( vecPlayerEyePos, vOrigin, Vector(-2, -2, -2), Vector(2, 2, 2), ( MASK_SOLID & ~(CONTENTS_HITBOX) ) | CONTENTS_WINDOW | CONTENTS_GRATE, &traceFilter, &pmOriginTrace );//1 if ( bDebugVis ) { debugoverlay->AddBoxOverlay( pmOriginTrace.endpos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), QAngle( 0, 0, 0 ), 0, 255, 0, 16, 0 ); if ( pmOriginTrace.DidHit() || pmOriginTrace.startsolid ) { debugoverlay->AddLineOverlay( pmOriginTrace.startpos, pmOriginTrace.endpos, 255, 128, 128, true, 0 ); } else { debugoverlay->AddLineOverlay( pmOriginTrace.startpos, pmOriginTrace.endpos, 255, 0, 0, true, 0 ); } } if ( pmOriginTrace.DidHit() || pmOriginTrace.startsolid ) { vOrigin = pmOriginTrace.endpos; } else { if ( pPlayer->m_vecFlashlightOrigin != vecPlayerEyePos ) { vOrigin = vecPos; } } } else // on ladder...skip the above hull trace { vOrigin = vecPos; } // Now do a trace along the flashlight direction to ensure there is nothing within range to pull back from int iMask = MASK_OPAQUE_AND_NPCS; iMask &= ~CONTENTS_HITBOX; iMask |= CONTENTS_WINDOW | CONTENTS_GRATE | CONTENTS_IGNORE_NODRAW_OPAQUE; Vector vTarget = vOrigin + vecForward * r_flashlightfar.GetFloat(); // Work with these local copies of the basis for the rest of the function Vector vDir = vTarget - vOrigin; Vector vRight = vecRight; Vector vUp = vecUp; VectorNormalize( vDir ); VectorNormalize( vRight ); VectorNormalize( vUp ); // Orthonormalize the basis, since the flashlight texture projection will require this later... vUp -= DotProduct( vDir, vUp ) * vDir; VectorNormalize( vUp ); vRight -= DotProduct( vDir, vRight ) * vDir; VectorNormalize( vRight ); vRight -= DotProduct( vUp, vRight ) * vUp; VectorNormalize( vRight ); AssertFloatEquals( DotProduct( vDir, vRight ), 0.0f, 1e-3 ); AssertFloatEquals( DotProduct( vDir, vUp ), 0.0f, 1e-3 ); AssertFloatEquals( DotProduct( vRight, vUp ), 0.0f, 1e-3 ); trace_t pmDirectionTrace; UTIL_TraceHull( vOrigin, vTarget, Vector( -1.5, -1.5, -1.5 ), Vector( 1.5, 1.5, 1.5 ), iMask, &traceFilter, &pmDirectionTrace );//.5 if ( bDebugVis ) { debugoverlay->AddBoxOverlay( pmDirectionTrace.endpos, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ), QAngle( 0, 0, 0 ), 0, 0, 255, 16, 0 ); debugoverlay->AddLineOverlay( vOrigin, pmDirectionTrace.endpos, 255, 0, 0, false, 0 ); } float flTargetPullBackDist = 0.0f; float flDist = (pmDirectionTrace.endpos - vOrigin).Length(); if ( flDist < flDistCutoff ) { // We have an intersection with our cutoff range // Determine how far to pull back, then trace to see if we are clear float flPullBackDist = bPlayerOnLadder ? r_flashlightladderdist.GetFloat() : flDistCutoff - flDist; // Fixed pull-back distance if on ladder flTargetPullBackDist = flPullBackDist; if ( !bPlayerOnLadder ) { trace_t pmBackTrace; // start the trace away from the actual trace origin a bit, to avoid getting stuck on small, close "lips" UTIL_TraceHull( vOrigin - vDir * ( flDistCutoff * r_flashlightbacktraceoffset.GetFloat() ), vOrigin - vDir * ( flPullBackDist - flEpsilon ), Vector( -1.5f, -1.5f, -1.5f ), Vector( 1.5f, 1.5f, 1.5f ), iMask, &traceFilter, &pmBackTrace ); if ( bDebugVis ) { debugoverlay->AddLineOverlay( pmBackTrace.startpos, pmBackTrace.endpos, 255, 0, 255, true, 0 ); } if( pmBackTrace.DidHit() ) { // We have an intersection behind us as well, so limit our flTargetPullBackDist float flMaxDist = (pmBackTrace.endpos - vOrigin).Length() - flEpsilon; flTargetPullBackDist = MIN( flMaxDist, flTargetPullBackDist ); //m_flCurrentPullBackDist = MIN( flMaxDist, m_flCurrentPullBackDist ); // possible pop } } } if ( bDebugVis ) { // visualize pullback debugoverlay->AddBoxOverlay( vOrigin - vDir * m_flCurrentPullBackDist, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), QAngle( 0, 0, 0 ), 255, 255, 0, 16, 0 ); debugoverlay->AddBoxOverlay( vOrigin - vDir * flTargetPullBackDist, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), QAngle( 0, 0, 0 ), 128, 128, 0, 16, 0 ); } m_flCurrentPullBackDist = Lerp( flDistDrag, m_flCurrentPullBackDist, flTargetPullBackDist ); m_flCurrentPullBackDist = MIN( m_flCurrentPullBackDist, flDistCutoff ); // clamp to max pullback dist vOrigin = vOrigin - vDir * m_flCurrentPullBackDist; vecFinalPos = vOrigin; BasisToQuaternion( vDir, vRight, vUp, quatOrientation ); return true; }
void CSDKInput::CAM_Think( void ) { VPROF("CAM_Think"); Vector idealAngles; Vector camOffset; QAngle viewangles; if( !CAM_IsThirdPerson() ) return; ConVarRef cam_idealpitch( "cam_idealpitch" ); ConVarRef cam_idealyaw( "cam_idealyaw" ); ConVarRef cam_idealdist( "cam_idealdist" ); idealAngles[ PITCH ] = cam_idealpitch.GetFloat(); idealAngles[ YAW ] = cam_idealyaw.GetFloat(); idealAngles[ DIST ] = cam_idealdist.GetFloat(); // Obtain engine view angles and if they popped while the camera was static, // fix the camera angles as well engine->GetViewAngles( viewangles ); // bring the pitch values back into a range that MoveToward can handle if ( idealAngles[ PITCH ] > 180 ) idealAngles[ PITCH ] -= 360; else if ( idealAngles[ PITCH ] < -180 ) idealAngles[ PITCH ] += 360; // bring the yaw values back into a range that MoveToward can handle // -- // Vitaliy: going with >= 180 and <= -180. // This introduces a potential discontinuity when looking directly at model face // as camera yaw will be jumping from +180 to -180 and back, but when working with // the camera allows smooth rotational transitions from left to right and back. // Otherwise one of the transitions that has ">"-comparison will be locked. // -- if ( idealAngles[ YAW ] >= 180 ) idealAngles[ YAW ] -= 360; else if ( idealAngles[ YAW ] <= -180 ) idealAngles[ YAW ] += 360; ConVarRef c_minpitch( "c_minpitch" ); ConVarRef c_maxpitch( "c_maxpitch" ); ConVarRef c_minyaw( "c_minyaw" ); ConVarRef c_maxyaw( "c_maxyaw" ); ConVarRef c_mindistance( "c_mindistance" ); ConVarRef c_maxdistance( "c_maxdistance" ); // clamp pitch, yaw and dist... idealAngles[ PITCH ] = clamp( idealAngles[ PITCH ], c_minpitch.GetFloat(), c_maxpitch.GetFloat() ); idealAngles[ YAW ] = clamp( idealAngles[ YAW ], c_minyaw.GetFloat(), c_maxyaw.GetFloat() ); idealAngles[ DIST ] = clamp( idealAngles[ DIST ], c_mindistance.GetFloat(), c_maxdistance.GetFloat() ); // update ideal angles cam_idealpitch.SetValue( idealAngles[ PITCH ] ); cam_idealyaw.SetValue( idealAngles[ YAW ] ); cam_idealdist.SetValue( idealAngles[ DIST ] ); // Move the CameraOffset "towards" the idealAngles // Note: CameraOffset = viewangle + idealAngle CAM_GetCameraOffset( camOffset ); ConVarRef cam_snapto( "cam_snapto" ); if( cam_snapto.GetInt() ) { camOffset[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ]; camOffset[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ]; camOffset[ DIST ] = cam_idealdist.GetFloat(); } else { ConVarRef cam_ideallag( "cam_ideallag" ); float lag = max( 1, 1 + cam_ideallag.GetFloat() ); if( camOffset[ YAW ] - viewangles[ YAW ] != cam_idealyaw.GetFloat() ) camOffset[ YAW ] = MoveToward( camOffset[ YAW ], cam_idealyaw.GetFloat() + viewangles[ YAW ], lag ); if( camOffset[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch.GetFloat() ) camOffset[ PITCH ] = MoveToward( camOffset[ PITCH ], cam_idealpitch.GetFloat() + viewangles[ PITCH ], lag ); if( abs( camOffset[ DIST ] - cam_idealdist.GetFloat() ) < 2.0 ) camOffset[ DIST ] = cam_idealdist.GetFloat(); else camOffset[ DIST ] += ( cam_idealdist.GetFloat() - camOffset[ DIST ] ) / lag; } // move the camera closer to the player if it hit something trace_t trace; C_BasePlayer* localPlayer = C_BasePlayer::GetLocalPlayer(); if ( localPlayer ) { Vector camForward; // find our player's origin, and from there, the eye position Vector origin = localPlayer->GetLocalOrigin(); origin += localPlayer->GetViewOffset(); // get the forward vector AngleVectors( QAngle(camOffset[ PITCH ], camOffset[ YAW ], 0), &camForward, NULL, NULL ); // use our previously #defined hull to collision trace CTraceFilterSimple traceFilter( localPlayer, COLLISION_GROUP_NONE ); UTIL_TraceHull( origin, origin - (camForward * camOffset[ DIST ]), Vector(-CAM_HULL_OFFSET, -CAM_HULL_OFFSET, -CAM_HULL_OFFSET), Vector(CAM_HULL_OFFSET, CAM_HULL_OFFSET, CAM_HULL_OFFSET), MASK_SOLID, &traceFilter, &trace ); // move the camera closer if it hit something if( trace.fraction < 1.0 ) { camOffset[ DIST ] *= trace.fraction; } // For now, I'd rather see the insade of a player model than punch the camera through a wall // might try the fade out trick at some point //if( camOffset[ DIST ] < CAM_MIN_DIST ) // camOffset[ DIST ] = CAM_MIN_DIST; // clamp up to minimum } ConVarRef cam_showangles( "cam_showangles" ); if ( cam_showangles.GetInt() ) { engine->Con_NPrintf( 4, "Pitch: %6.1f Yaw: %6.1f %38s", viewangles[ PITCH ], viewangles[ YAW ], "view angles" ); engine->Con_NPrintf( 6, "Pitch: %6.1f Yaw: %6.1f Dist: %6.1f %19s", cam_idealpitch.GetFloat(), cam_idealyaw.GetFloat(), cam_idealdist.GetFloat(), "ideal angles" ); engine->Con_NPrintf( 8, "Pitch: %6.1f Yaw: %6.1f Dist: %6.1f %16s", camOffset[ PITCH ], camOffset[ YAW ], camOffset[ DIST ], "camera offset" ); } QAngle angOffset; angOffset.x = camOffset.x; angOffset.y = camOffset.y; angOffset.z = camOffset.z; CAM_SetCameraThirdData(NULL, angOffset); }