-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fog rendering and weather #201
Comments
I don't know about FOG.TXT, but the original game does appear to load the FOG.LGT file. |
I think FOG.TXT is actually used. Here are some notes from WalterPPK on Discord:
FOG.LGT is a light table that tells what colors to use for darker areas. 13 palettes for 13 light levels. |
As a temporary implementation, you can generate a random 40x25 array of 0.. |
I will try that soon. I am figuring out rain and thunderstorms right now, it seems fairly easy except for the lightning bolt generation. |
To test, I modified FOG.TXT in my directory and yes, it definitely is used. Modify the contents and you'll see artifacts appear in the fog in-game. |
Need to add TXT file support to the texture manager (ironically). It's not really a text file. |
I described lightning effects in the wiki. |
Thank you! I didn't know lightning bolts were just CFA files. I think I can get rain and thunderstorms done now. Do thunderstorms only happen during the night? I haven't tested extensively yet but it felt like it was only at night. |
Yes, from 18 to 6. |
If you want to emulate the original game exactly, I believe it is when the game minutes passed that day are < 360 (6:00) or > 1081 (18:01). Every time an in-game minute passes, a global value gets obtained like: value = ((TotalGameMinutes % 1440) * 1024) / 1440; which is the game minutes passed that game day, multiplied by 1024/1440. Then, as a condition for doing the lightning bolts, this value needs to be either < 0x100 or > 0x300, which should translate to < 6:00 or > 18:01. Of course, I imagine the intention was just basically getting it between 18 and 6. |
I'm able to get accurate time precision with my Clock class. I use that for streetlights and things already.
|
Rain and snow are done. Will be looking at thunderstorms next. I think I have everything I need, just need to do it. |
Thunderstorms now have flashes and sound. Adding lightning bolts tomorrow probably. |
Lightning bolts are working. Now this issue can be focused back on fog rendering. |
This should be FOG.TXT right? I don't think we would get anything valuable by right shifting values from FOG.LGT since it's just palettes. If I do |
Sure; |
Ah okay, I think it's coming together in my head now. Since Working through it now trying to make more sense of it. Haven't done any fixed-point stuff in this engine yet, or really ever. |
Also, the random values in the 40x25 matrix is because we don't know how to interpret FOG.TXT due to a complicated algorithm and/or self-modifying assembly? |
Yes, I am yet to guess the precise steps used for sampling. If you feel adventurous, try sampling every second pixel from a random position from |
I'm so close to being convinced that Arena uses some kind of spherical projection to map the fog onto the screen. If you turn the camera then the fog shimmers; parts of the texture appear and disappear. This makes me think it's a projection that's not 1-to-1 with the texture dimensions, and it's not always straight toward the texture. The fog also has an every-other-pixel pattern to it like you mentioned. I think there are two layers to the fog: the main fog texture and another one that slowly rotates around the player. It would seem that, since the zeroed-out row is in the middle of the screen, then the bottom ~50 rows of the 320x200 texture are unused because that's where the interface is, or maybe they are used in a different way. This is a weird weather effect! |
I just made one small discovery -- the right edge of the screen has a blocky appearance to it, like the 320x200 texture is not getting populated correctly from the noise algorithm, so it's like it's just the raw texels from the 40x25 texture. Easier to see against a dark background like a wall. Actually it looks like those tiles on the right edge are trying to wrap around the screen, like they are supposed to be 8 pixels left of the left screen edge instead. So this is probably an off-by-one bug. So I have a theory now. For each 8x8 tile on the screen, Arena projects a square onto the 320x200 texture and reads those values onto the screen, and then it does the every-other-pixel masking to give it that dither pattern. Every 16 frames it also moves some position across the texture like you mentioned which adds to the "slowly crawling" look. |
"Every other pixel masking" is just dithering. As fog level is float, the float part is propagated to the pixel to the right, giving that specific pattern. And yes, the fog transformation is applied to the rendered world. |
It appears to depend on the player angle. Also, data from A.EXE is used. I don't know if this will be helpful, as this is incomplete information, but in the function where FOG.TXT seems to be loaded, there is this:
A function is then called that uses those values in AX, CX and DI like follows: ushort index = DI * 2; where array1's data looks like [0, 402, 804, 1206 ...] going up in intervals of 402 in the beginning, but smaller values later on, up to 32766. array2's data looks like [32767, 32766, 32759 ...], starting at 32767 and then seeming to be a reverse of array1. The new values of AX and CX are then used in the fog function. Carmina16 can probably explain further. Is this kind of incomplete information useful for you, afritz1? Should I continue trying to reverse the fog function? |
That is rotation by the player angle. I hope to produce the sampling part soon. The corresponfing drawing procedure (the one above) is already understood. |
How do I use the low 8 bits of each FOG.TXT sample to do the dithering? I tried adding it as a delta but that just makes everything brighter and makes some pixels overflow to 0, resulting in black spots.
Does this mean generating a random XY position for every pixel, or does every pixel share that same one? |
Going to try passing this data to the renderer next but still don't feel like I understand everything completely. |
Something like that:
|
I'm thinking of merging what I have now to master and coming back to it later once we have more information on how it all works. I want to get started refactoring the UI since it's much larger of a task. Fog is at least bootstrapped in the renderer now, which is valuable because the remaining work is more about implementation details and the overall data flow into the renderer will not be as affected by future changes. One of my goals was to get 100% of the necessary resources captured in the renderer so it's easier to refactor everything as a whole. There is currently an issue with the clip space coordinates for the fog geometry. It does not project the fog texture properly if a corner of the fog cube is behind the camera. Need to figure that out at some point (basically just a math problem). Feel free to make a Fog page or revise the Weather page in the wiki if there is anything you two would like to add. |
I added the function from A.EXE (1.06) that samples from FOG.TXT to the Weather page of the Wiki, translated to C++, as well as a helper function it relies on. The function is called every game update (maybe only when rendering the 3d world) and two values that are increased by 4 just before every call (they are 0 at program start but are 4 by the time of the function's first call) have an effect on which data is sampled. Other than them, the player's X, Y, and angle affect the result, as does one more unknown value that might always be 0x92 when the function is called (it is modified by several parts of the game, being saved and restored when opening and closing menu screens, etc.) |
@afritz1 Added the next (last?) fog function as well, which uses the sampled data along with the contents of FOG.LGT. |
Thank you for exploring it in so much detail. I'll try to make sense of it after I get 0.15 out. |
Wow, that's some great detail. I believe the "changes every hour" part on the weather page may be inaccurate, as you can go in and out of any door repeatedly and it will change weather a few times within a couple real-world minutes even if the in-game hour does not increase. Related to this thread, I was experimenting with the lighting palettes and was wondering if it might be possible to block the (annoying to some) effects of fog. I see I can replace FOG.LGT with a copy of NORMAL.LGT and the lighting acts as if it is a clear day, but the view distance is cut short. Is there a way the files can be manipulated to remove the fog's view distance modifier perhaps by stubbing |
The functions, and FOG.TXT and FOG.LGT, probably aren't related to the drop in view distance, just to the fog effects that animate on the screen. (BTW I just changed "int SampleFOGTXT()" to "void SampleFOGTXT()" in the wiki since it isn't "returning" anything) |
Regarding the player angle, it may already be known, but the value is 0 at due south, 0x80 (128) at due west, 0x100 (256) at due north, and 0x180 (384) at due east. The maximum value it can hold is 0x1FF (511). |
Arena implements fog as light, so it's actually player light distance that's limited. Not sure how to change this gameplay value, maybe Arena hardcodes it during daytime. Light spells help at night though. |
I'll make sure to normalize those rendering values 0->1 as much as I can so the math is in vector space and will work at any resolution. |
When writing the entry for the fog functions I wrote the locations of data in the 1.06 EXE as they would be in |
In the original game, fog is an extra layer in screen space that follows the player around and acts like a mask over the scene.
I experimented with FOG.TXT a bit. After some trial and error, I got some decent results by treating it as an uncompressed 128x128 image, two bytes per pixel, and dividing each pixel value by 4096 to get an intensity percent.
This doesn't seem to be what the original game uses, and it was mentioned on Discord that the game uses a very complex noise algorithm instead.
The text was updated successfully, but these errors were encountered: