UE2 - UT2kX making a skybox corona visible

  • 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.

Silver_Ibex

Member
Feb 27, 2001
654
0
16
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?
 

Attachments

  • DevastationSunBloomFX.jpg
    DevastationSunBloomFX.jpg
    30.6 KB · Views: 30

Wormbo

Administrator
Staff member
Jun 4, 2001
5,913
36
48
Germany
www.koehler-homepage.de
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.
 
Apr 11, 2006
738
0
16
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.
 

Wormbo

Administrator
Staff member
Jun 4, 2001
5,913
36
48
Germany
www.koehler-homepage.de
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.
 
Apr 11, 2006
738
0
16
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.
 

Attachments

  • emitter.jpg
    emitter.jpg
    98.1 KB · Views: 24

Silver_Ibex

Member
Feb 27, 2001
654
0
16
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
}
 

meowcat

take a chance
Jun 7, 2001
803
3
18
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:

Silver_Ibex

Member
Feb 27, 2001
654
0
16
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
}
 

meowcat

take a chance
Jun 7, 2001
803
3
18
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.
 

Wormbo

Administrator
Staff member
Jun 4, 2001
5,913
36
48
Germany
www.koehler-homepage.de
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.
 

Silver_Ibex

Member
Feb 27, 2001
654
0
16
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?
 

Attachments

  • SunBloomA.jpg
    SunBloomA.jpg
    15.7 KB · Views: 12
  • SunBloomB.jpg
    SunBloomB.jpg
    15.2 KB · Views: 12
  • SunBloomC.jpg
    SunBloomC.jpg
    11.4 KB · Views: 12

meowcat

take a chance
Jun 7, 2001
803
3
18
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.
 

Silver_Ibex

Member
Feb 27, 2001
654
0
16
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() );