UE1 - UT Increase ambient lighting for the player only

  • Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

G-Flex

New Member
Oct 25, 2012
16
0
0
I'm working on a Deus Ex mod (sorry, no relevant prefix was available), and trying to fix the light amplification part of the vision augmentation.

Basically, what it's supposed to do is give green-tinted night vision. However, the current implementation is lacking:
Code:
gc.SetStyle(DSTY_Modulated);
gc.DrawPattern(boxTLX, boxTLY, boxW, boxH, 0, 0, Texture'SolidGreen');
gc.DrawPattern(boxTLX, boxTLY, boxW, boxH, 0, 0, Texture'SolidGreen');
gc.SetStyle(DSTY_Normal);

In effect, what this seems to do is enhance the green in all rendered pixels while discarding the red and blue. As a result, everything looks green, many things look brighter, but some things look dark, especially very red or blue things (blood looks solid black!). Even worse, since this is applied after basic lighting and rendering, it's still no good in dark areas because it cannot increase the level of detail (you effectively still have no dynamic range when looking at dark areas, as if they are still dark). In effect, it's almost strictly worse than just turning your gamma/brightness setting up.

I've been looking for a better way to do this in the Unreal engine, and I can't figure it out. I'd love to have some way to increase the apparent brightness for the player but not other actors, or otherwise meaningfully make the map look less dark, as if it were better lit than it actually is.

I know there's a render mode that effectively makes everything look unlit, but I tried it and it looks completely terrible.
 

meowcat

take a chance
Jun 7, 2001
803
3
18
Its been a long time since I played DeusEx so I don't quite remember how theyr night vision Aug worked. Here is my suggestion (which may be redundant to what DeusEx was already doing). When I recently updated my own night vision code for my UT2k4 YARM mod I ended up using both a custom screen overlay, much like what your code seems to be doing, and spawning a clientside only dynamic light with a relatively small radius. Each time the NVG was turned on the light was turned on (LightEffect = LE_steady or something like that) and then attached to my player (light.setbase(pawn);). It ended up working pretty nicely and looked quite a bit better than when I had only switched to the Unlit rendering mode with a green overlay.
 

G-Flex

New Member
Oct 25, 2012
16
0
0
Hrm, it's possible to do a client-side-only light that won't affect the vision of NPCs or other actors? If so, I'm interested in how that might work, because I haven't done anything strictly client-side/server-side yet, as I've only really worked with single-player stuff.

If I could do that as well as the green overlay, it might work, although I'd need to find a way for the green overlay to work differently so it doesn't simply exaggerate the green color in things while destroying the red and blue.

For what it's worth, the link to your YARM mod in your signature seems to be broken.

And to clarify how the Deus Ex code works: It's basically nothing but what I just pasted. It draws a green box, in modulated style, over the screen (or part of the screen? I forget). So the green component of pixels are exaggerated a bunch, and red and blue are discarded. That's literally all it does. Other levels of the vision augmentation do other things, but that's all the "LightAmp" aspect of it does.
 
Last edited:

meowcat

take a chance
Jun 7, 2001
803
3
18
The NPC's vision (at least in all other 'standard' UEngine games) typically has nothing to do with the lighting levels. The 'bot' vision is all based on their 'sightradius', 'peripheralvision' variables, the 'visibility' variable value of the other pawns being seen. When an internal timer goes off/counts to zero (see the 'sightCounter' variable), the game appears to iterate through the pawn list for the pawn whose timer just went off and does a Line-Of-Sight (LOS) trace check to see if the other pawn's are visible. If the pawn is within the sightradius (see threshold below) then the pawn (or pawn's controller for UT2kX and forward) receives a 'SeePlayer' or 'SeeMonster' notifcation. What I have not tested is how many times these events are called in a given visibility check cycle (e.g. if 20 pawns are visible, will an AI pawn receive the SeeMonster/Pawn event 20 times for that given visiblity check cycle provided it does not go to a state that ignores the event.)

Visibility Threshold = (OtherPawn.Visibility/128) * ThisPawnSightRadius;

As for the NVGs, here is some excerpts from my YARM mod's latest NVG code.
The Light which is spawned Clientside:
Code:
class NVGLight extends Light;

var NVGGogglesInv_yarm Goggles;

defaultproperties
{
    Texture=none
    LightType=LT_None//Steady
    LightEffect=LE_None
    LightBrightness=80
    LightSaturation=255
    LightRadius=18
    LightPeriod=34
    CollisionRadius=+5.0
    CollisionHeight=+5.0
    bHidden=true
    bStatic=false
    bNoDelete=false
    bMovable=true
    bDynamicLight=true
    bDirectional=false
    RemoteRole=ROLE_None
}

The Inventory NVG item (note this will not directly translate back into UEngine 1/2's class tree). See the PostNetBeginPlay function for where the Client's light and HUDOverlay are spawned on its machine (both of these actor have RemoteRole==ROLE_None):
Code:
//+=====================================
// NVGGoggles that allow the player to see in the dark using an effect similar to
// the one in Halo Reach (local light plus outline around pawns)
//+=====================================
class NVGGogglesInv_yarm extends Powerups;

var byte VisionMode;
var NVGgogglesHudOverlay  NVGVision;
var bool bNVGPlayerEffects, bUseBatteryLife;// if true cover the players in a "bright" shader in NVG mode , use up battery power
var float fBatteryPower, fRechargeRate;
var NVGLight MyNVGLight;

// Network replication.
replication
{
	// Things the server should send to the client.
	reliable if( bNetOwner && (Role==ROLE_Authority) )
		VisionMode, bNVGPlayerEffects, bUseBatteryLife, fBatteryPower, fRechargeRate, AddClientOverlay;
}


function PickupFunction(Pawn Other){
    local PlayerController PC;

	Super.PickupFunction(Other);
    // add the NVG view Hud Overlay on the listen server or standalone
    PC = Level.GetLocalPlayerController();
    if(PC!=none && PC == PlayerController(Instigator.Controller)){
        NVGVision=spawn(class'NVGgogglesHudOverlay');
        if(NVGVision!=none){
           PC.myHud.AddHudOverlay(NVGVision);
           NVGVision.PlayerOwner = PC;
           NVGVision.Goggles = self;
        }
        MyNVGLight=spawn(class'NVGLight',Instigator,,Instigator.location);
        if(MyNVGLight!=none){
           MyNVGLight.SetBase(Instigator);
           MyNVGLight.Goggles = self;
        }
    }
    AttachToPawn(Other);
}

simulated event PostNetBeginPlay(){
    local PlayerController PC;

    super.PostNetBeginPlay();
    if(Level.NetMode != NM_Client) return;
//    log("Goggles PostNBP -> Add Overlay and Light", 'NVGs');
    // add the thermal view Hud Overlay for the clients!!!
    PC = Level.GetLocalPlayerController();
    if(PC!=none && PC == PlayerController(Instigator.Controller)){
//        log("Goggles PostNBP -> Local PC & Instigator exist", 'NVGs');
        if(NVGVision == none) NVGVision = spawn(class'NVGgogglesHudOverlay');
        if(NVGVision!=none){
           PC.myHud.AddHudOverlay(NVGVision);
           NVGVision.PlayerOwner = PC;
           NVGVision.Goggles = self;
        }
        if(MyNVGLight == none) MyNVGLight=spawn(class'NVGLight',Instigator,,Instigator.location);
        if(MyNVGLight!=none){
           MyNVGLight.SetBase(Instigator);
           MyNVGLight.Goggles = self;
        }
    }
}

// this does not seem to ever get called...?
simulated function AddClientOverlay(){
    local PlayerController PC;

    if(Role==ROLE_Authority) return; // if already exists or on a standalone game don't do anything
    Pawn(Owner).ClientMessage("Goggles AddClientOverlay");
    // add the thermal view Hud Overlay
    PC = Level.GetLocalPlayerController();
    if(PC!=none && PC == PlayerController(Instigator.Controller)){
        if(NVGVision == none) NVGVision = spawn(class'NVGgogglesHudOverlay');
        if(NVGVision!=none){
           PC.myHud.AddHudOverlay(NVGVision);
           NVGVision.PlayerOwner = PC;
           NVGVision.Goggles = self;
        }
        if(MyNVGLight == none) MyNVGLight=spawn(class'NVGLight',Instigator,,Instigator.location);
        if(MyNVGLight!=none){
           MyNVGLight.SetBase(Instigator);
           MyNVGLight.Goggles = self;
        }
    }
}

function AttachToPawn(Pawn P){

	Instigator = P;
    if(yarmPawn(P) == none) return;// no third person for the non-yarm pawns just yet...
	if ( ThirdPersonActor == None ){
		ThirdPersonActor = Spawn(AttachmentClass,Owner);
		InventoryAttachment(ThirdPersonActor).InitFor(self);
	}
	else
		ThirdPersonActor.NetUpdateTime = Level.TimeSeconds - 1;
	P.AttachToBone(ThirdPersonActor,'NVGPos');// only visible in the third person view
}

// this function only runs on the server, but the variable is replicated down to the owner so that the Owner's HudOverlay can check it and see whether to turn on or off the NVG effects.
function Activate(){
   switch(VisionMode){
       case 0:
         VisionMode=1;
         Pawn(Owner).ClientMessage("NVG - ON");
         //MyNVGLight.LightType = LT_Steady; // do this via the overlay instead
         break;
       default:
         VisionMode=0;
         Pawn(Owner).ClientMessage("NVG - OFF");
         //MyNVGLight.LightType=LT_None;
         break;
   }
}

simulated function Destroyed()
{
   local PlayerController PC;

    // remove the thermal view HUDOverlay
    PC = Level.GetLocalPlayerController();
    if(Instigator!=none && PC == PlayerController(Instigator.Controller)){
        if(NVGVision != none) NVGVision.GogglesDestroyed();
    }
    if(MyNVGLight!=none) MyNVGLight.Destroy();
	super.destroyed();
}

defaultproperties
{
     VisionMode=0

     numcopies=1
	 bActivatable=true
	 bAutoActivate=false
	 bCanHaveMultipleCopies=false
     bOnlyDirtyReplication=true
	 bOnlyRelevantToOwner=true
	 bReplicateInstigator=true
	 AttachmentClass=class'NVGThird_yarm'
	 PickupClass=class'NVGPickup_yarm'
     BobDamping=0.960
     bTravel=True
     DrawType=DT_None
     AmbientGlow=0
     RemoteRole=ROLE_SimulatedProxy
	 NetPriority=3.0
	 NetUpdateFrequency=4.0
	 bOnlyOwnerSee=true
	 bHidden=true
	 bClientAnim=true
	 Physics=PHYS_None
	 bReplicateMovement=false
	 bAcceptsProjectors=false
     bDrawingFirstPerson=false
     IconMaterial=Material'ymPickupIcons'
     IconCoords=(X1=0,Y1=0,X2=127,Y2=127)
}

And here is the pertinent code for the HUDOverlay, which I don't quite remember what the similar actor was in the old engine, HUDMutator perhaps? Since the HUDoverlay is spawned clientside by the PostNetBeginPlay function in the inventory item, it can control the light as well (which was also spawned clientside at the same time) by switching them on and off based on what the 'VisionMode' variable is set to.
Code:
//=============================================================================
// NVG goggles HudOverlay. By "meowcat"
// Similar to the HR NVG view effect
//=============================================================================

class NVGgogglesHudOverlay extends HUDOverlay;

var bool bOn, bWasOn;
var Shader NVGplayer;
var Material View, ColorMat, EnvMap;
var color color_nvg, color_view;

var float lastCheckTime;
var float FadeTime; // for fading the screen from black
var sound toggleSound;
const NVGDRAIN = 1.0;
const MAXDIST = 3072;

var NVGGogglesInv_yarm Goggles;
var() PlayerController PlayerOwner;

// close up shop so to speak
simulated function GogglesDestroyed(){
    if(PlayerOwner!=none) PlayerOwner.rendmap=5; // reset rendering mode in case it was changed
    Destroy();
}


function Render( Canvas C ){
    local float currtime;//, percentPower;
    local Pawn RP;
    local pawn P;
    local float fadevalue;

    if(Goggles != none) bOn = (Goggles.VisionMode > 0);
    else GogglesDestroyed();

    currtime = level.timeseconds;

    P=PlayerOwner.Pawn;

    if ( currTime - FadeTime <= 0.8 ){
        FadeValue = 255 * ( 1.0 - (currtime - FadeTime)/0.8);
    	C.DrawColor.A = FadeValue;
    	C.Style = 5;
    	C.SetPos(0,0);
    	C.DrawTile( Texture'Engine.BlackTexture', C.SizeX, C.SizeY, 0.0, 0.0, 16, 16);
    }

    // Handle switching of goggles on and off
    if(bOn && !bWasOn){
       bWasOn=true;
       //if(Goggles.VisionMode==1) PlayerController(P.Controller).rendmap=6;  // No unlit mode in this version
       if(P !=none) P.PlayOwnedSound(toggleSound, SLOT_Interact,0.5,,,,false);
       FadeTime = level.timeseconds;
       Goggles.MyNVGLight.LightType = LT_Steady;
       Goggles.ThirdPersonActor.bHidden = false;
    }else if(!bOn && bWasOn ){
       bWasOn=false;
       Goggles.MyNVGLight.LightType = LT_None;
       Goggles.ThirdPersonActor.bHidden = true;
       PlayerController(P.Controller).rendmap=5;
       if(P != none) P.PlayOwnedSound(toggleSound, SLOT_Interact,0.5,,,,false);
       FadeTime = level.timeseconds;
       // clear all of the overlay stuff
       ForEach P.DynamicActors(class'Pawn', RP, ){
                ....... // I removed all of the Overlay material removal code from this section 
               }
           }
    }

    // draw all the fancy stuff
    if(bOn){

    	if(Goggles.VisionMode==1){
            // Night Vision
            PlayerController(P.Controller).rendmap=5;
            C.Style = 255;
    	    C.DrawColor=color_nvg;
            C.SetPos(0,0);
    	    C.DrawTile( ColorMat, C.SizeX, C.SizeY, 0.0, 0.0, ColorMat.MaterialUsize(), ColorMat.MaterialVsize() );

           // set these here so that the client machines will not see when the ListenServer's goggle overlay material
            NVGplayer.Diffuse=TexPanner'XGameShaders.ZoomFX.ScreenNoisePan';
            ....... // I removed all of the Overlay material code from this section

    }
    // update the last check time
    lastCheckTime =  currtime;
}


defaultproperties
{
     View=Material'NVGview'
     color_nvg=(r=0,g=200,b=0,a=120)
     toggleSound=sound'MenuSounds.MS_CLick'
.....
 
Last edited:

G-Flex

New Member
Oct 25, 2012
16
0
0
I'm not sure how much of that is applicable here since Deus Ex uses very different AI functions and parameters for determining visibility of other actors (which do take lighting into account), but I'll see what I can do. Thanks!
 

meowcat

take a chance
Jun 7, 2001
803
3
18
Are you sure it takes lighting into account? I went through the source code and although I saw the references to whether or not the player had the various Augmentations turned on (cloak for instance) I did not see anything that specifically indicated that the pawn's lighting level was considered (obviously there could be some native code "magic," but there are usually some other UScript hooks or references).

There was some specific AI code that looked for 'Beam' type lights owned by the Human player (used by the Light Augmentation), but that appeared to be it.

I think you should be good with a local light :)! Or maybe just turn the player pawn itself into a light by turning on the light properties of the pawn (if singleplayer only...).
 
Last edited:

G-Flex

New Member
Oct 25, 2012
16
0
0
I've done tests, and the return value of the AICanSee() function definitely varies depending on how well-lit the player (or presumably whatever other actor) is, and that value is used (in some manner that's hard for me to figure out) in determining whether or not the player is seen. It's true that the player's CalculatePlayerVisibility() function doesn't take lighting into account, but AICanSee() appears to do that itself.

For what it's worth, I've tried using a special light before class that has bNoDelete=False and RemoteRole=ROLE_None, and summoning it using command-line cheats (that call a simulated function to spawn it), but that didn't seem to work (it still affected ScriptedPawn vision). I'll try a little more in a bit, though, if I can think of something.
 
Last edited:

meowcat

take a chance
Jun 7, 2001
803
3
18
hmm, that is definitely interesting. Do you think the 'CurrentVisibility' variable in the base actor class stores this info? I'd be curious to see if you can "brute force" override the visibility-affected-by lighting thing. I wonder if the dynamically spawned light's LightEffect was set to type LE_StaticSpot (or maybe LE_SearchLight) that the native visibility updates/AI checks would not be effected provided the light was spawned and kept in front of the PlayerPawn?

Since the ScriptedPawn code specifically looks for the 'Beam' subclass of lights that kind of makes me wonder if some setting in it (class'Beam') automatically disables it from affecting the pawn's lighting/AI visibility. If that is the case then you could always try using a subclass of 'Beam' (with the timer function overridden to nothing so that the MakeNoise function is not called) and then work with it as the dynamic light, making sure to keep the brightness 32 or less (to exempt it from the CheckBeamPresence function's check in ScriptedPawn). Or just experiment with the display variables to see what does or does not effect visibility.
 

G-Flex

New Member
Oct 25, 2012
16
0
0
Nah, the Beam class affects visibility the same way (I've tried). I'm not sure why NPCs react to it specifically; I think it's to force them to react to it as if it's an odd thing (similar to a loud noise), and not just a normal light.

Also: Even if the light is far enough in front of the player to not affect the player's visibility, that still causes problems, because then the player would effectively be farsighted (since nothing too close is being lit up well), and it would also light up other things the NPCs might be looking for. Brute-forcing a given variable has the same problem, among other problems, like AICanSee() returning a maximum of 1.0 (so if it would exceed that, it's capped, so you can't know what it would be without that light present).