Skip to main content
GameDev.net gamedev.net
🔒 Locked

HL2 BSP Lightmap Coordinates

Started by puref0rlyfe Sep 8, 2010 at 5:27 AM 9 replies 7k views
Original Post
puref0rlyfe
puref0rlyfe
Hey guys,

I am having trouble calculating texture coordinates for lightmaps in Half Life 2 (Source) bsp files. So far what i have is

float lu =	TextureInfo[Faces[faceId].texinfo].lightVecsU.dotProduct(Vertexes[vertexIndice]) + TextureInfo[Faces[faceId].texinfo].lightOffsetU;				float lv =	TextureInfo[Faces[faceId].texinfo].lightVecsV.dotProduct(Vertexes[vertexIndice]) + TextureInfo[Faces[faceId].texinfo].lightOffsetV;lu /= (Faces[faceId].LightmapTextureSizeInLuxels[0]+1);lv /= (Faces[faceId].LightmapTextureSizeInLuxels[1]+1);


This manages to get the lightmaps to the correct scale as far as i can see but their offsets are wrong and they are in the wrong position. I have tried endless combinations of things and looked everywhere for the solution but the closest i could find was for quake 2 bsp lightmaps and that didn't work for these. Any help is appreciated. Thanks
puref0rlyfe
puref0rlyfe
The valve development wiki contains the structure for the texinfo lump as follows.

struct texinfo_t{	float	textureVecs[2][4];	// [s/t][xyz offset]	float	lightmapVecs[2][4];	// [s/t][xyz offset] - length is in units of texels/area	int	flags;			// miptex flags	overrides	int	texdata;		// Pointer to texture name, size, etc.}


When it states "length is in units of texels/area," what exactly is this implying?
ViLiO
ViLiO
My apologies if anything I am about to say is complete nonsense as it has been over 2 years since I last looked at my hl2 bsp source code :)

The only thing I can see that you have omitted, is not subtracting the LightmapTextureMinsInLuxels from the lu/lv before dividing by the corresponding LightmapTextureSizeInLuxels.

So I think your code should read...
float lu = TextureInfo[Faces[faceId].texinfo].lightVecsU.dotProduct(Vertexes[vertexIndice])    + TextureInfo[Faces[faceId].texinfo].lightOffsetU    - Faces[faceId].LightmapTextureMinsInLuxels[0];				float lv = TextureInfo[Faces[faceId].texinfo].lightVecsV.dotProduct(Vertexes[vertexIndice])    + TextureInfo[Faces[faceId].texinfo].lightOffsetV    - Faces[faceId].LightmapTextureMinsInLuxels[1];lu /= (Faces[faceId].LightmapTextureSizeInLuxels[0] + 1);lv /= (Faces[faceId].LightmapTextureSizeInLuxels[1] + 1);

Regards,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
puref0rlyfe
puref0rlyfe
Hey ViLiO, thanks for the reply.
Since i made my initial post i had done a lot of looking at various sets of coordinates generated by my code and figured out that i would need to subtract the mins which was correct, however the textures are still ever so slightly misaligned. I tried changing
lu /= (Faces[faceId].LightmapTextureSizeInLuxels[0]+1);lv /= (Faces[faceId].LightmapTextureSizeInLuxels[1]+1);

to simply
lu /= (Faces[faceId].LightmapTextureSizeInLuxels[0]);lv /= (Faces[faceId].LightmapTextureSizeInLuxels[1]);

however they are still just that bit off. It could be possible that i am reading in the lightmaps incorrectly or maybe the formula just needs one more thing in it somewhere like a floor or ceiling function at some point?

http://nackers.net/bad_lightmaps.JPG

Here is an example of the very slight misalignment of the textures.

Thanks for your help so far.
ViLiO
ViLiO
Assuming you are creating a texture for each individual lightmap, this looks like it could be solved by setting the AddressU and AddressV render states to Clamp (or CLAMP_TO_EDGE_EXT in OpenGL).

In my own hl2 bsp renderer I packed lightmaps into a fewer larger textures using a technique similar to http://www.blackpawn.com/texts/lightmaps/default.html and padded each lightmap with a 1 pixel border to avoid seams.

Regards,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
puref0rlyfe
puref0rlyfe
Ah, setting the texture wrapping to GL_CLAMP_TO_EDGE makes it better but there is still some tiny seams left.. and for some reason they are appearing mostly vertically. ie, all of the lightmaps fit fairly good horizontally, but they do not go correctly vertically, this is strange. Also that lightmap packing technique looks good, i'll have to give it a go. How would padding the lightmaps with a border reduce the seams as such?

http://nackers.net/bad_lightmaps2.JPG

thanks again.

[Edited by - puref0rlyfe on September 13, 2010 3:32:20 AM]
ViLiO
ViLiO
The reason for the padding was to stop the texels from neighbouring packed lightmaps bleeding into each other. To do this I add a border around each packed lightmap (so a 16x16 lightmap becomes 18x18 when packed) and the padding gets filled with the nearest texel on the source lightmap. The texture coords are then adjusted to only address the 16x16 area inside the packed lightmap.

There is quite an old article on flipcode that explains some of the reasons bleeding occurs http://www.flipcode.com/archives/Light_Mapping_Theory_and_Implementation.shtml

There are a few other ways you could solve your texture seams, padding with a 1 texel border is just the one I favour :)

All the best,
ViLiO
Richard 'ViLiO' Thomasv.net | Twitter | YouTube
puref0rlyfe
puref0rlyfe
Thanks! I'll give it a go and see how it turns out.
puref0rlyfe
puref0rlyfe
Hmm, after adding the border to the luxels and adjusting the coordinates it still seems to come out with the same problem.

//Calculate lightmap coordinates		float lu =	TextureInfo[Faces[faceId].texinfo].lightVecsU.dotProduct(Vertexes[vertexIndice])			+ TextureInfo[Faces[faceId].texinfo].lightOffsetU			- Faces[faceId].LightmapTextureMinsInLuxels[0]			+1;						float lv =	TextureInfo[Faces[faceId].texinfo].lightVecsV.dotProduct(Vertexes[vertexIndice])			+ TextureInfo[Faces[faceId].texinfo].lightOffsetV			- Faces[faceId].LightmapTextureMinsInLuxels[1]			+1;				lu /= (Faces[faceId].LightmapTextureSizeInLuxels[0]+2);		lv /= (Faces[faceId].LightmapTextureSizeInLuxels[1]+2);


My code now looks like this and the lightmaps are the same as before with a 1 pixel border around them resembling their closest pixel. The wrap mode is set to GL_CLAMP_TO_EDGE. Any ideas on what else i'm messing up?
ebray99
ebray99
If you're using OpenGL, try this:

		float lu =	TextureInfo[Faces[faceId].texinfo].lightVecsU.dotProduct(Vertexes[vertexIndice])			+ TextureInfo[Faces[faceId].texinfo].lightOffsetU			- Faces[faceId].LightmapTextureMinsInLuxels[0]			+ 1.5;						float lv =	TextureInfo[Faces[faceId].texinfo].lightVecsV.dotProduct(Vertexes[vertexIndice])			+ TextureInfo[Faces[faceId].texinfo].lightOffsetV			- Faces[faceId].LightmapTextureMinsInLuxels[1]			+ 1.5;


If you're not using OpenGL, then I'm afraid I can't be much of a help. The reason I suggest this is due to a subtle difference in the way OpenGL addresses textures. It treats the coordinate (0.5 / width) as the center of the first texel. Direct3D uses (0.0 / width) as the center of the first texel.

Kevin B
puref0rlyfe
puref0rlyfe
Hi, thanks for the reply,

i have tried adding 0.5 to the luxel coordinates before but it didn't make any difference, i have tried it again and it still just has some tiny seams.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.