Bake into texture artifacts. Rasterization and centroids

Hi All.

I’m currently working on a GPU lightmapper for OpenFrameworks, inspired by an @evanwallace 's shader trick.

The idea is accumulating multiple shadowmaps into a texture to bake the lights.
For that, I’m using the UV coords of the mesh at the vertex shader to project the fragments in texture space.

gl_Position = vec4(texcoord * 2.0 - 1.0, 0.0, 1.0);

But I’m running into UV/raster artifacts.
At the edge of the polygons there are missing pixels and interpolation creates black lines.


The tiling effect is due the edge artifacts. The shadow texture should be seamless.

This is a known issue that is actually mentioned on the original project I’m basing my code on.

The webgl example solves this issue by generating two specific texture coordinates that match the edge of the texel and the centroid of the texel. But I’m using imported assets with predefined UVs.

I’ve read the documentation for centroid, but I can not get my head on it. I’ve tried using it to bake the texture and also to read it back into the forward render, but still the same results.

Please, any suggestion?
Someone with experience rendering into texture coords?

Greetings

// -----------------------------------------------------------------------------------
OpenGL 3.2
Linux archlinux 5.6.6-arch1-1
Intel® Core™ i7-6500U
NVIDIA GeForce 940M

Texture and FBO
Format = GL_RGBA32F_ARB
MinFilter = GL_LINEAR
MaxFilter = GL_LINEAR
TextureTarget = GL_TEXTURE_2D
Depth = false
Stencil = false
Samples = 0 // I've tried multisampling as well
WrapModeHorizontal = GL_CLAMP
WrapModeVertical = GL_CLAMP

Try GL_CLAMP_TO_EDGE instead of GL_CLAMP.

GL_CLAMP pulls in the border texel color, which is almost never what you want.

1 Like

Thanks for your reply.
I already tried with GL_CLAMP_TO_EDGE and does not change the result.

I’ve been checking out conservative rasterization.
I tried this extension on a nvidia graphics card and did not work.

glEnable(GL_CONSERVATIVE_RASTERIZATION_NV);
glConservativeRasterParameterfNV(GL_CONSERVATIVE_RASTER_DILATE_NV, 0.5);

Then I tried the intel version on an intel graphics card.

glEnable(GL_CONSERVATIVE_RASTERIZATION_INTEL);

The intel version did work but still did not totally solve the problem.
The shared edges are fixed now, but still having black seams. (with and without GL_CLAMP_TO_EDGE). And it does looks worse with the actual shadow map.

Top: glEnable CONSERVATIVE_RASTERIZATION
Bottom: glDisable CONSERVATIVE_RASTERIZATION

I’m currently trying to implement conservative rasterization as a geometry shader dilation.

Does everybody have same issues when rendering into a texture using the texcoord?

Pretty much. Essentially, rendering isn’t guaranteed to modify every pixel which will be sampled. Any pixel which intersects the mesh in UV space will affect the final render but only pixels whose centres lie inside the mesh will be rendered by the “baking” step.

How I’ve handled this in the past is to perform an explicit dilation step on the texture between baking and rendering. The texture has an alpha channel which is cleared to zero but set to one by rendering. The dilation step modifies pixels with zero alpha, copying the colour from neighbours with non-zero alpha.

But I don’t think I’ve touched that since the pre-shader days. With more recent versions, there are some alternatives. One option which springs to mind is to use a texture with an alpha channel as above and simply divide the sampled colour by its alpha component. If filtering produces a blend between (r,g,b,1) and (0,0,0,0), you get (a*r,a*g,a*b,a) where a is the blending factor, so dividing by the alpha component will restore the original colour.

Also, you shouldn’t be getting lines for triangles which share an edge in physical space. That implies you have texture seams where you don’t need (and shouldn’t have) seams. For a lightmap, edges which are shared in physical space should normally be shared in texture space unless the topology prevents it. That seems to be the main issue in the above images; it looks like the UV map has a definite gap between the tiles.

Centroid sampling isn’t relevant here; it’s only applicable to multi-sample rasterisation (MSAA). GL_CLAMP_TO_EDGE is (mostly) not relevant; it will affect sampling at the edge of the texture, but your main issue is between “tiles” within the atlas.

1 Like

Hi!
Thanks a lot for your response.

I already try dilation on the texture after baking it, but then I got some bleeding on the edges.
Dilation is also a technique used by @andsz on his Lightmapper.

I am not having lines on the shared edges. That seems working fine.
I do have the artifacts on the outer edges of the quads that are not shared.
this happens because rasterization discards fragments which centroid is not within the polygon, but texture mapping interpolation uses information from pixels that touch the polygon.

I’ve implemented dilation on the UV coords as geometry shader. Basically increases the the rasterization perimeter by 1px as the conservative rasterization would do.
This seems to solve the problem with the black gap at the edge of the polygons but still having artifacts when baking the shadow maps creating a tiling pattern.

Using the shadow map in forward rendering looks good, baking it onto a texture produces the artifacts.

Its seems to have something to be with the texture precision and the centroids. I do not want to depend on perfectly generated coords to solve this issue.

I am thinking on remapping the UVs with a triangle packer and have 2 sets of coords. One set for the original model textures and the other one for the generated (texel perfect) UVs for the baked shadow maps.

Any idea?
Suggestions on baking techniques?
Someone with similar experience?

Greetings

I solved the black edges issue by implementing my own conservative rasterization as geometry shader dilation.

Thanks for your help :slight_smile: