1001 lines
30 KiB
Ucode
1001 lines
30 KiB
Ucode
/**
|
|
* Camera: defines the Point of View of a player in world space.
|
|
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
|
|
*/
|
|
class Camera extends Actor
|
|
notplaceable
|
|
native(Camera)
|
|
dependson(EngineBaseTypes)
|
|
transient;
|
|
|
|
/** PlayerController Owning this Camera Actor */
|
|
var PlayerController PCOwner;
|
|
|
|
/** Camera Mode */
|
|
var Name CameraStyle;
|
|
/** default FOV */
|
|
var float DefaultFOV;
|
|
/** true if FOV is locked to a constant value*/
|
|
var bool bLockedFOV;
|
|
/** value FOV is locked at */
|
|
var float LockedFOV;
|
|
/** FOV that is not effected by checkerboard resolution */
|
|
var float UnmodifiedFOV;
|
|
|
|
/** If we should insert black areas when rendering the scene to ensure an aspect ratio of ConstrainedAspectRatio */
|
|
var bool bConstrainAspectRatio;
|
|
/** If bConstrainAspectRatio is true, add black regions to ensure aspect ratio is this. Ratio is horizontal/vertical. */
|
|
var float ConstrainedAspectRatio;
|
|
/** Default aspect ratio */
|
|
var float DefaultAspectRatio;
|
|
|
|
/** Off-axis yaw angle offset */
|
|
var float OffAxisYawAngle;
|
|
|
|
/** Off-axis pitch angle offset */
|
|
var float OffAxisPitchAngle;
|
|
|
|
/** If we should apply FadeColor/FadeAmount to the screen. */
|
|
var bool bEnableFading;
|
|
/** Color to fade to. */
|
|
var color FadeColor;
|
|
/** Amount of fading to apply. */
|
|
var float FadeAmount;
|
|
|
|
/** Apply fading of audio alongside the video */
|
|
var bool bFadeAudio;
|
|
|
|
/** Indicates if CamPostProcessSettings should be used when using this Camera to view through. */
|
|
var float CamOverridePostProcessAlpha;
|
|
|
|
/** Post-process settings to use if bCamOverridePostProcess is TRUE. */
|
|
var PostProcessSettings CamPostProcessSettings;
|
|
|
|
/** Rendering overrides that are active on this camera. */
|
|
var RenderingPerformanceOverrides RenderingOverrides;
|
|
|
|
/**
|
|
* Forces Temporal AA to be disabled when True.
|
|
* This is useful for hiding reprojection artifacts while certain game specific translucent effects are active.
|
|
*/
|
|
var transient bool bForceDisableTemporalAA;
|
|
|
|
/** Turn on scaling of color channels in final image using ColorScale property. */
|
|
var bool bEnableColorScaling;
|
|
/** Allows control over scaling individual color channels in the final image. */
|
|
var vector ColorScale;
|
|
/** Should interpolate color scale values */
|
|
var bool bEnableColorScaleInterp;
|
|
/** Desired color scale which ColorScale will interpolate to */
|
|
var vector DesiredColorScale;
|
|
/** Color scale value at start of interpolation */
|
|
var vector OriginalColorScale;
|
|
/** Total time for color scale interpolation to complete */
|
|
var float ColorScaleInterpDuration;
|
|
/** Time at which interpolation started */
|
|
var float ColorScaleInterpStartTime;
|
|
|
|
/** The actors which the camera shouldn't see. Used to hide actors which the camera penetrates. */
|
|
//var array<Actor> HiddenActors;
|
|
|
|
/* Caching Camera, for optimization */
|
|
struct native TCameraCache
|
|
{
|
|
/** Cached Time Stamp */
|
|
var float TimeStamp;
|
|
/** cached Point of View */
|
|
var TPOV POV;
|
|
};
|
|
var TCameraCache CameraCache, LastFrameCameraCache;
|
|
|
|
|
|
/**
|
|
* View Target definition
|
|
* A View Target is responsible for providing the Camera with an ideal Point of View (POV)
|
|
*/
|
|
struct native TViewTarget
|
|
{
|
|
/** Target Actor used to compute ideal POV */
|
|
var() Actor Target;
|
|
/** Controller of Target (only for non Locally controlled Pawns) */
|
|
var() Controller Controller;
|
|
/** Point of View */
|
|
var() TPOV POV;
|
|
/** Aspect ratio */
|
|
var() float AspectRatio;
|
|
/** PlayerReplicationInfo (used to follow same player through pawn transitions, etc., when spectating) */
|
|
var() PlayerReplicationInfo PRI;
|
|
|
|
};
|
|
|
|
/** Current ViewTarget */
|
|
var TViewTarget ViewTarget;
|
|
/** Pending view target for blending */
|
|
var TViewTarget PendingViewTarget;
|
|
/** Time left when blending to pending view target */
|
|
var float BlendTimeToGo;
|
|
|
|
enum EViewTargetBlendFunction
|
|
{
|
|
/** Camera does a simple linear interpolation. */
|
|
VTBlend_Linear,
|
|
/** Camera has a slight ease in and ease out, but amount of ease cannot be tweaked. */
|
|
VTBlend_Cubic,
|
|
/** Camera immediately accelerates, but smoothly decelerates into the target. Ease amount controlled by BlendExp. */
|
|
VTBlend_EaseIn,
|
|
/** Camera smoothly accelerates, but does not decelerate into the target. Ease amount controlled by BlendExp. */
|
|
VTBlend_EaseOut,
|
|
/** Camera smoothly accelerates and decelerates. Ease amount controlled by BlendExp. */
|
|
VTBlend_EaseInOut,
|
|
};
|
|
|
|
/** A set of parameters to describe how to transition between viewtargets. */
|
|
struct native ViewTargetTransitionParams
|
|
{
|
|
/** Total duration of blend to pending view target. 0 means no blending. */
|
|
var() float BlendTime;
|
|
/** Function to apply to the blend parameter */
|
|
var() EViewTargetBlendFunction BlendFunction;
|
|
/** Exponent, used by certain blend functions to control the shape of the curve. */
|
|
var() float BlendExp;
|
|
/** If TRUE, lock outgoing viewtarget to last frame's camera position for the remainder of the blend.
|
|
* This is useful if you plan to teleport the viewtarget, but want to keep the camera motion smooth. */
|
|
var() bool bLockOutgoing;
|
|
|
|
structdefaultproperties
|
|
{
|
|
BlendFunction=VTBlend_Cubic
|
|
BlendExp=2.f
|
|
bLockOutgoing=FALSE
|
|
}
|
|
|
|
// providing the constructor by hand here, because we pass this as an optional parameter
|
|
// and when the parameter isn't there, the default contructor is called.
|
|
structcpptext
|
|
{
|
|
FViewTargetTransitionParams()
|
|
{}
|
|
FViewTargetTransitionParams(EEventParm)
|
|
: BlendTime(0.f), BlendFunction(VTBlend_Cubic), BlendExp(2.f), bLockOutgoing(FALSE)
|
|
{}
|
|
}
|
|
};
|
|
|
|
var ViewTargetTransitionParams BlendParams;
|
|
|
|
/** List of camera modifiers to apply during update of camera position/ rotation */
|
|
var Array<CameraModifier> ModifierList;
|
|
|
|
/** Distance to place free camera from view target */
|
|
var float FreeCamDistance;
|
|
|
|
/** Offset to Z free camera position */
|
|
var vector FreeCamOffset;
|
|
|
|
/** camera fade management */
|
|
var vector2d FadeAlpha;
|
|
var float FadeTime, FadeTimeRemaining;
|
|
|
|
|
|
// "Lens" effects (e.g. blood, dirt on camera)
|
|
/** CameraBlood emitter attached to this camera */
|
|
var protected transient array<EmitterCameraLensEffectBase> CameraLensEffects;
|
|
|
|
|
|
|
|
/////////////////////
|
|
// Camera Modifiers
|
|
/////////////////////
|
|
|
|
/** Camera modifier for cone-driven screen shakes */
|
|
var() editinline transient CameraModifier_CameraShake CameraShakeCamMod;
|
|
/** Class to use when instantiating screenshake modifier object. Provided to support overrides. */
|
|
var() protected class<CameraModifier_CameraShake> CameraShakeCamModClass;
|
|
|
|
enum ECameraAnimPlaySpace
|
|
{
|
|
/** This anim is applied in camera space */
|
|
CAPS_CameraLocal,
|
|
/** This anim is applied in world space */
|
|
CAPS_World,
|
|
/** This anim is applied in a user-specified space (defined by UserPlaySpaceMatrix) */
|
|
CAPS_UserDefined,
|
|
};
|
|
|
|
////////////////////////
|
|
// CameraAnim support
|
|
////////////////////////
|
|
|
|
const MAX_ACTIVE_CAMERA_ANIMS = 8;
|
|
|
|
/** Pool of anim instance objects available with which to play camera animations */
|
|
var protected CameraAnimInst AnimInstPool[MAX_ACTIVE_CAMERA_ANIMS];
|
|
|
|
/** Array of anim instances that are currently playing and in-use */
|
|
var protected array<CameraAnimInst> ActiveAnims;
|
|
/** Array of anim instances that are not playing and available */
|
|
var protected array<CameraAnimInst> FreeAnims;
|
|
|
|
/** Internal. Receives the output of individual camera animations. */
|
|
var protected transient DynamicCameraActor AnimCameraActor;
|
|
|
|
/** if true, server will use camera positions replicated from the client instead of calculating locally. */
|
|
var bool bUseClientSideCameraUpdates;
|
|
|
|
/** If true, replicate the client side camera position but don't use it, and draw the positions on the server */
|
|
var bool bDebugClientSideCamera;
|
|
|
|
/** if true, send a camera update to the server on next update */
|
|
var bool bShouldSendClientSideCameraUpdate;
|
|
|
|
cpptext
|
|
{
|
|
protected:
|
|
void InitTempCameraActor(class ACameraActor* CamActor, class UCameraAnim* AnimToInitFor) const;
|
|
void ApplyAnimToCamera(class ACameraActor const* AnimatedCamActor, class UCameraAnimInst const* AnimInst, FTPOV& OutPOV);
|
|
|
|
UCameraAnimInst* AllocCameraAnimInst();
|
|
void ReleaseCameraAnimInst(UCameraAnimInst* Inst);
|
|
UCameraAnimInst* FindExistingCameraAnimInst(UCameraAnim const* Anim);
|
|
|
|
public:
|
|
virtual void ModifyPostProcessSettings(FPostProcessSettings& PPSettings) const;
|
|
|
|
void AssignViewTarget(AActor* NewTarget, FTViewTarget& VT, struct FViewTargetTransitionParams TransitionParams=FViewTargetTransitionParams(EC_EventParm));
|
|
AActor* GetViewTarget();
|
|
virtual UBOOL PlayerControlled();
|
|
}
|
|
|
|
/**
|
|
* Internal. Creates and initializes a new camera modifier of the specified class, returns the object ref.
|
|
*/
|
|
protected function CameraModifier CreateCameraModifier(class<CameraModifier> ModifierClass)
|
|
{
|
|
local CameraModifier NewMod;
|
|
NewMod = new(Outer) ModifierClass;
|
|
NewMod.Init();
|
|
NewMod.AddCameraModifier(Self);
|
|
return NewMod;
|
|
}
|
|
|
|
|
|
function PostBeginPlay()
|
|
{
|
|
local int Idx;
|
|
|
|
super.PostBeginPlay();
|
|
|
|
// Setup camera modifiers
|
|
if( (CameraShakeCamMod == None) && (CameraShakeCamModClass != None) )
|
|
{
|
|
CameraShakeCamMod = CameraModifier_CameraShake(CreateCameraModifier(CameraShakeCamModClass));
|
|
}
|
|
|
|
// create CameraAnimInsts in pool
|
|
for (Idx=0; Idx<MAX_ACTIVE_CAMERA_ANIMS; ++Idx)
|
|
{
|
|
AnimInstPool[Idx] = new(Self) class'CameraAnimInst';
|
|
|
|
// add everything to the free list initially
|
|
FreeAnims[Idx] = AnimInstPool[Idx];
|
|
}
|
|
|
|
// spawn the two temp CameraActors used for updating CameraAnims
|
|
AnimCameraActor = Spawn(class'DynamicCameraActor', self,,,,, TRUE);
|
|
}
|
|
|
|
event Destroyed()
|
|
{
|
|
// clean up the temp camera actors
|
|
AnimCameraActor.Destroy();
|
|
super.Destroyed();
|
|
}
|
|
|
|
/**
|
|
* Apply modifiers on Camera.
|
|
* @param DeltaTime Time is seconds since last update
|
|
* @param OutPOV Point of View
|
|
*/
|
|
|
|
native function ApplyCameraModifiers(float DeltaTime, out TPOV OutPOV);
|
|
|
|
/**
|
|
* Initialize Camera for associated PlayerController
|
|
* @param PC PlayerController attached to this Camera.
|
|
*/
|
|
function InitializeFor(PlayerController PC)
|
|
{
|
|
CameraCache.POV.FOV = DefaultFOV;
|
|
PCOwner = PC;
|
|
|
|
SetViewTarget(PC.ViewTarget);
|
|
|
|
// set the level default scale
|
|
SetDesiredColorScale(WorldInfo.DefaultColorScale, 5.f);
|
|
|
|
// Force camera update so it doesn't sit at (0,0,0) for a full tick.
|
|
// This can have side effects with streaming.
|
|
UpdateCamera(0.f);
|
|
}
|
|
|
|
|
|
/**
|
|
* returns camera's current FOV angle
|
|
*/
|
|
function float GetFOVAngle()
|
|
{
|
|
if( bLockedFOV )
|
|
{
|
|
return LockedFOV;
|
|
}
|
|
|
|
return CameraCache.POV.FOV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Lock FOV to a specific value.
|
|
* A value of 0 to beyond 170 will unlock the FOV setting.
|
|
*/
|
|
function SetFOV(float NewFOV)
|
|
{
|
|
if( NewFOV < 1 || NewFOV > 170 )
|
|
{
|
|
bLockedFOV = FALSE;
|
|
return;
|
|
}
|
|
|
|
bLockedFOV = TRUE;
|
|
LockedFOV = NewFOV;
|
|
}
|
|
|
|
/** Checkerborad-free FOV */
|
|
function SetUnmodifiedFOV(float NewFOV)
|
|
{
|
|
UnmodifiedFOV = NewFOV;
|
|
}
|
|
|
|
`if(`__TW_)
|
|
function float GetActualFOV() { return GetFOVAngle(); }
|
|
`endif
|
|
|
|
/**
|
|
* Master function to retrieve Camera's actual view point.
|
|
* do not call this directly, call PlayerController::GetPlayerViewPoint() instead.
|
|
*
|
|
* @param OutCamLoc Camera Location
|
|
* @param OutCamRot Camera Rotation
|
|
*/
|
|
final function GetCameraViewPoint(out vector OutCamLoc, out rotator OutCamRot)
|
|
{
|
|
// @debug: find out which calls are being made before the camera has been ticked
|
|
// and have therefore one frame of lag.
|
|
/*
|
|
if( CameraCache.TimeStamp != WorldInfo.TimeSeconds )
|
|
{
|
|
`Log(WorldInfo.TimeSeconds @ GetFuncName() @ "one frame of lag");
|
|
ScriptTrace();
|
|
}
|
|
*/
|
|
|
|
OutCamLoc = CameraCache.POV.Location;
|
|
OutCamRot = CameraCache.POV.Rotation;
|
|
}
|
|
|
|
final function rotator GetCameraRotation()
|
|
{
|
|
return CameraCache.POV.Rotation;
|
|
}
|
|
|
|
/**
|
|
* Sets the new desired color scale and enables interpolation.
|
|
*/
|
|
simulated function SetDesiredColorScale(vector NewColorScale, float InterpTime)
|
|
{
|
|
// if color scaling is not enabled
|
|
if (!bEnableColorScaling)
|
|
{
|
|
// set the default color scale
|
|
bEnableColorScaling = TRUE;
|
|
ColorScale.X = 1.f;
|
|
ColorScale.Y = 1.f;
|
|
ColorScale.Z = 1.f;
|
|
}
|
|
|
|
// Don't bother interpolating if we're already scaling at the desired color
|
|
if( NewColorScale != ColorScale )
|
|
{
|
|
// save the current as original
|
|
OriginalColorScale = ColorScale;
|
|
// set the new desired scale
|
|
DesiredColorScale = NewColorScale;
|
|
// set the interpolation duration/time
|
|
ColorScaleInterpStartTime = WorldInfo.TimeSeconds;
|
|
ColorScaleInterpDuration = InterpTime;
|
|
// and enable color scale interpolation
|
|
bEnableColorScaleInterp = TRUE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Performs camera update.
|
|
* Called once per frame after all actors have been ticked.
|
|
* Non-local players replicate the POV if bUseClientSideCameraUpdates is true
|
|
*/
|
|
simulated event UpdateCamera(float DeltaTime)
|
|
{
|
|
if ( PCOwner.IsLocalPlayerController() || !bUseClientSideCameraUpdates || bDebugClientSideCamera )
|
|
{
|
|
DoUpdateCamera(DeltaTime);
|
|
|
|
if (WorldInfo.NetMode == NM_Client && bShouldSendClientSideCameraUpdate)
|
|
{
|
|
PCOwner.ServerUpdateCamera(CameraCache.POV.Location, (CameraCache.POV.Rotation.Pitch & 65535) + ((CameraCache.POV.Rotation.Yaw & 65535) << 16));
|
|
bShouldSendClientSideCameraUpdate = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function DoUpdateCamera(float DeltaTime)
|
|
{
|
|
local TPOV NewPOV;
|
|
local float DurationPct, BlendPct;
|
|
|
|
// update color scale interpolation
|
|
if (bEnableColorScaleInterp)
|
|
{
|
|
BlendPct = FClamp(`TimeSince(ColorScaleInterpStartTime)/ColorScaleInterpDuration,0.f,1.f);
|
|
ColorScale = VLerp(OriginalColorScale,DesiredColorScale,BlendPct);
|
|
// if we've maxed
|
|
if (BlendPct == 1.f)
|
|
{
|
|
// disable further interpolation
|
|
bEnableColorScaleInterp = FALSE;
|
|
}
|
|
}
|
|
|
|
// Reset aspect ratio and postprocess override associated with CameraActor.
|
|
bConstrainAspectRatio = FALSE;
|
|
CamOverridePostProcessAlpha = 0.f;
|
|
|
|
// Don't update outgoing viewtarget during an interpolation when bLockOutgoing is set.
|
|
if( PendingViewTarget.Target == None || !BlendParams.bLockOutgoing )
|
|
{
|
|
// Update current view target
|
|
CheckViewTarget(ViewTarget);
|
|
UpdateViewTarget(ViewTarget, DeltaTime);
|
|
}
|
|
|
|
// our camera is now viewing there
|
|
NewPOV = ViewTarget.POV;
|
|
ConstrainedAspectRatio = ViewTarget.AspectRatio;
|
|
|
|
// if we have a pending view target, perform transition from one to another.
|
|
if( PendingViewTarget.Target != None )
|
|
{
|
|
BlendTimeToGo -= DeltaTime;
|
|
|
|
// Reset aspect ratio. The call to UpdateViewTarget() may turn this back on.
|
|
bConstrainAspectRatio = FALSE;
|
|
|
|
// Update pending view target
|
|
CheckViewTarget(PendingViewTarget);
|
|
UpdateViewTarget(PendingViewTarget, DeltaTime);
|
|
|
|
// blend....
|
|
if( BlendTimeToGo > 0 )
|
|
{
|
|
DurationPct = (BlendParams.BlendTime - BlendTimeToGo) / BlendParams.BlendTime;
|
|
|
|
switch (BlendParams.BlendFunction)
|
|
{
|
|
case VTBlend_Linear:
|
|
BlendPct = Lerp(0.f, 1.f, DurationPct);
|
|
break;
|
|
case VTBlend_Cubic:
|
|
BlendPct = FCubicInterp(0.f, 0.f, 1.f, 0.f, DurationPct);
|
|
break;
|
|
case VTBlend_EaseIn:
|
|
BlendPct = FInterpEaseIn(0.f, 1.f, DurationPct, BlendParams.BlendExp);
|
|
break;
|
|
case VTBlend_EaseOut:
|
|
BlendPct = FInterpEaseOut(0.f, 1.f, DurationPct, BlendParams.BlendExp);
|
|
break;
|
|
case VTBlend_EaseInOut:
|
|
BlendPct = FInterpEaseInOut(0.f, 1.f, DurationPct, BlendParams.BlendExp);
|
|
break;
|
|
}
|
|
//BlendPct = FCubicInterp(0.f, class'DialogueManager'.default.OutTan, 1.f, class'DialogueManager'.default.InTan, 1.f - DurationPct);
|
|
|
|
// Update pending view target blend
|
|
NewPOV = BlendViewTargets(ViewTarget, PendingViewTarget, BlendPct);
|
|
}
|
|
else
|
|
{
|
|
// we're done blending, set new view target
|
|
ViewTarget = PendingViewTarget;
|
|
|
|
// clear pending view target
|
|
PendingViewTarget.Target = None;
|
|
PendingViewTarget.Controller = None;
|
|
|
|
BlendTimeToGo = 0;
|
|
|
|
// our camera is now viewing there
|
|
NewPOV = PendingViewTarget.POV;
|
|
}
|
|
|
|
if( bConstrainAspectRatio )
|
|
{
|
|
// NOTE: We don't interpolate aspect ratio since either the prior or pending view target's AspectRatio
|
|
// may be the default value (1.3333) unless the view target has a camera actor set to override
|
|
// the aspect ratio. We'll just use the pending view target's aspect.
|
|
ConstrainedAspectRatio = PendingViewTarget.AspectRatio;
|
|
}
|
|
}
|
|
|
|
// Cache results
|
|
FillCameraCache(NewPOV);
|
|
|
|
if (bEnableFading && FadeTimeRemaining > 0.0)
|
|
{
|
|
FadeTimeRemaining = FMax(FadeTimeRemaining - DeltaTime, 0.0);
|
|
if (FadeTime > 0.0)
|
|
{
|
|
FadeAmount = FadeAlpha.X + ((1.f - FadeTimeRemaining/FadeTime) * (FadeAlpha.Y - FadeAlpha.X));
|
|
}
|
|
|
|
if (bFadeAudio)
|
|
{
|
|
ApplyAudioFade();
|
|
if (FadeAmount == 0)
|
|
{
|
|
bFadeAudio = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Apply audio fading */
|
|
native function ApplyAudioFade();
|
|
|
|
/**
|
|
* Blend 2 viewtargets.
|
|
*
|
|
* @param A Source view target
|
|
* @paramn B destination view target
|
|
* @param Alpha Alpha, % of blend from A to B.
|
|
*/
|
|
final function TPOV BlendViewTargets(const out TViewTarget A,const out TViewTarget B, float Alpha)
|
|
{
|
|
local TPOV POV;
|
|
|
|
POV.Location = VLerp(A.POV.Location, B.POV.Location, Alpha);
|
|
POV.FOV = Lerp(A.POV.FOV, B.POV.FOV, Alpha);
|
|
POV.Rotation = RLerp(A.POV.Rotation, B.POV.Rotation, Alpha, TRUE);
|
|
|
|
return POV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Cache update results
|
|
*/
|
|
final function FillCameraCache(const out TPOV NewPOV)
|
|
{
|
|
// Backup last frame results.
|
|
if( CameraCache.TimeStamp != WorldInfo.TimeSeconds )
|
|
{
|
|
LastFrameCameraCache = CameraCache;
|
|
}
|
|
CameraCache.TimeStamp = WorldInfo.TimeSeconds;
|
|
CameraCache.POV = NewPOV;
|
|
}
|
|
|
|
|
|
/**
|
|
* Make sure ViewTarget is valid
|
|
*/
|
|
native function CheckViewTarget(out TViewTarget VT);
|
|
|
|
|
|
/**
|
|
* Query ViewTarget and outputs Point Of View.
|
|
*
|
|
* @param OutVT ViewTarget to use.
|
|
* @param DeltaTime Delta Time since last camera update (in seconds).
|
|
*/
|
|
function UpdateViewTarget(out TViewTarget OutVT, float DeltaTime)
|
|
{
|
|
local vector Loc, Pos, HitLocation, HitNormal;
|
|
local rotator Rot;
|
|
local Actor HitActor;
|
|
local CameraActor CamActor;
|
|
local bool bDoNotApplyModifiers;
|
|
local TPOV OrigPOV;
|
|
local Pawn TPawn;
|
|
|
|
// Don't update outgoing viewtarget during an interpolation
|
|
if( PendingViewTarget.Target != None && OutVT == ViewTarget && BlendParams.bLockOutgoing )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// store previous POV, in case we need it later
|
|
OrigPOV = OutVT.POV;
|
|
|
|
// Default FOV on viewtarget
|
|
OutVT.POV.FOV = DefaultFOV;
|
|
|
|
// Viewing through a camera actor.
|
|
CamActor = CameraActor(OutVT.Target);
|
|
if( CamActor != None )
|
|
{
|
|
CamActor.GetCameraView(DeltaTime, OutVT.POV);
|
|
|
|
// Grab aspect ratio from the CameraActor.
|
|
bConstrainAspectRatio = bConstrainAspectRatio || CamActor.bConstrainAspectRatio;
|
|
OutVT.AspectRatio = CamActor.AspectRatio;
|
|
|
|
// See if the CameraActor wants to override the PostProcess settings used.
|
|
CamOverridePostProcessAlpha = CamActor.CamOverridePostProcessAlpha;
|
|
CamPostProcessSettings = CamActor.CamOverridePostProcess;
|
|
}
|
|
else
|
|
{
|
|
TPawn = Pawn(OutVT.Target);
|
|
// Give Pawn Viewtarget a chance to dictate the camera position.
|
|
// If Pawn doesn't override the camera view, then we proceed with our own defaults
|
|
if( TPawn == None || !TPawn.CalcCamera(DeltaTime, OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV) )
|
|
{
|
|
// don't apply modifiers when using these debug camera modes.
|
|
bDoNotApplyModifiers = TRUE;
|
|
|
|
switch( CameraStyle )
|
|
{
|
|
case 'Fixed' : // do not update, keep previous camera position by restoring
|
|
// saved POV, in case CalcCamera changes it but still returns false
|
|
OutVT.POV = OrigPOV;
|
|
break;
|
|
|
|
case 'ThirdPerson' : // Simple third person view implementation
|
|
case 'FreeCam' :
|
|
case 'FreeCam_Default':
|
|
Loc = OutVT.Target.Location;
|
|
Rot = OutVT.Target.Rotation;
|
|
|
|
// Take into account Mesh Translation so it takes into account the PostProcessing we do there.
|
|
if ((TPawn != None) && (TPawn.Mesh != None))
|
|
{
|
|
Loc += (TPawn.Mesh.Translation - TPawn.default.Mesh.Translation) >> OutVT.Target.Rotation;
|
|
}
|
|
|
|
//OutVT.Target.GetActorEyesViewPoint(Loc, Rot);
|
|
if( CameraStyle == 'FreeCam' || CameraStyle == 'FreeCam_Default' )
|
|
{
|
|
Rot = PCOwner.Rotation;
|
|
}
|
|
`if(`__TW_)
|
|
if( OutVT.Target != PCOwner )
|
|
{
|
|
Loc += FreeCamOffset >> Rot;
|
|
Pos = Loc - Vector(Rot) * FreeCamDistance;
|
|
}
|
|
else
|
|
{
|
|
Pos = Loc;
|
|
}
|
|
`else
|
|
Loc += FreeCamOffset >> Rot;
|
|
Pos = Loc - Vector(Rot) * FreeCamDistance;
|
|
`endif
|
|
// @fixme, respect BlockingVolume.bBlockCamera=false
|
|
HitActor = Trace(HitLocation, HitNormal, Pos, Loc, FALSE, vect(12,12,12));
|
|
OutVT.POV.Location = (HitActor == None) ? Pos : HitLocation;
|
|
OutVT.POV.Rotation = Rot;
|
|
break;
|
|
|
|
case 'FirstPerson' : // Simple first person, view through viewtarget's 'eyes'
|
|
default : OutVT.Target.GetActorEyesViewPoint(OutVT.POV.Location, OutVT.POV.Rotation);
|
|
// Take into account Mesh Translation so it takes into account the PostProcessing we do there.
|
|
if ((TPawn != None) && (TPawn.Mesh != None))
|
|
{
|
|
OutVT.POV.Location += (TPawn.Mesh.Translation - TPawn.default.Mesh.Translation) >> OutVT.Target.Rotation;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bDoNotApplyModifiers )
|
|
{
|
|
// Apply camera modifiers at the end (view shakes for example)
|
|
ApplyCameraModifiers(DeltaTime, OutVT.POV);
|
|
}
|
|
//`log( WorldInfo.TimeSeconds @ GetFuncName() @ OutVT.Target @ OutVT.POV.Location @ OutVT.POV.Rotation @ OutVT.POV.FOV );
|
|
}
|
|
|
|
|
|
/**
|
|
* Set a new ViewTarget with optional BlendTime
|
|
*/
|
|
native final function SetViewTarget(Actor NewViewTarget, optional ViewTargetTransitionParams TransitionParams);
|
|
|
|
|
|
/**
|
|
* Give each modifier a chance to change view rotation/deltarot
|
|
*/
|
|
function ProcessViewRotation(float DeltaTime, out rotator OutViewRotation, out Rotator OutDeltaRot)
|
|
{
|
|
local int ModifierIdx;
|
|
|
|
for( ModifierIdx = 0; ModifierIdx < ModifierList.Length; ModifierIdx++ )
|
|
{
|
|
if( ModifierList[ModifierIdx] != None )
|
|
{
|
|
if( ModifierList[ModifierIdx].ProcessViewRotation(ViewTarget.Target, DeltaTime, OutViewRotation, OutDeltaRot) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* list important Camera variables on canvas. HUD will call DisplayDebug() on the current ViewTarget when
|
|
* the ShowDebug exec is used
|
|
*
|
|
* @param HUD - HUD with canvas to draw on
|
|
* @input out_YL - Height of the current font
|
|
* @input out_YPos - Y position on Canvas. out_YPos += out_YL, gives position to draw text for next debug line.
|
|
*/
|
|
simulated function DisplayDebug(HUD HUD, out float out_YL, out float out_YPos)
|
|
{
|
|
local Vector EyesLoc;
|
|
local Rotator EyesRot;
|
|
local Canvas Canvas;
|
|
|
|
Canvas = HUD.Canvas;
|
|
Canvas.SetDrawColor(255,255,255);
|
|
|
|
Canvas.DrawText(" Camera Style:" $ CameraStyle @ "main ViewTarget:" $ ViewTarget.Target);
|
|
out_YPos += out_YL;
|
|
Canvas.SetPos(4,out_YPos);
|
|
|
|
`if(`__TW_)
|
|
Canvas.DrawText(" CamLoc:" $ CameraCache.POV.Location @ "CamRot:" $ CameraCache.POV.Rotation @ "FOV:" $ GetFOVAngle());
|
|
`else
|
|
Canvas.DrawText(" CamLoc:" $ CameraCache.POV.Location @ "CamRot:" $ CameraCache.POV.Rotation @ "FOV:" $ CameraCache.POV.FOV);
|
|
`endif
|
|
out_YPos += out_YL;
|
|
Canvas.SetPos(4,out_YPos);
|
|
|
|
Canvas.DrawText(" AspectRatio:" $ ConstrainedAspectRatio);
|
|
out_YPos += out_YL;
|
|
Canvas.SetPos(4,out_YPos);
|
|
|
|
if( ViewTarget.Target != None )
|
|
{
|
|
ViewTarget.Target.GetActorEyesViewPoint(EyesLoc, EyesRot);
|
|
Canvas.DrawText(" EyesLoc:" $ EyesLoc @ "EyesRot:" $ EyesRot);
|
|
out_YPos += out_YL;
|
|
Canvas.SetPos(4,out_YPos);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////
|
|
// Camera Lens Effects
|
|
////////////////////////////////
|
|
|
|
/** Finds the first instance of a lens effect of the given class, using linear search. */
|
|
function EmitterCameraLensEffectBase FindCameraLensEffect(class<EmitterCameraLensEffectBase> LensEffectEmitterClass)
|
|
{
|
|
local EmitterCameraLensEffectBase LensEffect;
|
|
|
|
foreach CameraLensEffects(LensEffect)
|
|
{
|
|
if ( !LensEffect.bDeleteMe &&
|
|
( (LensEffect.Class == LensEffectEmitterClass) ||
|
|
(LensEffect.EmittersToTreatAsSame.Find(LensEffectEmitterClass) != INDEX_NONE) ||
|
|
(LensEffectEmitterClass.default.EmittersToTreatAsSame.Find(LensEffect.Class) != INDEX_NONE ) ) )
|
|
{
|
|
return LensEffect;
|
|
}
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
/**
|
|
* Initiates a camera lens effect of the given class on this camera.
|
|
*/
|
|
function AddCameraLensEffect(class<EmitterCameraLensEffectBase> LensEffectEmitterClass)
|
|
{
|
|
local vector CamLoc;
|
|
local rotator CamRot;
|
|
local EmitterCameraLensEffectBase LensEffect;
|
|
|
|
if (LensEffectEmitterClass != None)
|
|
{
|
|
if (!LensEffectEmitterClass.default.bAllowMultipleInstances)
|
|
{
|
|
LensEffect = FindCameraLensEffect(LensEffectEmitterClass);
|
|
|
|
if (LensEffect != None)
|
|
{
|
|
LensEffect.NotifyRetriggered();
|
|
}
|
|
}
|
|
|
|
if (LensEffect == None)
|
|
{
|
|
// spawn with viewtarget as the owner so bOnlyOwnerSee works as intended
|
|
LensEffect = Spawn( LensEffectEmitterClass, PCOwner.GetViewTarget() );
|
|
if (LensEffect != None)
|
|
{
|
|
GetCameraViewPoint(CamLoc, CamRot);
|
|
`if(`__TW_)
|
|
LensEffect.UpdateLocation( CamLoc, CamRot, GetActualFOV() );
|
|
`else
|
|
LensEffect.UpdateLocation(CamLoc, CamRot, GetFOVAngle());
|
|
`endif
|
|
LensEffect.RegisterCamera(self);
|
|
|
|
CameraLensEffects.AddItem(LensEffect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Removes this particular lens effect from the camera. */
|
|
function RemoveCameraLensEffect(EmitterCameraLensEffectBase Emitter)
|
|
{
|
|
CameraLensEffects.RemoveItem(Emitter);
|
|
}
|
|
|
|
/** Removes all Camera Lens Effects. */
|
|
function ClearCameraLensEffects()
|
|
{
|
|
local EmitterCameraLensEffectBase LensEffect;
|
|
|
|
foreach CameraLensEffects(LensEffect)
|
|
{
|
|
LensEffect.Destroy();
|
|
}
|
|
|
|
// empty the array. unnecessary, since destruction will call RemoveCameraLensEffect,
|
|
// but this gets it done in one fell swoop.
|
|
CameraLensEffects.length = 0;
|
|
}
|
|
|
|
/** ------------------------------------------------------------
|
|
* Camera Shakes
|
|
* ------------------------------------------------------------ */
|
|
|
|
|
|
/**
|
|
* Play a camera shake
|
|
*/
|
|
function PlayCameraShake(CameraShake Shake, float Scale, optional ECameraAnimPlaySpace PlaySpace=CAPS_CameraLocal, optional rotator UserPlaySpaceRot)
|
|
{
|
|
if (Shake != None)
|
|
{
|
|
CameraShakeCamMod.AddCameraShake(Shake, Scale, PlaySpace, UserPlaySpaceRot);
|
|
}
|
|
}
|
|
|
|
/** Stop playing a camera shake. */
|
|
function StopCameraShake(CameraShake Shake)
|
|
{
|
|
if (Shake != None)
|
|
{
|
|
CameraShakeCamMod.RemoveCameraShake(Shake);
|
|
}
|
|
}
|
|
|
|
|
|
/** Internal. Returns intensity scalar in the range [0..1] for a shake originating at Epicenter. */
|
|
static function float CalcRadialShakeScale(Camera Cam, vector Epicenter, float InnerRadius, float OuterRadius, float Falloff)
|
|
{
|
|
local Vector POVLoc;
|
|
local float DistPct;
|
|
|
|
// using camera location so stuff like spectator cameras get shakes applied sensibly as well
|
|
// need to ensure server has reasonably accurate camera position
|
|
POVLoc = Cam.Location;
|
|
|
|
if (InnerRadius < OuterRadius)
|
|
{
|
|
DistPct = (VSize(Epicenter - POVLoc) - InnerRadius) / (OuterRadius - InnerRadius);
|
|
DistPct = 1.f - FClamp(DistPct, 0.f, 1.f);
|
|
return DistPct ** Falloff;
|
|
}
|
|
else
|
|
{
|
|
// ignore OuterRadius and do a cliff falloff at InnerRadius
|
|
return (VSize(Epicenter - POVLoc) < InnerRadius) ? 1.f : 0.f;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Static. Plays an in-world camera shake that affects all nearby players, with distance-based attenuation.
|
|
*/
|
|
static function PlayWorldCameraShake(CameraShake Shake, Actor ShakeInstigator, vector Epicenter, float InnerRadius, float OuterRadius, float Falloff, bool bTryForceFeedback, optional bool bOrientShakeTowardsEpicenter )
|
|
{
|
|
local PlayerController PC;
|
|
local float ShakeScale;
|
|
local Rotator CamRot;
|
|
local vector CamLoc;
|
|
|
|
if( ShakeInstigator != None )
|
|
{
|
|
foreach ShakeInstigator.LocalPlayerControllers(class'PlayerController', PC)
|
|
{
|
|
if (PC.PlayerCamera != None)
|
|
{
|
|
ShakeScale = CalcRadialShakeScale(PC.PlayerCamera, Epicenter, InnerRadius, OuterRadius, Falloff);
|
|
|
|
if (bOrientShakeTowardsEpicenter && PC.Pawn != None)
|
|
{
|
|
PC.PlayerCamera.GetCameraViewPoint(CamLoc, CamRot);
|
|
PC.ClientPlayCameraShake(Shake, ShakeScale, bTryForceFeedback, CAPS_UserDefined, rotator(Epicenter - CamLoc));
|
|
}
|
|
else
|
|
{
|
|
PC.ClientPlayCameraShake(Shake, ShakeScale, bTryForceFeedback);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function ClearAllCameraShakes()
|
|
{
|
|
CameraShakeCamMod.RemoveAllCameraShakes();
|
|
// StopAllCameraAnims(TRUE);
|
|
}
|
|
|
|
|
|
/** ------------------------------------------------------------
|
|
* CameraAnim support
|
|
* ------------------------------------------------------------ */
|
|
|
|
/** Play the indicated CameraAnim on this camera. Returns the CameraAnim instance. */
|
|
simulated native function CameraAnimInst PlayCameraAnim(CameraAnim Anim, optional float Rate=1.f, optional float Scale=1.f, optional float BlendInTime, optional float BlendOutTime, optional bool bLoop, optional bool bRandomStartTime, optional float Duration, optional bool bSingleInstance);
|
|
|
|
/**
|
|
* Stop playing all instances of the indicated CameraAnim.
|
|
* bImmediate: TRUE to stop it right now, FALSE to blend it out over BlendOutTime.
|
|
*/
|
|
simulated native function StopAllCameraAnims(optional bool bImmediate);
|
|
|
|
/**
|
|
* Stop playing all instances of the indicated CameraAnim.
|
|
* bImmediate: TRUE to stop it right now, FALSE to blend it out over BlendOutTime.
|
|
*/
|
|
simulated native function StopAllCameraAnimsByType(CameraAnim Anim, optional bool bImmediate);
|
|
|
|
/**
|
|
* Stops the given CameraAnim instance from playing. The given pointer should be considered invalid after this.
|
|
*/
|
|
simulated native function StopCameraAnim(CameraAnimInst AnimInst, optional bool bImmediate);
|
|
|
|
|
|
defaultproperties
|
|
{
|
|
DefaultFOV=90.f
|
|
DefaultAspectRatio=AspectRatio4x3
|
|
bHidden=TRUE
|
|
RemoteRole=ROLE_None
|
|
FreeCamDistance=256.f
|
|
bUseClientSideCameraUpdates=TRUE
|
|
bDebugClientSideCamera=FALSE
|
|
|
|
CameraShakeCamModClass=class'CameraModifier_CameraShake'
|
|
}
|