I have solved the dark edges in lightmaps problem!

Blitz3D Forums/Blitz3D Programming/I have solved the dark edges in lightmaps problem!

sswift(Posted 2003) [#1]
And it is absurdly simple to solve!
(Even though some folks claimed it could not be solved!)

I was playing around with YAL from the code archives... the newer 1.4 version today. (As opposed to the actually older "update" version listed after it.)

Anyhow, I looked at a few pages on lightmapping an radiosity trying to find info on how someone else solved the problem, but I couldn't find anything.

Then, it occured to me that a texel that is inside a wall is on the back side of all polygons the wall is made of.

But a texel which is actually obscured by geometry is on the OUTSIDE of the geometry.

It was then that I realised that the only problem with YAL's lightmapping was that one function call had the paramters reversed:

If EntityVisible(LumelPivot, LightPivot)
;If EntityVisible(LightPivot, LumelPivot)
NHits = NHits + 1
EndIf

The original code, commented out, can be found in the LMLightProcess() function.

As you can see, instead of the light looking at the lumel to see if the light can see the lumel, the lumel looks at the light to see if it can see the light. Now, if a lumel is inside a wall, it can see the light, because the wall, facing away from the lumel, will be culled, and the lumel will be lit. But if it is on the outside of the wall, but on the opposite side from the light, a polygon, which is not culled because it faces the lumel, will be in the way, and the lumel will not be able to see the light.

...

There is one problem with this method of lighting however.

With this method, it becomes possible for light to bleed under walls. This will be potentially visible in dark areas.

However, because of the nature of levels being brightly lit, and the fact that you're much less likely to have pixels improperly lit by light, than improperly shadowed by being partly outside of the level or partially inside walls, this is a worthwhile tradeoff.

Also, I beleive that if you sampled each texel from the four corners rather than from the center, and if any of those were shadowed the texel was shadowed, then that would solve that final issue of light bleeding under walls.

Here is a before and after pic from YAL:





You'll notice that something doesn't look quite right with the cube in the center. For one, there appears to be a dark shadow extending out from the bottom of it onto the larger cube. And for another, the sides of it are darker.

I'm not sure exactly what is causing these issues. I beleive that there's couple bugs elsewhere in YAL which is causing these two issues.

I think that the dark edges on the small cube may be caused by bilinear filtering because the areas adjacent to those edges are outside of the area calculated by the lightmap. I think YAL may be calculating lighting info for only those texels which are actually inside the polygons. If so, then the solution is to calculate an extra texel or two outside of the polygons.

As for the dark shadow along the base of the cube... That's caused by the dark area inside the cube leaking out. If you go inside the cube it's the same color as the area inside the cube. Come to think of it, I'm not sure actually why there is any dark area inside the cube at all. The floor under the cube should be able to see the light... Unless... Maybe the cube's bottom side is managing to hide those texels. That could be it I suppose. I'm not posiive though. If so, then it seems that a properly consturcted level would not have this issue because you shouldn't even have a floor inside that cube, nevermind having that cube have a bottom to it.

[edit]
Yes, moving the little cube down a fraction of an inch puts it's bottom beneath the floor of the larger cube, and as a result, the shadow along the lower edge of the small cube which should not be there dissapeared, and a tiny bit of light bleed under the cube showed up, but it's much less visible and would probably be virtually impossible to see with real textures there.

But the dark edges are still on the small cube itself. Have to find some way to calculate extra pixels around the polygosn for the lightmaps... But I'm not very familiar with YAL's code yet.
[/edit]


IPete2(Posted 2003) [#2]
I hope some of this cleverness rubs off on others who frequent these forums...er like me!

Well done Shawn!

IPete2.


sswift(Posted 2003) [#3]
I have solved the dark edges on the cube problem, and significantly reduced the dark band you got on one side of the cube.

You need to change this function. Look for the comments that have (sswift) in them. You will also need to change the terrain lighting function in the same manner.

Bascially, the problem was that the lightmapper was casting rays from the light to the TOP LEFT CORNER of each lumel instead of at the lumel's center. The center of each lumel corresponds to the center of each pixel in the lightmap. So it was sampling from the wrong place.

See link two messages down.



The only issues now are that the top of the cube displays slightly lighter bands near it's edges, and near the bottom of the cube on the floor you see either a slightly lighter shade or slightly darker shade in the lightmap depending on wehther you offset the cube into the floor a tiny bit or not.

You should be able to reduce these artifacts by doing 4x antialiasing on the lightmap. Ie, sample it at twice the resolution and then average it down. But that won't solve the issue entirely.

As for how to solve the issue entirely, I think you'd need to be able to detect when a texel is partially in shadow so you can darken it. So that would involve sampling at each of the 4 corners of the texel. Then texels which have a center that is just inside a wall on the opposite side of the wall from a light would have two corners out side the wall on the shadowed side of the wall, and that texel would therefore become shadowed.


sswift(Posted 2003) [#4]
Okay, I fixed the problems.

First, I set the lightmapping function so it would accept the current lumel size as a parameter. Then, I used that value to calculate the corners of the lumel. Then I check all four corners of each lumel to see if it can see the light source. If ALL of them can, then that lumel is in the light.

(You might want to increase the size you pass to the function depending on the amount of blur you use. It may help to avoid areas being lit by the blur that should not be lit.)

Then, I added a constant which allows you to move the lumel pivot away from the surface it is illuminating in the direction of the lightmap mapping. By moving it away from the surface a tiny bit, objects that rest flat on the ground and have bottoms no longer have black outlines around them on the ground, and there are no black outlines around the edges of some objects like the cube which had some new black outlines caused by the more agressive shadowing.

The only remaining issue is that the dark top of the cube has a tiny bit of light at the fornt and back edges. I'm not sure why this is. I think it might have to do with the light under the wall leak issue with this different way of lighting. In that case I don't know how to solve it.

Here's a pic of the latest version:



And here's a link to the latest code. The terrain functions still need to be updated. I'm not gonna muck about with it though, I'm just messing around with this cause I'm bored.

http://home.earthlink.net/~sswift/514-004.bb

I think I'm gonna try one last thing with this. I'm gonna try going back to the old method of calculating which lumels are hit by light, but then make any lumel which has a corner that is lit be lit, and see what that does.


sswift(Posted 2003) [#5]
Well I tried the old lighting method with the new 4 sample method from the lumel corners, but while it did fix a lot of artifacts it still left a bunch and created new ones that I'm not sure how to fix, so it looks like the above will be as good as it gets for now.


jfk EO-11110(Posted 2003) [#6]
Amazing work! I'm am hopeful the new problems will be solved the sooner or the later.


JaviCervera(Posted 2003) [#7]
sswift GREAT WORK!!! I have fixed this horrible bleeding in BSP Factory! Thank you!


DJWoodgate(Posted 2003) [#8]

The only remaining issue is that the dark top of the cube has a tiny bit of light at the fornt and back edges. I'm not sure why this is. I think it might have to do with the light under the wall leak issue with this different way of lighting. In that case I don't know how to solve it.



Is this due to bilinear filtering? Perhaps duplicating the border pixels for each image in the lightmap will solve it?


Koriolis(Posted 2003) [#9]
I made the exact same guess. It's logical that this happens if polygons are packed without any border betyween them in the textures, and there's nothing else (other than creating a one-pixel border) you can do to prevent this. The problem being that this would require independant sets of texture coordinates for adjacent polygons (to have a delta of one pixel between the texture coordinates of a vertex for different polygons). And I don't see how you can do that (in the present state of b3d) without unwelding every vertex, which is not a very good idea. So better keep going in this way SSwift : cheating a little bit to minimize the artefacts.
If we had more than 2 texture coordinates sets in b3d, we could make "clever" processing to have adjacent polygons use different sets, thus allowing to have independant texture coordinates for each polygon, without duplicating the vertices. This way we would have perfect, sharp borders.


sswift(Posted 2003) [#10]
"Is this due to bilinear filtering?"

I'm not sure. It is either that, or it is lighter pixels around the edges of the map caused by the pixels off the map being in the light because there's no surface between then an d the light because in reality they are off the edge of the polygons on the top of the cube.


"Perhaps duplicating the border pixels for each image in the lightmap will solve it?"

It probably would, but you'll have to determine those borders using the actual polygons mapped to the lightmap, which is too much work for me. :-)

And you have to make sure that the lightmaps as it is don't already butt up against one another. Which unfortunately, I think they do, because YAL combined multiple polygons into single "surfaces". So you'll have to duplicate only the edges of the triangles in those "surfaces" which do not touch other triangles in the surface.


sswift(Posted 2003) [#11]
I thought that it was likely that the top of the cube was being illuminated by the lights below, but it looks like I was wrong, and that YAL does in fact check the angle of incidence for light rays hitting the surfaces and attentuates the light properly. So a lumel that's off a surface should still be facing away from the light and be dark, even if there's really nothing between it and the light.

So that can't be the issue.

The only remaining possiblity is bilinear filtering... And looking at the lightmap that is generated, I think I can say that this is our culprit. I'm pretty sure the top of the cube is being put in the top right corner, which means that on each side of it sit the much larger light grey lightmaps. (YAL compresses lightmaps with low contrast more than others)

Unfortunately it looks like YAL must stick it's UV's right up against the map edges. So we can't simply draw extra pixels around it. We'll have to find a way to get it to make the polygons smaller within the lightmaps.


sswift(Posted 2003) [#12]
I found a totally unrelated bug in YAL while looking through it.

The function which decided whether a lightmap had a small enough amount of contrast to compress was comparing the maximum R G or B with the minimum R G or B. The result of this was that a pure red map would be considered high contrast because G and B would be 0 and red would be much greater.

So I fixed the function to compare each channel seperately and then return the contrast of the one with the highest contrast.

And here's a link to another post I made about it so as not to muck up this thread with wide code.

http://www.blitzbasic.com/bbs/posts.php?topic=25245


sswift(Posted 2003) [#13]
Okay I got rid of the lighting on top of the cube, but I don't really understand the math behind what I did.

Here's the code I changed in the LMSetupSurface function:

	; Reduce black borders
	; (sswift)
	; Multiplying by 3.0 eradicates the light bleeding from adjacent lightmaps, but I don't know why, or what
	; effect changing the lumel size will have.
	;DT# = lumelsize * Float(blurradius + 1)
	DT# = LumelSize# * Float(BlurRadius# + 1.0) * 3.0



As you can see I simply multiplied DT# by 3.0 above and beyond what it was already set to for removing black borders. Unfortunately, I don't have a complete grasp of all the mathmatical goings on here at the moment so I don't know what exactly I've done, and whether it will stand up to changing the lumel size or if it is going to be wasting tons of space in the lightmap. The lightmapping LOOKS fine though with the current lumel size. I will have to change the lumel size and see what the effect is now and try to understand what I've done to make sure it's a good solution.


Mustang(Posted 2003) [#14]
but I don't really understand the math behind what I did.


:)