All pastes #279790 Raw Edit

Something

public text v1 · immutable
·published 2006-12-15 09:45 UTC
rendered paste body
class Effect_ShadowProjector extends Projector config(user);

var() vector LightDirection;
var() float LightDistance, InterpolationRate, MaxFOV, FadeSpeed, DarknessScale;
var ShadowBitmapMaterial ShadowTexture;
var bool bFadeIn;

var bool bLastAggressiveLOD;
var bool bCurrentBlobbiness;

var bool bDirtyNextTime;

var float DetailDropTime;
var float DetailIncreaseTime;

var globalconfig enum DetailEnum {
	VeryLow,
	Low,
	Medium,
	High,
	Maximum
} ShadowDetail;

function PostBeginPlay()
{
	//Super(Actor).PostBeginPlay();
}

// these don't need to tick, we update all shadows at the same time in the controller
function Tick(float dt) {}

// this turns the shadow off
function DisableShadow()
{
	// detach
	DetachProjector();

	// stop shadow texture from being reuploaded to video here
	if (ShadowTexture != None)
	{
		ShadowTexture.Dirty = false;
		ShadowTexture.ShadowActor = None;
	}
}

// initialize
function InitializeFor(Effect_ShadowController ShadowController)
{
	if (ShadowController.Owner != None)
	{
		// set the Owner
		SetOwner(ShadowController.Owner);

		// allocate the shadow texture
		if(ShadowTexture == None) CreateShadowTexture();

		// set projector texture
		//ProjTexture = ShadowTexture;
		// already done in Create

		// initialize the shadow texture
		if (ShadowTexture != None)
		{
			ShadowTexture.Invalid = false;
			ShadowTexture.ShadowActor = Owner;
			ShadowTexture.bBlobShadow = false;
			ShadowTexture.CullDistance = CullDistance;
			//Owner.AttachToBone(self, 'shadow');
		}
		else
		{
			log(Name$".InitializeFor: No shadow texture!  Escaping...");
			Destroy();
		}
	}
	else
		log(Name$".InitializeFor: No Owner!");
}

// updates this shadow's location, rotation, and FOV
simulated function UpdateShadow(float dt, int LN, Effect_ShadowController ShadowController)
{
	local Plane BoundingSphere;
	local Actor ShadowLight;
	local vector Diff, ShadowLocation, Origin;
	local rotator LightRotation, AdjustedRotation;
	local float Interpolation;
	local bool bFadeOut;
	local float DrawS;

	if(Level.bAggressiveLOD) return;
	DetachProjector(true);

	if (Owner == None || Owner.bHidden || ShadowTexture == None)
		return;

	// fallback and destroy
	if (ShadowTexture.Invalid)
	{
		Destroy();
		return;
	}

	// cull more if we haven't rendered this pawn in 5 seconds
	if (Level.TimeSeconds - Owner.LastRenderTime > 5)
		CullDistance = 0.5*Default.CullDistance;
	else
		CullDistance = Default.CullDistance;

	// cull shadows much earlier if below min framerate, important
   	if (Level.bDropDetail) {
		if(Level.bAggressiveLOD && bLastAggressiveLOD) {
			//log(self@"aggressivelod true");
			DropShadowDetail();
		}
		ShadowTexture.CullDistance = 0.6*CullDistance;
	} else {
		if(!bLastAggressiveLOD)
			IncreaseShadowDetail();
		ShadowTexture.CullDistance = CullDistance;
	}
	bLastAggressiveLOD = Level.bAggressiveLOD;

	// in case shadow was disabled earlier
	ShadowTexture.ShadowActor = Owner;

	// set light
	ShadowLight = ShadowController.Lights[LN].CurrentLight;

	// fade out if necessary
	if (ShadowController.Lights[LN].LastLight != None)
	{
		if (ShadowTexture.ShadowDarkness > 5)
		{
			ShadowLight = ShadowController.Lights[LN].LastLight;
			bFadeOut = true;
		}
		else
		{
			ShadowController.Lights[LN].LastLight = None;
			bFadeOut = false;
			bFadeIn = true;
			DarknessScale = 0;
		}
	}

	// fallback if no more lights after fadeout
	if (ShadowLight == None)
		return;

	// get the direction of the light
	Diff = ShadowLight.Location - Owner.Location;

	// set light distance
	if (ShadowLight.LightEffect == LE_Sunlight)
		LightDistance = ShadowController.MaxLightDistance*0.3;
	else
		LightDistance = FClamp(VSize(Diff), ShadowController.MaxLightDistance*0.1, ShadowController.MaxLightDistance*0.3);

	MaxTraceDistance = LightDistance * 3;
	// get a location along the path of the light slightly away from center of player
	ShadowLocation = Owner.Location + 4*Normal(Diff);
	if (ShadowLocation.Z < Owner.Location.Z)
		ShadowLocation.Z = Owner.Location.Z+4;

	//ShadowLocation = Owner.GetBoneCoords('shadow').Origin;
	// set location
	SetLocation(ShadowLocation + vect(0,0,-8));

	// calculate FOV
	BoundingSphere = Owner.GetRenderBoundingSphere();
	FOV = (Atan(BoundingSphere.W*2 + 160, LightDistance) * 180/PI);

	// set rotation, compensate for FOV warping -- kinda hackish, but fixes shadows that
	// bend so much they detach from the pawn
	AdjustedRotation = rotator(Owner.Location-ShadowLight.Location);
	AdjustedRotation.Pitch = Clamp(AdjustedRotation.Pitch, -20500, -9500);
	SetRotation(AdjustedRotation);

	// determine correct direction of light
	LightDirection = -vector(AdjustedRotation)*LightDistance;

	// set light direction
	ShadowTexture.LightDirection = Normal(LightDirection);

	// set lightdistance
	ShadowTexture.LightDistance = LightDistance;

	// update shadow texture FOV
	ShadowTexture.LightFOV = FOV;

	// set the drawscale, exaggerate a bit
	DrawS = (LightDistance * 0.82) * tan(0.5 * FOV * PI / 180) / (0.45 * ShadowTexture.USize);
	SetDrawScale(DrawS);

	// fade out gracefully
	if (bFadeOut)
		ShadowTexture.ShadowDarkness = Max(ShadowTexture.ShadowDarkness - (FadeSpeed*dt), 0);
	else
	{
		ShadowTexture.ShadowDarkness = 140*(1.0-(FClamp(VSize(ShadowLight.Location-Owner.Location)/ShadowController.MaxLightDistance, 0.0, 1.0))) + 70;
		if (bFadeIn && DarknessScale < 1.0)
		{
			DarknessScale = FMin(DarknessScale + ((FadeSpeed*0.007)*dt), 1.0);
			ShadowTexture.ShadowDarkness = float(ShadowTexture.ShadowDarkness)*DarknessScale;
		}
		else
			bFadeIn = false;
	}

	// dirty texture for reuploading to video
	bDirtyNextTime = !bDirtyNextTime;
	if(!Level.bAggressiveLOD || bDirtyNextTime)
		ShadowTexture.Dirty = true;

	// reattach projector
	AttachProjector();
}

function Destroyed()
{
	// free shadow texture from the object pool
	if (ShadowTexture != None)
	{
		ShadowTexture.ShadowActor = None;

		if (!ShadowTexture.Invalid)
			Level.ObjectPool.FreeObject(ShadowTexture);

		// must set to none
		ShadowTexture = None;
		ProjTexture = None;
	}
	Super.Destroyed();
}

simulated function DropShadowDetail() {
	local bool bChangeQuality;
	if(ShadowTexture == None) return;
	if(!Level.bAggressiveLOD) return;
	if(Level.TimeSeconds - DetailDropTime < 0.5) return; // ignore dropdetails if it's been less than 0.5 sec
	//log(self@" ... bing... Decreasing shadow detail from"@ShadowDetail);

	switch(ShadowDetail) {
		case Maximum:
			bCurrentBlobbiness = False;
			ShadowDetail = High;
			bChangeQuality = True;
			break;
		case High:
			bCurrentBlobbiness = False;
			ShadowDetail = Medium;
			bChangeQuality = True;
			break;
		case Medium:
			bCurrentBlobbiness = False;
			ShadowDetail = Low;
			bChangeQuality = True;
			break;
		case Low:
			bCurrentBlobbiness = False;
			ShadowDetail = VeryLow;
			bChangeQuality = True;
			break;
		case VeryLow:
			bCurrentBlobbiness = True;
			ShadowDetail = VeryLow;
			ShadowTexture.bBlobShadow = true;
			break;
	}
	if(bChangeQuality) {
		DetailDropTime = Level.TimeSeconds;
		if(!ShadowTexture.Invalid)
			Level.ObjectPool.FreeObject(ShadowTexture);

		ShadowTexture = None;
	}
	if(ShadowTexture == None) {
		CreateShadowTexture();
	}
}

simulated function IncreaseShadowDetail() {
	local bool bChangeQuality;
	if(Level.TimeSeconds - DetailIncreaseTime < 5 || ShadowDetail == Maximum) return;
	if(!Level.bDropDetail) {
		//log(self@" ... bing... Increasing shadow detail from"@ShadowDetail);
		switch(ShadowDetail) {
			case VeryLow:
				if(ShadowTexture.bBlobShadow) {
					ShadowTexture.bBlobShadow = false;
					bCurrentBlobbiness = false;
				} else {
					ShadowDetail = Low;
					bCurrentBlobbiness = false;
					bChangeQuality = True;
				}
				break;
			case Low:
				bCurrentBlobbiness = False;
				ShadowDetail = Medium;
				bChangeQuality = True;
				break;
			case Medium:
				bCurrentBlobbiness = False;
				ShadowDetail = High;
				bChangeQuality = True;
				break;
			case High:
				bCurrentBlobbiness = False;
				ShadowDetail = Maximum;
				bChangeQuality = True;
				break;
		}
		log(self@"New shadow detail="@ShadowDetail);
	}
	if(bChangeQuality && ShadowTexture != None) {
		DetailIncreaseTime = Level.TimeSeconds;
		if(!ShadowTexture.Invalid)
			Level.ObjectPool.FreeObject(ShadowTexture);

		ShadowTexture = None;
	}
	if(ShadowTexture == None) CreateShadowTexture();
}

simulated function CreateShadowTexture() {
	switch (ShadowDetail) {
		case VeryLow:
			ShadowTexture=ShadowBitmapMaterial(Level.ObjectPool.AllocateObject(class'Effect_ShadowBitmapMaterialVLow'));
			break;
		case Medium:
			ShadowTexture = ShadowBitmapMaterial(Level.ObjectPool.AllocateObject(class'Effect_ShadowBitmapMaterialMed'));
			break;
		case High:
			ShadowTexture = ShadowBitmapMaterial(Level.ObjectPool.AllocateObject(class'Effect_ShadowBitmapMaterialHigh'));
			break;
		case Maximum:
			ShadowTexture = ShadowBitmapMaterial(Level.ObjectPool.AllocateObject(class'Effect_ShadowBitmapMaterialMax'));
			break;
		Default:
			ShadowTexture = ShadowBitmapMaterial(Level.ObjectPool.AllocateObject(class'Effect_ShadowBitmapMaterialLow'));
			break;
	}
	if(ShadowTexture != None) {
		ShadowTexture.bBlobShadow = bCurrentBlobbiness;
		ShadowTexture.Invalid = false;
		ShadowTexture.ShadowActor = Owner;
		ShadowTexture.CullDistance = CullDistance;
		ProjTexture=ShadowTexture;
	}
}

// You can delete this function if you're using it on a game that has bNoProjectOnOwner, then set that
// in the Default Props.
simulated event Touch(Actor Other) {
	if(Other == Owner) return;
	super.Touch(Other);
}


defaultproperties
{
	ShadowDetail=Low
	bProjectActor=true
	// how quickly we should interpolate
	InterpolationRate=2.5
	// this should be dynamically updated also
	MaxTraceDistance=3500
	// maximum FOV
	MaxFOV=80.0
	// how quickly to fade in/out
	FadeSpeed=500.0

	bProjectOnParallelBSP=true
	bProjectOnAlpha=false
	bProjectStaticMesh=True
	bProjectParticles=False
	bClipBSP=False
	bGradient=True
	bStatic=false
	bOwnerNoSee=False
	bDynamicAttach=true

	bHidden=False

	RemoteRole=ROLE_None
	CullDistance=1200.0
}