Let There Be Lightmaps

Published July 30, 2007
Advertisement
Quote:Original post by Ravuya
Eventually I gave up on my mod (double shotguns).
Heh, you might like the Killer Quake Pack. [grin]

I've added some primitive parsing and have now loaded the string table, instructions, functions and definitions from progs.dat but can't do a lot with them until I work out what the instructions are. Quake offers some predefined functions as well (quite a lot of them) so that'll require quite a lot of porting.

Quote:Original post by Evil Steve
I seem to recall that the original Quake used "Truebright" colours (Which were either the first or last 16 colours in the palette), and these colours weren't affected by lighting. How the rendering was done, I've no idea.
I haven't looked at the data structures so could be making this up entirely: Quake does lighting using a colour map (a 2D structure with colour on one axis and brightness on the other). I'm assuming, therefore, that for the fullbright colours they map to the same colour for all brightnesses, rather than fade to black.

How could you simulate that? I guess that the quickest and dirtiest method would be to load each texture twice, once with the standard palette and once with the palette adjusted for the darkest brightness and use that as a luma texture. I believe Scet did some interesting and clever things with pixel shaders for DOOM, but that would end up playing merry Hell with 24-bit truecolour external textures.

Quote:I might make a Quake clone as my next random side project / engine code test actually. I like doing cool low level stuff like this.
Aye, it's fun. [smile]


I think I've cracked those blasted lightmaps.



The lightmaps are small greyscale textures applied to faces to provide high-quality lighting effects with a very small performance overhead. Most of the visible faces have a lightmap.

They are stored in the BSP file. Extracting them has been a little awkward, not helped by a very stupid mistake I made.

Each face has a pointer to its lightmap. To get a meaningful texture out of the BSP we also need to know its width and height, which are based on the bounds of the face's vertices.

However, a lightmap is a 2D texture, and a face occupies three dimensional space. We need to scrap an axis!

Each face is associated with a plane. Each plane has a value which indicates which axis it closest lies orthogonal to. I could use this property to pick the component to discard!

This didn't work too well. Most of the textures were scrambled, and most of them were the same width. This should have rung warning bells, but I ignored this and moved on to other things. The problem was that each face (made up of edges) specifies which of the level's global list of edges comes first, and how many edges it uses (edges are stored consecutively).

// My code looked a bit like this:for (int i = 0; i < Face.EdgeCount; ++i) {    Edge = level.Edges;    //}// It should have looked like this:for (int i = 0; i < Face.EdgeCount; ++i) {    Edge = level.Edges;<br>    <span class="cpp-comment">//</span><br>}<br></pre></div><!–ENDSCRIPT–><br><br>With that all in position, sane lightmap textures appear as if by magic!<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.27.01.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.27.01.jpg" border="2" width="408" height="318" /></a></center><br>The textures aren't really orientated very well. Some are mirrored, some are rotated - and the textures of some are still clearly the wrong width and height. This 3D-to-2D conversion isn't working very well.<br><br>Each face references some texture information, including two vectors denoting the horizontal and vertical axes for aligning the texture. This information can surely also be used to align the lightmaps correctly (where <tt>2D.X = Vector2.Dot(3D, Horizontal)</tt>, <tt>2D.Y = Vector2.Dot(3D, Vertical)</tt>)?<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.27.02.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.27.02.jpg" border="2" width="408" height="318" /></a></center><br>I now draw these textures after the main textures and before the luma textures.<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.27.04.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.27.04.jpg" border="2" width="408" height="318" /></a></center><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.27.05.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.27.05.jpg" border="2" width="408" height="318" /></a></center><br>Problem: There are typically > 4000 lightmap textures. Rendering all of the lightmaps drops the > 200FPS framerate down to about 35FPS. This isn't great!<br><br>Coupling this problem with the other problem that drawing non-world BSP objects (such as ammo crates) isn't very practical at the moment gives me a good excuse to write a new renderer.<br><br>Quake uses a BSP tree to speed up rendering. Each leaf has a compressed visibility list attached to it, indicating which other leaves are visible from that one. Each leaf also contains information about which faces are inside it, and so by working out which leaf the camera is in you can easily get a list of which faces are available.<br><br><!–STARTSCRIPT–><!–source lang="c#"–><div class="source"><pre><span class="cpp-comment">/// <summary>Gets the leaf that contains a particular position.</summary></span><br><span class="cpp-comment">/// <param name="position">The position to find a leaf for.</param></span><br><span class="cpp-comment">/// <returns>The containing leaf.</returns></span><br><span class="cpp-keyword">public</span> Node.Leaf GetLeafFromPosition(Vector<span class="cpp-literal"><span class="cpp-number">3</span></span> position) {<br>	<span class="cpp-comment">// Start from the model's root node:</span><br>	Node SearchCamera = <span class="cpp-keyword">this</span>.RootNode;<br>	<span class="cpp-keyword">for</span> (; ; ) {<br>		<span class="cpp-comment">// Are we in front of or behind the partition plane?</span><br>		<span class="cpp-keyword">if</span> (Vector<span class="cpp-literal"><span class="cpp-number">3</span>.D</span>ot(SearchCamera.Partition.Normal, position) > SearchCamera.Partition.D) {<br>			<span class="cpp-comment">// We're in front of the partition plane.</span><br>			<span class="cpp-keyword">if</span> (SearchCamera.FrontLeaf != <span class="cpp-literal">null</span>) {<br>				<span class="cpp-keyword">return</span> SearchCamera.FrontLeaf;<br>			} <span class="cpp-keyword">else</span> {<br>				SearchCamera = SearchCamera.FrontNode;<br>			}<br>		} <span class="cpp-keyword">else</span> {<br>			<span class="cpp-comment">// We're behind the partition plane.</span><br>			<span class="cpp-keyword">if</span> (SearchCamera.BackLeaf != <span class="cpp-literal">null</span>) {<br>				<span class="cpp-keyword">return</span> SearchCamera.BackLeaf;<br>			} <span class="cpp-keyword">else</span> {<br>				SearchCamera = SearchCamera.BackNode;<br>			}<br>		}<br>	}<br>}<br></pre></div><!–ENDSCRIPT–><br><br>The following three screenshots show a wireframe view of going around a sharp corner using the visibility list information from the level's BSP file.<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.29.04.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.04.jpg" border="2" width="244" height="190" /></a>   <a href="http://benryves.com/bin/blueprints/3d/2007.07.29.05.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.05.jpg" border="2" width="244" height="190" /></a>   <a href="http://benryves.com/bin/blueprints/3d/2007.07.29.06.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.06.jpg" border="2" width="244" height="190" /></a></center><br><br>Another fix in the new renderer is the correction of faces that don't have a lightmap texture. Some faces - such as those which are completely dark, or the faces used for the sky texture - don't have such information, and are currently rendered at full brightness.<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.29.07.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.07.jpg" border="2" width="244" height="190" /></a>     <a href="http://benryves.com/bin/blueprints/3d/2007.07.29.08.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.08.jpg" border="2" width="244" height="190" /></a><small><br>Before and after the fix</small></center><br><br>If the renderer encounters a lightmap-less face, it enables lighting, sets the ambient light to the face's brightness level, draws the face, then disables lighting again. As you can see from the screenshots this looks a lot better. [smile]<br><br>The new renderer not only renders the levels using the BSP tree - it also breaks them down into individual models. A level file contains multiple models. The first model is the main level architecture. Other models form parts of the level that can be moved.<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.29.09.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.09.jpg" border="2" width="244" height="190" /></a>   <a href="http://benryves.com/bin/blueprints/3d/2007.07.29.10.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.10.jpg" border="2" width="244" height="190" /></a>   <a href="http://benryves.com/bin/blueprints/3d/2007.07.29.11.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.11.jpg" border="2" width="244" height="190" /></a><small><br>Models 0, 1 and 2 of <i>The Slipgate Complex</i></small></center><br><br>Having multiple BSP renderer objects means that I can now render the ammo boxes and health packs.<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.29.12.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.12.jpg" border="2" width="408" height="318" /></a><small><br><tt>maps/b_bh25.bsp</tt></small></center><br><br>I'm not sure what advantage there is to using BSP models instead of Alias models for these items.<br><br><center><a href="http://benryves.com/bin/blueprints/3d/2007.07.29.13.png"><img src="http://benryves.com/bin/blueprints/3d/2007.07.29.13.jpg" border="2" width="408" height="318" /></a><small><br><i>Place of Two Deaths</i> has a <i>Place of Two Medikits</i></small></center><div>


</div>
0 likes 3 comments

Comments

Evil Steve
Quote:Original post by benryves
I'm not sure what advantage there is to using BSP models instead of Alias models for these items.
I was wondering that myself when I was doing Quake modding. BSP models are only used for cuboid models (Correct me if I'm wrong), so it may have been more effient to render them as BSP models using the old software renderer Quake uses. Just my guess anyway.
July 30, 2007 07:29 AM
benryves
Quote:Original post by Evil Steve
BSP models are only used for cuboid models (Correct me if I'm wrong), so it may have been more effient to render them as BSP models using the old software renderer Quake uses. Just my guess anyway.
The BSP models used are health packs, ammo crates and the exploding barrels - so yes, all cuboid.

My guess would be that Quake uses affine texture mapping for Alias models and almost perspective-correct mapping for BSP models, and that the textures on these large, flat surfaces of the cuboids would visibly swim had they been Alias models. Quake 2 used affine texture mapping on its medikits, which means that if you crouch on top of them with full health they look rather ugly.
July 30, 2007 08:08 AM
Scet
Looks nice, I could never figure out Quakes lightmaps. I got the Quake 3s lightmaps to work, but I'd rather play Quake then Quake 3(seriously Q3 sucked).

Quote:
I believe Scet did some interesting and clever things with pixel shaders for DOOM, but that would end up playing merry Hell with 24-bit truecolour external textures.


It was meant to make it look like the Doom software renderer but with Direct3D. Plus I could use L8A8 textures which prevented it from eating up my RAM. All you'd have to do is switch the shader technique when using 24-bit textures, although you'd have to implement your own fading system since the colour maps are just palettes and you lose palette support.

July 30, 2007 05:18 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement