As you know, Bge, Upbge, Range has that problem that there’s no real indirect lighting … so unless you full your scenes with tons of lamp ( with all the light bleeding it can causes and the severe harm it does on your fps) … your scene will be pretty dull and ugly (get only a single sun as light source to see how ugly your game will look like) . Ofc you can change the shadow color for not having it completely black and so it will be less harsh , but the problem remains : it looks so flat.
And so, Upbge 0.25/Range 1.0 is shipped with that combo of 2 hemi + Environement lighting to give some colors : a global blueish color with some hard orange to emulate some light bouncing off the ground … it roughly do the job : it looks less ugly and your scene is supposed to be happening outdoors.
But , when i came some times ago to a problem : how the hell can i get ride of that static global environement lighting that chase my character even when she is like in a 100 meter deep cave … Why , my character can have only 2 shades : exposed to the sun (with/without EL) and not exposed to the sun (with/without EL) …
The answer is in that often ignored/discarded input of the Extended Material node . That input provides
That input provides how much your material will confirm or cancel the global Environment lighting . Interesting thing : its point-based and not an uniform value → so providing a color texture will give details
And so , for static objects, you just need to provide an AO map and you are done .
Btw, for some reasons, there’s that myth that AO map has to be multiplied with the Diffuse map … it’s completely wrong to do so : color x black = black … you cannot retrieve your colors by adding source lights … your colors are gone , you cant go back. On the opposite : that Ambient input indicates how much you want to get ride of the Environment Lighting only .
Now, for the dynamic objects : problem, the typical baking cannot work ofc … for some reasons, i never encounter some concerns about this problem in the upbge community except some attempt done with a 2d filter that bugs with moving cameras … but there’s a solution i was thinking about and discovered later that such solution exist in games engines like Unity :
Light Probe !
The idea is simple : its to provide a global lighting but with local variations
Before get known on those things, i was thinking about solutions and some people here came with the idea of a ray to either read the closest vertex on the ground or the UV of the poly on the ground … as you might guess problem is when you get off that ground or that your character has to climb some stairs …
Due to the ray technic, the persian gonna get the ambiant color of the deepness before even falling
So, finally i come with this Light-Probe-3D-baking idea i would like to see implemented in Range engine
Get AO values in 3d space
--> bake on Vertex Colors of a Grid mesh the AO
--> Record the Values
--> Move the Grid +1 unit on the Z - Repeat the 2 above
--> Create a 3d Matrix of all the Values
--> Record it in a file
In game
first tic :
→ import that 3d matrix of 3d AO values [0,1]
when character is moving :
→ compute the worldposition of your character regarding the virtual 8 surrounding points of a cube in which your character is positionned into at that moment
→ compute a barrymetric weight to assign for each of those 8 surrounding points according their distance to the worldPosition of your character
→ compute a global score as being [weights] x [AO]
→ assign that weighted AO value to your object.color
import bge
from math import floor
from mathutils import Vector
## get the AO 3d matrix
from table import mm
scene = bge.logic.getCurrentScene()
cont = bge.logic.getCurrentController()
obj = scene.objects['Suzanne']
### X,Y,Z
point = obj.worldPosition
x , y , z = point
f = floor(x) ; g = floor(y) ; h = floor(z)
## virtual cube in which your character is standing in
cube = [(f,g,h),(f+1,g,h),(f,g+1,h),(f+1,g+1,h),
(f,g,h+1),(f+1,g,h+1),(f,g+1,h+1),(f+1,g+1,h+1)]
## retrieve associated AO values by Z,Y,X
values = [ mm[i[2]][i[0]][i[1]] for i in cube]
## just compute once the max normalized length existing in a cube
maxl = 3**0.5
## measure the 8 distances
dists = [(Vector(i) - Vector(point)).length for i in cube]
## normalized score
barry = [1-i/maxl for i in dists]
## sum of weights must be 1.0
sumb = sum(barry)
ws = [i/sumb for i in barry]
## final weighted AO score
ao = sum([i*j for i, j in zip(ws,values)])
## either you bake on high-vertex Grid , either you lerp a bit
obj.color = obj.color.lerp((ao,ao,ao,1.0),0.5)
Plug it to the Ambiant input (red, green, blue, they are all the same - only the level 0-1 matters)
Result (sun shadows are off and i baked also the AO on the castle so one can compare)
https://i.imgur.com/NQDhDrZ.mp4
soon : instead of using the Object color, i will use the Light Data node for making the Ambiant not uni-dimensional