lightmaps without seams

Started by
6 comments, last by ldeej 16 years, 6 months ago
I'm trying to use D3DXUVAtlasCreate to generate uv's for lightmaps, however I'm getting noticeable seams. I think this may be because the function uses the charts in the 1st texture coordinate set (for diffuse map texturing) and simply reorganises them into an atlas. I'm aware of the technique outlined on flipcode http://www.flipcode.com/cgi-bin/fcarticles.cgi?show=64423 but there doesn't appear to be enough information there for implementation, and I don't see how the technique could work if every triangle in the mesh has a seam. I also don't see the point in generating the uv's using world axis plane mapping if all the triangles will need to be reorganized into an atlas anyway. How are seamless implementations actually achieved in real applications?
Advertisement
The fact that you have the uvs are split into charts have nothing to do with discountinuities, the discountinuities are caused by how your lightmapper fills the gutter pixels.

You need to fill the gutter pixels with the right information for interpolation to work correctly, and you can do this by finding the closer point on the closes triangle and replicating that value, or actually finding the triangle that the pixel should correspond to on a different chart and replicating that value.

The technique on the link you sent is for calculating a basic UV map for lightmaps, DX's atlas stuff is way more advanced and will do the hard work for you.

If you go into more details about what you are doing then maybe you will get some more specific hints.
Ok that makes sense. I am filling in the gutter pixels, but I think part of the problem is that dx atlas doesn't 'snap' all the uv's to lie in between pixels, it just randomly positions them. The result is misalignment in charts. I can't see any dx options to snap the uv's, so I've manually done this.

I'm still not sure how the chart edges should be aligned however. Should the edges lie between two neighboring pixels in the atlas, or through the middle of a pixel?
UVAtlas does not randomly position the UVs, it uses an algorithm called Isocharts (SIGGRAPH 200X), in which it tries different combinations until it finds one that maximizes texture space utilization.

When you create your atlas the API takes a variable to control the distance between charts. Edges should go through the middle of the pixel, and note that the charts are not axis aligned, they have different shapes based on how they were broken up with regards to the max stretch allowed.

Are there any screenshots of diagrams of the artifacts you are seeing, maybe a code snippet? that should help finding out what is going wrong here.
Here's an example of a seam I'm getting due to sub-pixel misalignment of charts (the one in the lower right. The others are caused by not bluring over discountinuities correctly). I've turned filtering off so you can see what's happening:




Here's the code I'm using to create the atlas and obtain gutter data:



LPD3DXMESH meshOut = NULL;
LPD3DXBUFFER pFacePartitioning = NULL, pVertexRemapArray = NULL;
FLOAT resultStretch;
UINT numCharts;

// Generate the atlas...
hr = D3DXUVAtlasCreate(bmesh->dxMesh, 0, 0, width, height, gutter, 0,NULL,NULL,NULL,0,0,0,&meshOut,&pFacePartitioning,&pVertexRemapArray, &resultStretch,&numCharts);

//Re-align the uvs
for(int i=0; i<numVerts; i++)
{
//Align atlas UV's to middle of pixels
pVertex.texcoord0.x = (int(pVertex.texcoord0.x*width)+0.5f)/float(width);
pVertex.texcoord0.y = (int(pVertex.texcoord0.y*height)+0.5f)/float(height);
}

//get gutter data
LPD3DXTEXTUREGUTTERHELPER texGutter;
hr = D3DXCreateTextureGutterHelper(width, height, bmesh->dxMesh, gutter, &texGutter);




The code to realign the uv's is there to snap the uv's to pixel mid points. D3DXUVAtlasCreate doesn't appear to care about subpixel alignment. Unfortunatly the D3DXCreateTextureGutterHelper function generates an error when the uv's are centered directly in the middle of a pixel, probably because it can't tell whether it's a gutter or a triangle.

Snapping the uv's in between pixels seems to work and does fix the alignment issues. Is there any specific reason why having edges in the middle of pixels is better?

Another problem I'm having with DX atlas is that polys are getting placed on the very edges of the texure atlas which prevents the gutter from being filled for those edges, potentially leading to seams. I guess I can tell it to generate an atlas for an n^2-1 area and then just add edge pixels manually.

One final thing I've been wondering about is that since the API may change the shape of polys, can I still count on adjacent edges being of the same length and orientation in the atlas so that the gutter can be filled correctly?
I do not have much time today, but you should not need to snap the uvs in any situation, the worst I have seen done is clamp the uvs to make sure they are in 0..1 since UV atlas might end up giving you some values that are slightly out of range.

The +0.5f should be done on your lightmapper when sampling the pixels, but everything else should "just work"
I still don't see how that's possible. A fundamental requirement for texel continuation over a seam is to have the same sub pixel offset all the way along the edge (in both directions).

If you draw an axis aligned box with edge vertices 1 and 2 forming opposite corners, the boxes for matching edges must have the same width, height, u sub pixel offset and v sub pixel offset by definition.



[Edited by - foxbat on October 18, 2007 5:21:40 AM]
I see what you mean, for what I remember UVAtlas places the charts correctly, so you should not need to do the snapping, UVAtlas should place vertices on the center of the pixels.

On the diagram you sent you have no space for gutter pixels, so your interpolation will not work in the general case, you need to make sure that there are enough pixel distance between charts.

Other than that I would try to fill the gutter pixels manually, or will take a look at how your lightmapper is filling the pixels.

This topic is closed to new replies.

Advertisement