1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. 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.

UE2 - UT2kX making a skybox corona visible

Discussion in 'Programming' started by Silver_Ibex, Jan 31, 2010.

  1. Silver_Ibex

    Silver_Ibex Member

    Joined:
    Feb 27, 2001
    Messages:
    654
    Likes Received:
    0
    Looking for a way in UT2k4 to make a corona in the map skybox visible to players, I know this was done to fake sun glare in the game Devastation see the attached pic, and in the game Raven Shield they used a directional corona, like how headlights are done it UT2k4, so the more directly you looked at it the bigger it was.

    I expect it is going to take some custom coding, so how would this be done in UT2k4? Has someone already done this for UT2k4 yet?
     

    Attached Files:

  2. Wormbo

    Wormbo Administrator Staff Member

    Joined:
    Jun 4, 2001
    Messages:
    5,913
    Likes Received:
    36
    You may need an Interaction and draw the corona in PreRender directly to the HUD. The problem will be figuring out if the skybox can be seen at the screen location where the corona would be.
     
  3. Wail of Suicide

    Wail of Suicide Member

    Joined:
    Apr 11, 2006
    Messages:
    738
    Likes Received:
    0
    Looks to me like they are using an emitter to create that effect. I have seen emitters used in several UT2004 maps to create a corona-like effect.
     
  4. Wormbo

    Wormbo Administrator Staff Member

    Joined:
    Jun 4, 2001
    Messages:
    5,913
    Likes Received:
    36
    Emitter or sprite actor - doesn't matter as both are drawn at their world location and thus get cut off by objects in front of them. Coronas are drawn after everything else and over all objects in the world.
     
  5. Wail of Suicide

    Wail of Suicide Member

    Joined:
    Apr 11, 2006
    Messages:
    738
    Likes Received:
    0
    I've attached a screenshot of a sunlight "corona" effect simulated using an emitter. The effect is pretty similar to a corona, not quite as good but mostly there.
     

    Attached Files:

  6. Silver_Ibex

    Silver_Ibex Member

    Joined:
    Feb 27, 2001
    Messages:
    654
    Likes Received:
    0
    thanks Wormbo, I am working on the code now :)
     
  7. Silver_Ibex

    Silver_Ibex Member

    Joined:
    Feb 27, 2001
    Messages:
    654
    Likes Received:
    0
    Ok I have two questions about working with Interactions

    how do I use an AllActors properly in an Interaction class? So it can find the SunLight.

    how do I tell it to Message the player properly in an Interaction class? So the player knows when it is working.

    Code:
    class SkyboxCorona extends Interaction;
    
    #exec OBJ LOAD FILE=wm_textures.utx
    
    var Vector SunDir;
    
    simulated function PostRender( canvas Canvas )
    {
    	local Actor Other;
    	local SunLight SL;
    	local Vector X, End, HitLocation, HitNormal,Start;
    	local Material HitMat;
    
        if(ViewportOwner.Actor.Pawn !=None)
    	{
    	start=viewportOwner.Actor.pawn.location;
    
    //	ForEach AllActors(class'SunLight', SL, )
    //the above line does not compile, it gives the following error
    // Error, 'ForEach': An iterator expression is required
    
    //So after looking through code of other Interaction class I found some that use "ViewportOwner.Actor.DynamicActors"
    //so I put in a "ViewportOwner.Actor." in front of the "AllActors" and it now compiles
    // but does not look to be doing anything
     
    	ForEach ViewportOwner.Actor.AllActors(class'SunLight', SL, )
    //how do I use an AllActors properly in an Interaction class?
    		{
    			if ( (SL != None) && (SL.Region.Zone.IsA('SkyZoneInfo')) )
    			{
    				X = (Vector(SL.Rotation))* -1;
    				End = Start + 50000 * X;
    				Other = viewportOwner.Actor.pawn.Trace(HitLocation, HitNormal, End, Start, true,, HitMat);
    				If ( (Other!=None) && (HitMat==Texture'wm_textures.sky') )
    
    					viewportOwner.Actor.pawn.ClientMessage("You are in SunLight");
    
    // how do I tell it to Message the player properly in an Interaction class?
    
    			}	
    		}
    	}
    
    }
    
    defaultproperties
    {
    bVisible=true
    bActive=true
    bRequiresTick=True
    }
    
     
  8. meowcat

    meowcat take a chance

    Joined:
    Jun 7, 2001
    Messages:
    801
    Likes Received:
    3
    Hi SI,
    Your code looks correct to me. But I have a few recommendations:
    1. Don't use the SL.rotation for the trace direction, instead use the vector pointing from the Sunlight actor to the SkyZoneInfo location since that is where you're viewing the corona from (just in case the SL does not point at the SkyZoneInfo actor exactly). You can then use the rotation later as in the directional corona class to attenuate the size.
    2. Keep a SunLight actor variable globally in the interaction class. Then just run the foreach allactors only when SL==none, after its been found there is no need to keep looking for it each tick/render.

    3. You could also consider searching for the SunLight actor exclusively in the SkyZone for the zone your pawn is in via the Region.Zone.SkyZone.ZoneActors(base class 'Class', out actor Actor) function.

    To keep from message spamming the pawn, just maintain a global bool variable which is set based on the success of seeing the sunlight actor, then use the Canvas.DrawText function to print the current status for debug purposes.

    Other wise (so long as the interaction has actually been added) it looks like the code you posted should work.
     
    Last edited: Mar 6, 2010
  9. Silver_Ibex

    Silver_Ibex Member

    Joined:
    Feb 27, 2001
    Messages:
    654
    Likes Received:
    0
    Thanks MeowCat, I found that using a "ForEach AllObjects" does the trick, now it is working and I can add the fancy stuff :)

    Code:
    class SkyboxCorona extends Interaction;
    
    #exec OBJ LOAD FILE=wm_textures.utx
    
    var Vector SunDir;
    
    event Initialized()
    {
    //	Log("=======Initialized=======");
    }
    
    
    simulated function PostRender( canvas Canvas )
    {
    	local Actor Other;
    	local SunLight SL;
    	local Vector X, End, HitLocation, HitNormal,Start;
    	local Material HitMat;
    
    //log("=======PostRender called=======");
    
        if(ViewportOwner.Actor.Pawn !=None)
    	{
    	start=viewportOwner.Actor.pawn.location;
    
    	ForEach AllObjects(class'SunLight', SL)
    			if ( (SL != None) && (SL.Region.Zone.IsA('SkyZoneInfo')) )
    			{
    				X = (Vector(SL.Rotation))* -1;
    				End = Start + 50000 * X;
    				Other = viewportOwner.Actor.pawn.Trace(HitLocation, HitNormal, End, Start, true,, HitMat);
    				If ( (Other!=None) && (HitMat==Texture'wm_textures.sky') )
    					{
    					viewportOwner.Actor.pawn.ClientMessage("Saw Sun");
    					//log("=======Saw Sun=======");
    					}
    
    			}	
    		
    	}
    
    }
    defaultproperties
    {
    bVisible=true
    bActive=true
    }
    
     
  10. meowcat

    meowcat take a chance

    Joined:
    Jun 7, 2001
    Messages:
    801
    Likes Received:
    3
    Cool! You may want to consider the recommendations I added to my previous post as I think they may be able to optimize the code.
     
  11. Wormbo

    Wormbo Administrator Staff Member

    Joined:
    Jun 4, 2001
    Messages:
    5,913
    Likes Received:
    36
    Oh no, please not AllObjects! That's extremely ineffective as it does not only iterate the entire actors list (that's quite inefficient already), it even iterates over all objects currently existing in (the UnrealScript-accessible part of) the application.

    Iterators for use with ForEach are just functions and they are called in a similar fashion, except that you put "ForEach" in front and a block (instead of a semicolon) afterwards. Get hold of an actor, such as the local player controller (you're already doing that via ViewportOwner.Actor in the very same function) and call the AllActors iterator on that one. Actually, instead of using AllActors you could look up the player Pawn's current zone and on its SkyZone you can call the ZoneActors iterator. That way you really make sure only SkyLights in the current sky zone are returned. Maps can be set up with more than one sky zone and by accessing the actually linked SkyZoneInfo you make sure you core also works correctly with those multi-skybox maps.

    BTW: You cannot assume that all maps use wm_textures.sky for their backdrop surfaces. It'd certainly be a good idea to do so, but there are many maps out there that use a different texture on their backdrop surfaces, including many Epic maps.

    The global sunlight variable is a good idea, but it should probably be a dynamic array of all sunlights in all skyboxes. You can build that list at startup (e.g. in the Interaction's Initialized() event) and iterate over the list, skipping over any sunlights in skyboxes other than the currently used one. Also, since sunlights are just Light actors with special property presets, maybe you should include all Light actors with LightEffect=LE_Sunlight in the list.
     
  12. Silver_Ibex

    Silver_Ibex Member

    Joined:
    Feb 27, 2001
    Messages:
    654
    Likes Received:
    0
    Thanks for the feedback :)
    I got the view angle brightness working, so the corona size depends on how close you are looking at the sun, see the attached pics.

    The script now only calls the allobjects once in the event Initialized() and then it saves the variables for use later.

    For example
    var Material SunCorona;

    SunCorona = SL.Skins[0]; //get the Corona material from the maps sunlight actor

    In the map I have the first skin slot set to EpicParticles.Flares.FlashFlare1

    However I have run into a problem with the DrawIcon, How do I tell it to use the SunCorona variable as the material?
    This does not compile
    Canvas.DrawIcon( SunCorona, draw_scale);

    The following works, but I want it to use the Corona the mapper sets up instead.
    Canvas.DrawIcon(material'EpicParticles.Flares.FlashFlare1', draw_scale);

    Any suggestions?
     

    Attached Files:

  13. meowcat

    meowcat take a chance

    Joined:
    Jun 7, 2001
    Messages:
    801
    Likes Received:
    3
    DrawIcon takes a 'texture' for the first parameter, not a 'material' (which is what the SunCorona var is). You need to use the DrawTile function directly instead of the DrawIcon wrapper.
     
  14. Silver_Ibex

    Silver_Ibex Member

    Joined:
    Feb 27, 2001
    Messages:
    654
    Likes Received:
    0
    Ok got it now :)
    For those that may run into the same problem, in the Class “Canvas” is where the “wrapper” function is located.

    Code:
    final function DrawIcon( texture Tex, float Scale )
    {
    	if ( Tex != None )
    		DrawTile( Tex, Tex.USize*Scale, Tex.VSize*Scale, 0, 0, Tex.USize, Tex.VSize );
    }
    
    To get the same draw effect with use of materials I adjusted the code and placed it in my class

    Code:
    var Material 	SunCorona;//this gets set during the Initialized event 
    
    //and in the function it uses
    local float draw_scale;//this gets set by  the angle finder
    
    Canvas.DrawTile( SunCorona, SunCorona.MaterialUSize()*draw_scale, SunCorona.MaterialVSize()*draw_scale, 0, 0, SunCorona.MaterialUSize(), SunCorona.MaterialVSize() );
    
     

Share This Page