Jump to content
barbolani

Fog does not tell you how foggy is today

Recommended Posts

Hi!

 

I'm back to Arma scripting :)

 

I want to make a dynamic AI decision on wether attack or not depending on several parameters. One of them is the fog state, which you know in Tanoa is important.

 

Ok, fog command does not tell you how foggy is the day, you may have 0.1 in return but due to the other params, you cant see a shit.

 

I played a bit with fogParams but I am not really getting what to tell the script to check to return is foggy or not. It seems it depends much more on how close to zero is the second param than the first one.

 

Any tip around?

 

Thanks in advance!

Share this post


Link to post
Share on other sites

are you using setFog in combination with fog?

Looks like fog Is just a getter for such, don't think the editor environment settings comply with the scripted ones.

Share this post


Link to post
Share on other sites

I am not setting fog, I am trying to know the fog status, but as I said, fog returns a number which is not really reliable to know if there is or not, big fog because of the other params seem to me more important.

Share this post


Link to post
Share on other sites

As Midnighters stated and the wiki describes:

 

Quote

 

Description

Description:
A getter for setFog. Returns the current value of the fog in range 0...1.

 

 

Same for fogParams...

 

It seems that you have to use setFog if u want to get Infos about.

  • Like 1

Share this post


Link to post
Share on other sites
6 hours ago, sarogahtyp said:

t seems that you have to use setFog if u want to get Infos about.

Correct!

Share this post


Link to post
Share on other sites

Im afraid you are not understanding me.

 

I dont want to change the fog.

 

Fog param getter commands work well with the engine fog, didn't touch anything on the weather settings and work well. Dont want to set anything.

 

What I want to know if it is a foggy day or not.

 

If you just say: if (fog > 0.5) then {hint "Today is a foggy day!"} you will see the hint in clear air sometimes.

 

If you pick data from fogParams you see the first param does not really affect on fog presence but a combination of the second and third param are the ones that make you experience fog depending on where you are.

 

EDIT: fog == fogParams select 0, useless command.

 

 

Share this post


Link to post
Share on other sites

The first parameter definitely affects the presence, it's the "thickness".

A while ago I tried to figure out how to get the perceived thickness at the player's position, but couldn't quite crack the code.

 

IIRC, the first value is the density at the base level (third param). The second, the decay rate, how quickly the fog gets thinner when going above the base, and how quickly it approaches full fog below it. I guess it's something like a percentage of the thickness per meter.

So [0.5,0.10,20] would mean 0.5 density at 20m ASL, which decays 10% per meter. So at 19m it's 10% thicker, and at 21m 10% thinner, i.e.  0.5 * (1 - 0.10) = 0.45.

 

Or I maybe completely wrong. I don't even remember did it even look like it worked like that. :)

Share this post


Link to post
Share on other sites
19 hours ago, barbolani said:

Im afraid you are not understanding me.

 

I dont want to change the fog.

 

Fog param getter commands work well with the engine fog, didn't touch anything on the weather settings and work well. Dont want to set anything.

 

What I want to know if it is a foggy day or not.

 

If you just say: if (fog > 0.5) then {hint "Today is a foggy day!"} you will see the hint in clear air sometimes.

 

If you pick data from fogParams you see the first param does not really affect on fog presence but a combination of the second and third param are the ones that make you experience fog depending on where you are.

 

EDIT: fog == fogParams select 0, useless command.

 

 

Once again, fog is a getter for fogParams and setFog. I don't see what you're so distraught about.

Share this post


Link to post
Share on other sites
18 hours ago, Greenfist said:

The first parameter definitely affects the presence, it's the "thickness".

A while ago I tried to figure out how to get the perceived thickness at the player's position, but couldn't quite crack the code.

 

IIRC, the first value is the density at the base level (third param). The second, the decay rate, how quickly the fog gets thinner when going above the base, and how quickly it approaches full fog below it. I guess it's something like a percentage of the thickness per meter.

So [0.5,0.10,20] would mean 0.5 density at 20m ASL, which decays 10% per meter. So at 19m it's 10% thicker, and at 21m 10% thinner, i.e.  0.5 * (1 - 0.10) = 0.45.

 

Or I maybe completely wrong. I don't even remember did it even look like it worked like that. :)

interesting observation.

Share this post


Link to post
Share on other sites

Fog explained

 

Spoiler

According to setFog description,

Quote

A little information about how Alt Syntax works. The fogValue is normal fog value that could be set independently with original setFog command. fogBase is the ASL altitude at which the fog will start. 0 is the sea level. fogDecay is how defined the fog start is. The more defined, the denser is the fog. 1 (or -1) are the max values. If it is positive the fog will be generated below fogBase line, if negative, above it. If fogDecay is small, the fog will transition more smoothly from no fog to full fog, and because of that it will cross fogBase line by quite a lot, depending on how small is fogDecay value

That really sounds like description of exponential function. So that for any point current effective fog value can be calculated as

BLq50XX.png

or sqf equivalent


effectiveFog = {
	private _z = param [0, 0, [0]];
	fogParams params ["_fogValue", "_fogDecay", "_fogBase"];
	_fogValue * exp ( - _fogDecay * (_z - _fogBase))
}

Sample graphs plotted for different fogDecay parameter:

Spoiler

1dHFPde.png

X axis is ASL position to where we calculate fog real effective value.
Y axis is calculated fog effective value.
All graphs plotted for _fogValue = 1 and _fogBase = 20.
_fogDecay values are as follows:
Red solid graph: 0.95
Cyan solid graph: 0.05
Dash graphs are their negative counterparts:
Red dash graph: -0.95
Cyan dash graph: -0.05
When _fogDecay is zero, function degenerates to _fogValue constant (green line).
Blue line represents _fogBase (added for clearness).
Notice how exponential functions can easily reach enormous values of fog coefficient (below base for positive decay, above for negative), you can only use 0..1 values for fogValue though.
Try  0 setFog [0.01,1,(eyePos player select 2) + 10]. Base is only 10 meters above your head; fog is only 0.01 (!) and you're in total milk. You will see your rifle though, and maybe your boots.

Spoiler

How does it look:

TgRmTtf.jpg

After getting several meters uphill:

iZGrbxn.jpg

0 setFog [1,0,0] for unit-density fog for reference.

 

Consider the magic number DFuwji2.png. It diminishes its coefficient (if any) by nearly 148 times. This is good to know when you're setting your fog decay range. For example you need the fog strip to go from fully dense fog to nothing in exactly 100m. Then your fogDecay is 5/100 = 0.05. For 20m it is 5/20 = 0.25. 20 meters of fog on the water is set by passing parameters [1, 0.25, 0] to setFog. Having maximum of fogDecay of 1.0 we have 5/1.0 = 5 m -- the thinnest gradient strip one can set. If you need 20m of fog on the water that looks really dense set the 5m strip with base of 15 m above water: [1, 1, 15].
Having other branch of exponenta going fast to huge numbers, this side seems to be under more control.

 

Ok, now when the real effective fog value is known, how do we know if it's foggy enough for AI to not see target?
Seems like Arma 3 simulates Beer–Lambert law. With attenuation coefficient being equal to fog value or to fog value multiplied by constant coefficient. At least zero fog corresponds to zero attenuation coefficient and the correlation is positive (bigger fog values cause more attenuation, just like bigger attenuation coeff.)

Given two points in space with ASL levels of z0 and z1 and 3d-distance l (small latin letter L, sorry if reads bad), we want to calculate light transmittance (T) of the fog between those points taking into account effect of fog with variable density.

BOK0vtU.png

To avoid confusion of mu's z argument (path length of the beam) with z coordinate in Arma, I rewrite it with argument t.
To get values of attenuation coefficient mu on beam's (0..l) we can map t values to corresponding values of z coordinate in range:

24LqhQw.png

where u is unknown unitless positive constant tieing fog value in Arma to attenuation coefficient (u might be 1 as well), and c and d — constants.

C22mUG2.png;

uHhXenU.png.

GCygEn7.png

in which form it can already be calculated (in terms of u) or can have variables substituted back:

B1kJynt.png

 

Some considerations:
-- linear dependency on l (seems natural): the longer distance the worse will be visibility;
-- l must not be zero if used for c constant (obviously for zero distance there's no attenuation), latest formula is actually ok with zero beam path;
-- linear dependency on fogValue (seems natural): the more dense fog the worse will be visibility;
-- fogDecay must not be zero to be used in these formulas: zeroes denominator (actually limit of dividing it with rightmost exp exist and equals 1); anyway, zero fogDecay is special case of uniform attenuation. No need to integrate anything, tau is just linear on beam path, so the following expression can be used:
xqXmMg9.png
-- for z1 == z0 (zeroes denominator) we again have uniform attenuation along the beam path (points with same level ASL).
-- tau >= 0, so that 0<T<=1: T makes good equivalent for some form of "visibility in fog" where 1 is fully visible and 0 is not visible;
-- transmittance T is exponent of -tau, and since exponent is monotonically growing on all its domain, to compare transmittances we can actually compare tau values: the greater tau, the lesser transmittance, and vice versa. Greater transmittance means better visibility; lesser tau means greater visibility. For single threshold T we can have single threshold tau. To convert threshold "visibility" T to threshold tau use this expression: fHR00Ws.png.

I'm not sure u might be or not be 1, so this formula is out of use for the time.

 

 

SQF.

/*
        Author: pedeathtrian

        Description:
        Returns optical depth between two points
        See also: https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law

        Parameter(s):
        0: POSITION
        1: POSITION
                (positions are in ASL format)

        Returns:
        NUMBER
*/

// takes two positions in ASL format;
params [["_pos0", [0,0,0], [[]], 3], ["_pos1", [0,0,0], [[]], 3]];
private _z0 = _pos0 param [2, 0, [0]];
private _z1 = _pos1 param [2, 0, [0]];
private _l = _pos0 distance _pos1;
fogParams params ["_fogValue", "_fogDecay", "_fogBase"];
_fogValue = _fogValue min 1.0;
_fogValue = _fogValue max 0.0;
_fogDecay = _fogDecay min 1.0;
_fogDecay = _fogDecay max -1.0;
_fogBase = _fogBase min 5000;
_fogBase = _fogBase max -5000;
private _dz = _z1 - _z0;
if (_dz ==0 || _fogDecay == 0) then {
        // covers _l == 0 too
        _fogValue * _l
} else {
        private _cl = -_fogDecay * _dz;
        private _d = -_fogDecay * (_z0 - _fogBase);
        // lim [(exp(x)-1) / x] = 1 as x->0
        if (abs(_cl) > 1e-4) then {
                _l * _fogValue * exp(_d) * ( exp (_cl) - 1.0) / _cl;
        } else {
                _l * _fogValue * exp(_d)
        }
}

What have to be done now is determining suitable threshold value which is by your taste is acceptable for AI to "see" the target.
Create some foggy setting and notice the returned value of function when you think AI should notice target. Write it to mission data, compare to that value. Better skilled AI might have slightly greater threshold for tau.

Spoiler

T7MHEym.jpg

 

8yYYPlE.jpg

 

Test mission.

 

Any questions? =)

Edited by pedeathtrian
UPD: forgor formulas for c and d
  • Like 3

Share this post


Link to post
Share on other sites
10 minutes ago, pedeathtrian said:

Fog explained

 

  Hide contents

According to setFog description,

That really sounds like description of exponential function. So that for any point current effective fog value can be calculated as

BLq50XX.png

or sqf equivalent



effectiveFog = {
	private _z = param [0, 0, [0]];
	fogParams params ["_fogValue", "_fogDecay", "_fogBase"];
	_fogValue * exp ( - _fogDecay * (_z - _fogBase))
}

Sample graphs plotted for different fogDecay parameter:

  Reveal hidden contents

1dHFPde.png

X axis is ASL position to where we calculate fog real effective value.
Y axis is calculated fog effective value.
All graphs plotted for _fogValue = 1 and _fogBase = 20.
_fogDecay values are as follows:
Red solid graph: 0.95
Cyan solid graph: 0.05
Dash graphs are their negative counterparts:
Red dash graph: -0.95
Cyan dash graph: -0.05
When _fogDecay is zero, function degenerates to _fogValue constant (green line).
Blue line represents _fogBase (added for clearness).
Notice how exponential functions can easily reach enormous values of fog coefficient (below base for positive decay, above for negative), you can only use 0..1 values for fogValue though.
Try  0 setFog [0.01,1,(eyePos player select 2) + 10]. Base is only 10 meters above your head; fog is only 0.01 (!) and you're in total milk. You will see your rifle though, and maybe your boots.

  Reveal hidden contents

How does it look:

TgRmTtf.jpg

After getting several meters uphill:

iZGrbxn.jpg

0 setFog [1,0,0] for unit-density fog for reference.

 

Consider the magic number DFuwji2.png. It diminishes its coefficient (if any) by nearly 148 times. This is good to know when you're setting your fog decay range. For example you need the fog strip to go from fully dense fog to nothing in exactly 100m. Then your fogDecay is 5/100 = 0.05. For 20m it is 5/20 = 0.25. 20 meters of fog on the water is set by passing parameters [1, 0.25, 0] to setFog. Having maximum of fogDecay of 1.0 we have 5/1.0 = 5 m -- the thinnest gradient strip one can set. If you need 20m of fog on the water that looks really dense set the 5m strip with base of 15 m above water: [1, 1, 15].
Having other branch of exponenta going fast to huge numbers, this side seems to be under more control.

 

Ok, now when the real effective fog value is known, how do we know if it's foggy enough for AI to not see target?
Seems like Arma 3 simulates Beer–Lambert law. With attenuation coefficient being equal to fog value or to fog value multiplied by constant coefficient. At least zero fog corresponds to zero attenuation coefficient and the correlation is positive (bigger fog values cause more attenuation, just like bigger attenuation coeff.)

Given two points in space with ASL levels of z0 and z1 and 3d-distance l (small latin letter L, sorry if reads bad), we want to calculate light transmittance (T) of the fog between those points taking into account effect of fog with variable density.

BOK0vtU.png

To avoid confusion of mu's z argument (path length of the beam) with z coordinate in Arma, I rewrite it with argument t.
To get values of attenuation coefficient mu on beam's (0..l) we can map t values to corresponding values of z coordinate in range:

24LqhQw.png

where u is unknown unitless positive constant tieing fog value in Arma to attenuation coefficient (u might be 1 as well), and c and d — constants.

C22mUG2.png;

uHhXenU.png.

GCygEn7.png

in which form it can already be calculated (in terms of u) or can have variables substituted back:

B1kJynt.png

 

Some considerations:
-- linear dependency on l (seems natural): the longer distance the worse will be visibility;
-- l must not be zero if used for c constant (obviously for zero distance there's no attenuation), latest formula is actually ok with zero beam path;
-- linear dependency on fogValue (seems natural): the more dense fog the worse will be visibility;
-- fogDecay must not be zero to be used in these formulas: zeroes denominator (actually limit of dividing it with rightmost exp exist and equals 1); anyway, zero fogDecay is special case of uniform attenuation. No need to integrate anything, tau is just linear on beam path, so the following expression can be used:
xqXmMg9.png
-- for z1 == z0 (zeroes denominator) we again have uniform attenuation along the beam path (points with same level ASL).
-- tau >= 0, so that 0<T<=1: T makes good equivalent for some form of "visibility in fog" where 1 is fully visible and 0 is not visible;
-- transmittance T is exponent of -tau, and since exponent is monotonically growing on all its domain, to compare transmittances we can actually compare tau values: the greater tau, the lesser transmittance, and vice versa. Greater transmittance means better visibility; lesser tau means greater visibility. For single threshold T we can have single threshold tau. To convert threshold "visibility" T to threshold tau use this expression: fHR00Ws.png.

I'm not sure u might be or not be 1, so this formula is out of use for the time.

 

 

SQF.


/*
        Author: pedeathtrian

        Description:
        Returns optical depth between two points
        See also: https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law

        Parameter(s):
        0: POSITION
        1: POSITION
                (positions are in ASL format)

        Returns:
        NUMBER
*/

// takes two positions in ASL format;
params [["_pos0", [0,0,0], [[]], 3], ["_pos1", [0,0,0], [[]], 3]];
private _z0 = _pos0 param [2, 0, [0]];
private _z1 = _pos1 param [2, 0, [0]];
private _l = _pos0 distance _pos1;
fogParams params ["_fogValue", "_fogDecay", "_fogBase"];
_fogValue = _fogValue min 1.0;
_fogValue = _fogValue max 0.0;
_fogDecay = _fogDecay min 1.0;
_fogDecay = _fogDecay max -1.0;
_fogBase = _fogBase min 5000;
_fogBase = _fogBase max -5000;
private _dz = _z1 - _z0;
if (_dz ==0 || _fogDecay == 0) then {
        // covers _l == 0 too
        _fogValue * _l
} else {
        private _cl = -_fogDecay * _dz;
        private _d = -_fogDecay * (_z0 - _fogBase);
        // lim [(exp(x)-1) / x] = 1 as x->0
        if (abs(_cl) > 1e-4) then {
                _l * _fogValue * exp(_d) * ( exp (_cl) - 1.0) / _cl;
        } else {
                _l * _fogValue * exp(_d)
        }
}

What have to be done now is determining suitable threshold value which is by your taste is acceptable for AI to "see" the target.
Create some foggy setting and notice the returned value of function when you think AI should notice target. Write it to mission data, compare to that value. Better skilled AI might have slightly greater threshold for tau.

  Hide contents

T7MHEym.jpg

 

8yYYPlE.jpg

 

Test mission.

 

Any questions? =)


Ah, the Beer-Lambert law, used that many a time with pulse oximeters and Kalman filters

But anyways, great and informative post!

Share this post


Link to post
Share on other sites

Update.

 

In short: Beer-Lambert part in my previous post incomplete, code DOES NOT work properly.
I conducted some experiments: measures aimed at determining u constant.
I set up uniform attenuation with zero fogDecay and different fogValues, then measured critical distance at which the same object switches from almost to completely invisible, assuming approximately equal amount of optical depth (LGXrW2X.png) reached for all cases. LGXrW2X.png should be somewhere close to 5 (the 6qXg7o7.png rule): NrBhX0G.png. That (assuming u is const too) should have given me 1Ge96nI.png, but it hadn't, that is, to my surprise and disappointment, even for uniform fog, transmittance DOES NOT conform to Jk1vgUF.png.
Expression
GyYhV81.png
should still stand true, but tau is clearly more complex than I thought before. Most likely it has form
RqcU07B.png
where ds9e0Us.png is optical depth calculated by code from my previous post, u and v are unknown functions on variables: z coordinates of points, fogValue, fogDecay, fogBase (and maybe more). v most likely adds or substracts, since one does not simply multiply on already logarithmic value. Not more than one function of u and v can be const.
I have no ways even to tabulate those functions separately, not saying to find their equations. There should be some physical processes simulated by Arma other than absorption which (probably) covered by ds9e0Us.png.

 

Any thoughts? =)

  • Like 1

Share this post


Link to post
Share on other sites

Wow!

 

First of all, I am the kind of guy with very basic math, so I got lost too early.

 

I  conducted some tests with combinations of all the possible patterns without getting a clear idea on what equation was behind, but never thought it was that complex with all those letters and numbers :)

 

What kind of number returns your function? My intention is to know if there is good weather to perform an assault, so I dont need ultra precise parameters, if a soldier cannot see clearly more than 200 meters on the target position, then dont attack, but I dont care if its 150, or 300...

 

 

Share this post


Link to post
Share on other sites
12 hours ago, barbolani said:

What kind of number returns your function?

It is logarithmic measure of how much fog decreases visibility of object. Being logarithmic means every unit added to the measure means visibility divided by correspondent value.
 

Spoiler

According to the setFog wiki page of BISim (thanks, @pierremgi), there might be another approach used to determine object visibility based on view distance: renderer cuts off objects based on this info and not on some cryptic optical transmittance values. View distance seem to be dependent on maximum view distance and fog value. So you take that calculated average fog value and apply it to second graph on the page to determine maximum view distance for that fog. If object is farther than this (or, say, 0.5 of this max distance), it should be considered not visible. Averaged fog should give better results than suggested maximum fog value of two points.

As using graph is not very practical in scripts, I tried to determine what this curve is. At first glance it looks like just exponential based on maximum view distance, fog value (same as for fog effective value based on fogValue and fogDecay) and some coefficient defining the speed of exponenta falling.

This btw fits way better to my experimental measurements than 1Ge96nI.png assumtion which gives hyperbola, not exponenta.

 

I represented the graph with this function: 6eW4z75.png

where f is fog value, lmax is the maximum view distance, and R is factor showing by how many times view distance decreased with transition from f = 0 to f =1.

On my system lmax is 6 km. On windows versions it seems to be 10 km. R on my machine appeared to be ~120. Might be same on windows version.

So here's what I got for this approximation.

 

Vertical axis is view distace (logarithmic scale), blue for calculated, red for experimental measure

Horizontal axis is fog value.

JMK8vH2.png

Though there's some excess near fog=1, in general, this estimate fits pretty well.

Excess might be caused by poor measurement "by eye", or probably because on short distances objects are better visible because they're close.

 

Now I suggest that when distance to object is greater than calculated view distance (or other threshold based on it), then object is not visible (visibility = 0). When object is lcoser, its visibility grows linearly from 0 (at max view distance) to 1 (at zero distance).

 

Fixed version, returning 0 for not visible and 1 for fully visible objects.

// takes two positions in ASL format;
params [["_pos0", [0,0,0], [[]], 3], ["_pos1", [0,0,0], [[]], 3]];
private _MaxViewDistance = 10000;
private _ViewDistanceDecayRate = 120;
private _z0 = _pos0 param [2, 0, [0]];
private _z1 = _pos1 param [2, 0, [0]];
private _l = _pos0 distance _pos1;
fogParams params ["_fogValue", "_fogDecay", "_fogBase"];
_fogValue = _fogValue min 1.0;
_fogValue = _fogValue max 0.0;
_fogDecay = _fogDecay min 1.0;
_fogDecay = _fogDecay max -1.0;
_fogBase = _fogBase min 5000;
_fogBase = _fogBase max -5000;
private _dz = _z1 - _z0;
private _fogCoeff = 1.0;
if (_dz !=0 && _fogDecay != 0) then {
	private _cl = -_fogDecay * _dz;
	private _d = -_fogDecay * (_z0 - _fogBase);
	// lim [(exp(x)-1) / x] = 1 as x->0
	if (abs(_cl) > 1e-4) then {
		_fogCoeff = exp(_d) * ( exp (_cl) - 1.0) / _cl;
	} else {
		_fogCoeff = exp(_d);
	}
}
private _fogAverage = _fogValue * _fogCoeff;
private _fogViewDistance = 0.9 * _MaxViewDistance * exp (- _fogAverage * ln(_ViewDistanceDecayRate));
0 max (1.0 - _l/_fogViewDistance)

This function returns 0.1 when object is at 0.9 of fog-defined view distance; 0.2 when object is at 0.8 of that distance, etc.

This function might require some tweaks, so any feedback is appreciated.

  • Like 1

Share this post


Link to post
Share on other sites

Hi!

 

After correcting an small typo is it seems to work!

 

The problem now: When using non ASL comparisons returns allways zero. I am not understanding why but I need to use this comparing marker position (third array param is zero) and a sample position.

 

Something like this:

 

 

_pos1 = getMarkerPos "marker_to_attack";
_pos2 = _pos1 getPos [100,0];
_result = [_pos1,_pos2] call fogCheck;
if (_result >0.3) then {attack!} else {dont attack!};

EDIT: Yes, I'm stupid :) Z coord. is a must to know if it's foggy on the target position or not. Will build the function creating a roadcone or whatever thing in the marker position until I find some way to know the ASL position of the ground level of a marker position. Thank you!

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×