barbolani 198 Posted May 10, 2017 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
Midnighters 152 Posted May 11, 2017 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
barbolani 198 Posted May 12, 2017 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
sarogahtyp 1109 Posted May 12, 2017 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. 1 Share this post Link to post Share on other sites
Midnighters 152 Posted May 12, 2017 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
barbolani 198 Posted May 13, 2017 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
Greenfist 1863 Posted May 13, 2017 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
Midnighters 152 Posted May 14, 2017 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
Midnighters 152 Posted May 14, 2017 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
pedeathtrian 100 Posted May 14, 2017 (edited) 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 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 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: After getting several meters uphill: 0 setFog [1,0,0] for unit-density fog for reference. Consider the magic number . 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. 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: 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. ; . in which form it can already be calculated (in terms of u) or can have variables substituted back: 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: -- 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: . 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 Test mission. Any questions? =) Edited May 14, 2017 by pedeathtrian UPD: forgor formulas for c and d 3 Share this post Link to post Share on other sites
HallyG 239 Posted May 14, 2017 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 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 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: After getting several meters uphill: 0 setFog [1,0,0] for unit-density fog for reference. Consider the magic number . 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. 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: 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. ; . in which form it can already be calculated (in terms of u) or can have variables substituted back: 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: -- 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: . 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 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
pedeathtrian 100 Posted May 17, 2017 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 () reached for all cases. should be somewhere close to 5 (the rule): . That (assuming u is const too) should have given me , but it hadn't, that is, to my surprise and disappointment, even for uniform fog, transmittance DOES NOT conform to . Expression should still stand true, but tau is clearly more complex than I thought before. Most likely it has form where 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 . Any thoughts? =) 1 Share this post Link to post Share on other sites
pierremgi 4906 Posted May 17, 2017 Yeah! That's a big deep fog! By this weather >> Did you read that? hips! Share this post Link to post Share on other sites
barbolani 198 Posted May 18, 2017 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
pedeathtrian 100 Posted May 19, 2017 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 assumtion which gives hyperbola, not exponenta. I represented the graph with this function: 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. 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. 1 Share this post Link to post Share on other sites
barbolani 198 Posted May 21, 2017 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
pedeathtrian 100 Posted May 23, 2017 Check out these commands, might be useful: ATLToASL, AGLToASL and getTerrainHeightASL Share this post Link to post Share on other sites