Game Development Community

Custom light maps for DTS files

by Adrian W · 11/22/2008 (3:45 pm) · 14 comments

As this is my first post I should first say Hello and a big thankyou to everyone for all the really useful info and resources that people have taken the time to post on this site.

And so, on to the nitty gritty. I've been creating my first DTS files for TGEA and it seems that since DTS files only have one UV channel, its difficult to create a custom lightmap or AO map for a model unless the light map and diffuse textures share the same UVs. This isn't a problem if the diffuse texture is one big baked skin, but if you're creating a building model for example and you have several tileable diffuse textures and one single baked AO map, then its a problem (or so it seems to me, I'm still a newbie and I may have missed a trick or two here so please let me know if I have).

Anyway, my way of getting around this was to write a "DTS merger", the idea being that in your modelling package of choice you UV map your geometry with your diffuse textures and export as DTS. Then bake an AO map (or whatever kind of lightmap you want), which creates a completeley different set of UVs, and export to a second DTS. Then you run both DTS files through the DTS merger which creates a new file with two UV channels (which I call an ATS file) and shade it with a custom shader.

Here are some screenshots, note that I turned off the default directional gouraud shading to make the lightmaps more obvious.

First DTS file with diffuse textures, tiled textures for the stone, windows, thatch roof etc:

www.futurenation.net/glbase/images/house1.jpg
Second DTS file with baked AO map, one single skin:

www.futurenation.net/glbase/images/house2.jpg
And finally the merged "ATS" file:

www.futurenation.net/glbase/images/house3.jpg
OK the effect in the example is subtle but looks better I think than the standard directional shading applied to DTS files by default. And since the lightmap is pre-baked it can be editted and tweaked to include as much or as little shading as you want and could also be coloured rather than just monochrome.

As well as generating the ATS file, the merger also creates a script for the custom materials, heres a code snippet (the numbering comes from the material indexes in the original DTS files) :

new CustomMaterial( house_mat_7_0 )
{
   texture[0] = "txt_thatchroof09";
   texture[1] = "buildingLightingMap";
   texture[2] = "$fog";
   translucent = true;
   BlendOp = LerpAlpha;
   shader     = AtsShape;
   version    = 2.0;
};
new CustomMaterial( house_mat_8_0 )
{
   texture[0] = "txt_stoneslab04b";
   texture[1] = "buildingLightingMap";
   texture[2] = "$fog";
   shader     = AtsShape;
   version    = 2.0;
};

addMaterialMapping( "house_mat_7_0" , "material: house_mat_7_0" );
addMaterialMapping( "house_mat_8_0" , "material: house_mat_8_0" );

Thanks for reading my first post!

#1
11/22/2008 (3:59 pm)
Nice...thanks for sharing.
#2
11/22/2008 (4:12 pm)
Very nice! interesting approach to solving the problem. And you are correct about the single vs double UV sets. It's one trade off or the other.
#3
11/22/2008 (4:23 pm)
Very nice indeed!

Only thing is the most common format for buildings and larger structures is dif...
#4
11/22/2008 (6:07 pm)
Only thing is the most common format for buildings and larger structures is dif...

Absolutely, and learning constructor is definitely on my list of things to do, but I'm a programmer trying to learn some art pipeline skills and once I had the idea I couldn't resist coding it and trying it :-)

Anyway my eventual aim is to build up a village something like Lakeside County in Guild Wars. The only way to find out is to try working in both DTS and DIF formats and see which works best.
#5
11/22/2008 (6:35 pm)
interesting.
i wonder if it would it be possible to create a new set of textures which are the normal material texture + the lightmaps. seems like it wouldn't be that tough, but your overall texture size could grow because you'd have to scale up the LM textures i think.
#6
11/22/2008 (6:39 pm)
Adrian, I immediately though of outside of Ashford Abbey in Lakeside County when I saw that building, I think the bricks sticking out and the style of the steps sold that the most. It looks good.

And Peter, though DIF is better for larger structures, a lot of people have been starting to favor dts (especially with polysoup) for smaller structures, or just ones you can't enter (such as the way these buildings were used.) And the ability to use AO has been thrown around a bit (though with the new SSAO pack most people were pleased.)

Any chance this'll go out as a resource? :D
#7
11/22/2008 (7:40 pm)
It should be released as a resource, there are a few things I need to do first:

- Getting the mission editor to recognise my files, at the moment I open up the mission file and change the .dts's to .ats's in notepad!

- Test with different models exported from different modelling packages

Orion:

Shouldn't be too difficult. I think you could use normal maps with either set of UVs, and code the shader accordingly.
#8
11/22/2008 (11:21 pm)
Great simple logic there Adrian, nice work. Out of curiousity it appears as though you are using a custom shader to do all this. Are you able to post this custom shader here or as a resource?
#9
11/23/2008 (10:04 am)
The shader is pretty simple because the bulk of the work is already done by the DTS merger. To make the shader I just made a copy of shaderP000 and tweaked it:

struct ConnectData
{
   float4 shading         : COLOR;
   float2 texCoord        : TEXCOORD0;
   float2 lmCoord         : TEXCOORD1;
   float2 fogCoord        : TEXCOORD2;
};


struct Fragout
{
   float4 col : COLOR0;
};


Fragout main( ConnectData IN,
              uniform float4    ambient         : register(C3),
              uniform sampler2D diffuseMap      : register(S0),
              uniform sampler2D lightMap        : register(S1),
              uniform float     visibility      : register(C6),
              uniform sampler2D fogMap          : register(S2)
)
{
   Fragout OUT;

   // Uncomment this if you want directional & lightmap shading
   //OUT.col = float4( IN.shading.rgb + ambient.rgb, 1 );
   //OUT.col *= tex2D(diffuseMap, IN.texCoord) * tex2D(lightMap, IN.lmCoord);

   // Uncomment this if you just want lightmap shading
   OUT.col = tex2D(diffuseMap, IN.texCoord) * tex2D(lightMap, IN.lmCoord);

   OUT.col.a *= visibility;

   float4 fogColor = tex2D(fogMap, IN.fogCoord);
   OUT.col.rgb = lerp(OUT.col.rgb, fogColor.rgb, fogColor.a);

   return OUT;
}


To get the second set of UVs into TEXCOORD1:

in the definition of TSMesh (my extra code is in the #ifdef)

ToolVector<Point2F> tverts;
#ifdef ADE_LMVERTS
   ToolVector<Point2F> lmverts;     // light map verts
#endif


and in TSMesh::createVBIB()

texcoord = tverts[i];
      vert->texCoord = texcoord;
#ifdef ADE_LMVERTS
      if (lmverts.size() > 0)
         texcoord = lmverts[i];
#endif
      vert->texCoord2 = texcoord;         // need to write this or write will be slower

When you load a DTS file TSMesh::lmverts is left empty and the above code does exactly the same as in unmodified TGEA. But when you load an ATS file the second UV channel is loaded into TSMesh::lmverts by my ATS file loader and the above bit of code copies it into the vertex buffer for the shader to use.

Hope this explains it a bit better.

Thanks for the positive feedback everyone, in the next couple of weeks I'll try to get a web page set up with something to download and try out.
#10
11/23/2008 (11:08 am)
@Adrian W
-Good luck on learning Constructor, a bit of advice is: start small, and keep your head cool (I'm almost biting my keyboard at times) otherwise keep up this good work:-)

@ Morrock
I guess everyone (unable to code it) is waiting for someone like Adrian W here to code a better alternative to the current DIF situation. I'm not at all happy about DIF's -there are simply too many export errors and too many workarounds you need to know. (but maybe some new editors are lurking in the near future)
DTS is more stable, and polysoup sounds very promising, but in the end it's determined by the effect on the system running the game ;-)
#11
11/23/2008 (11:25 pm)
Hey Adrian!

This is really great. have you looked at Ryan Mounts AO resource?

im not a coder but thought maybe you might find his work interesting in combination with your own!
#12
11/25/2008 (9:56 am)
Nice going Adrian!
Been longing for a 2nd UV-set for ages. But I am no coder...wish I was. :-(

Just so I got this right - these merged DTS - your new ATS - is a just a 'regular' DTS, now containing 2 UV-sets?
#13
11/25/2008 (7:34 pm)
Hi Surge,

I've seen some screenshots of stuff done with that I think and it looks very cool.

Tobias,

Not quite, for starters my ATS files are text files, which is probably a bit inefficient but makes life a lot easier during development because when something needs debugging I can open up the file and look at the data. Also dumping the data out as text made it a lot easier to understand how DTS files work. I can switch back to a binary format later.

All the meshes are stored as indexed tristrips. I only support standard meshes (TSMesh), not skin meshes so you can't use this on Kork. But all the other features like detail levels, sequence animations (translation, rotation, scale animations, not DSQ's), Col-n collision hulls, work as in a normal DTS file. Polysoup should work OK but haven't tested it yet. Currently I'm working on supporting IFL materials.

Polysoup is definitely something I need to understand better. I read about it on TDN and it sounded like it always throws all rendering meshes at the collision system. Sometimes I think you want polysoup collision, but maybe do not need the full complexity of your rendering meshes, so this is something I want to look into.
#14
11/25/2008 (7:54 pm)
@Adrian:
This is pretty neat, and something that's really been lacking especially since polysoup came along.

Have you considered the idea of using standard dts files that also contain specially named meshes (prefixed or suffixed with "_LM" or something similar) for the lightmap UVs?

I played around with the idea of doing this without source code changes by duplicating my meshes, re-texturing/unwrapping and baking lightmaps to the copied meshes, then setting the lightmap material to "subtractive" translucent blending. The main problem that I ran into was the inability to control the rendering order of the meshes in TGEA (couldn't get the "lightmap" version of the meshes to always render on top) due to the render batching system. That, and subtractive translucent materials are broken in stock TGEA.