Simple Cloud Spawner
Posted: Sun Nov 28, 2021 9:14 am
A big problem with clouds in outdoor areas in Doom is the obvious sky illusion that makes an outdoor sector seem much taller than it really is. That leaves one with few possibilities for convincing clouds. And surely Mars is a windy and dusty place. I've checked out the Realm667 fog and cloud generators that only go part way. The problem, it seems to me, is that one only wants clouds in sectors tall enough to make them not seem absurd and have a Goldilocks number of them. (Too few look silly, too many look silly.)
I think I've done that, but the results are rough so far. Here are screenshots:
https://i.postimg.cc/2ySNJ4Zt/Screensho ... 093216.png
https://i.postimg.cc/LX0x9fWw/Screensho ... 093159.png
As you can see there are a number of reddish-brown clouds in the courtyard. These gently float this way and that while slowly changing size and opacity as much as can be allowed using integers. Note the cloud shadows. These pan the courtyard also.
ZScript:
How this works is very simple. (It's the only way I could understand the math.) The script loops through sectors and spawns clouds in any sector with a defined SKY and a mid sector height of at least 128. It spawns a number of cloud spawners dependent on sector area. Sectors, note, are 2D irregular polygons; the area is calculated in the polygonArea function. The larger the sector, the more cloud spawners are dumped into it.
DECORATE:
Not fancy but functional. Each spawner spawns a cloud at a random location within 16-32 units of the ceiling, moving at a random speed and direction. The Cloud itself starts with the same X and Y scale and slowly increases or decreases scale along with opacity. I've added a fudge factor to the Y scale to make clouds appear oblong. My cloud sprite is a tinted PNG of a real cumulus cloud. I've left the original for the curious. The plain image is too hard to see against a bright sky; I like to think Martian clouds are reddish. I've watched this run for a few minutes here and there, and it's not unconvincing if that makes sense. For sprite clouds in an inevitably low ceiling area they look OK I think.
A lot of these choices are arbitrary, of course, and in very tall sectors the clouds will still be close to the top. I suppose in those cases they can be layered to create a greater illusion of depth. I didn't want them too close to the player, since that's fog and otherwise different.
I'm not sure all the flags are needed in the DECORATE definition, such as INTERPOLATEANGLES. It's pretty cool when the slowly drifting clouds cast shadows. Interestingly, these seem to mirror the density of the cloud. Changing the cloud_debug CVar will report some sector statistics, but it's all simple math (fortunately Doom sectors are not curved!).
I think I've done that, but the results are rough so far. Here are screenshots:
https://i.postimg.cc/2ySNJ4Zt/Screensho ... 093216.png
https://i.postimg.cc/LX0x9fWw/Screensho ... 093159.png
As you can see there are a number of reddish-brown clouds in the courtyard. These gently float this way and that while slowly changing size and opacity as much as can be allowed using integers. Note the cloud shadows. These pan the courtyard also.
ZScript:
Code: Select all
class clouds_EventHandler : EventHandler
{
// returns area of sector (irregular polygon)
float polygonArea(Sector sec)
{
Array<float> lineAreas;
for (int i = 0; i < sec.Lines.Size(); i++)
{
int v1x = sec.Lines[i].V1.P.x;
int v1y = sec.Lines[i].V1.P.y;
int v2x = sec.Lines[i].V2.P.x;
int v2y = sec.Lines[i].V2.P.y;
float avgY = (v1y + v2y) * 0.5 * .015625;
float widthX = (v2x - v1x) * .015625;
lineAreas.Push(avgY * widthX);
}
float totArea;
for (int i = 0; i < lineAreas.Size(); i++)
{
totArea += lineAreas[i];
}
return totArea;
}
// add cloud spawners
override void WorldLoaded(WorldEvent e)
{
Array<string> sky = {
"F_SKY1",
"F_SKY2",
"F_SKY3",
"F_SKY4"
};
int FLOOR = 0;
int CEILING = 1;
TexMan texture;
for(int i = 0; i < Level.Sectors.Size(); i++)
{
textureid ceilingid = Level.Sectors[i].GetTexture(CEILING);
SecPlane ceilingplane = Level.Sectors[i].CeilingPlane;
SecPlane floorplane = Level.Sectors[i].FloorPlane;
int ceilingZ = ceilingplane.ZAtPoint((Level.Sectors[i].CenterSpot.x, Level.Sectors[i].CenterSpot.y));
int floorZ = floorplane.ZAtPoint((Level.Sectors[i].CenterSpot.x, Level.Sectors[i].CenterSpot.y));
int centerheight = ceilingZ - floorZ;
if (sky.Find(texture.GetName(ceilingid)) != sky.Size() && centerheight > 128)
{
float pArea = polygonArea(Level.Sectors[i]);
int clouds = int(pArea * .03125);
vector3 v3 = (Level.Sectors[i].CenterSpot.x, Level.Sectors[i].CenterSpot.y, floorZ);
if (CVar.FindCVar("cloud_debug").GetBool())
{
console.printf("Sector: %d, Polygon Area: %f, needing %d clouds", i, pArea, clouds);
}
for (int ii = 0; ii <= clouds; ii++)
{
Actor.Spawn("CloudSpawner", v3);
}
}
}
}
}
DECORATE:
Code: Select all
Actor CloudSpawner
{
States
{
Spawn:
TNT1 A 1
TNT1 A 1 A_SpawnItemEx("Cloud", FRandom(-128, -128), FRandom(-128, -128), FRandom(ceilingZ - 32, ceilingZ - 16), FRandom(-0.25, 0.25), FRandom(-0.5, 0.5), 0)
STOP
}
}
Actor Cloud
{
var int user_XScale;
var int user_YScale;
var int user_dir;
+MISSILE
+NOBLOCKMAP
+NOGRAVITY
+CASTSPRITESHADOW
+BOUNCEONWALLS
+BOUNCEONCEILINGS
+NOBOUNCESOUND
+INTERPOLATEANGLES
RenderStyle Add
XScale 0.5
YScale 0.5
Alpha 0.15
States
{
Spawn:
TNT1 A 0
TNT1 A 1
{
user_XScale = 5;
user_YScale = 5;
user_dir = 1;
}
TNT1 A 1
{
user_XScale += user_dir;
user_YScale += user_dir;
if (abs(user_dir) == 10)
{
user_dir *= -1;
}
}
CMFX A 1 A_FadeTo(0.15 + (0.05 * user_dir), 0.1, FTF_CLAMP)
CMFX AAAAA Random(35, 72) A_SetScale((user_XScale + 5) * 0.05, user_YScale * 0.05)
GOTO SPAWN+2
}
}
A lot of these choices are arbitrary, of course, and in very tall sectors the clouds will still be close to the top. I suppose in those cases they can be layered to create a greater illusion of depth. I didn't want them too close to the player, since that's fog and otherwise different.
I'm not sure all the flags are needed in the DECORATE definition, such as INTERPOLATEANGLES. It's pretty cool when the slowly drifting clouds cast shadows. Interestingly, these seem to mirror the density of the cloud. Changing the cloud_debug CVar will report some sector statistics, but it's all simple math (fortunately Doom sectors are not curved!).