August 29, 2009
I’m pretty close to releasing Demo 2, I’ve implemented the last features – now it’s just a matter of fixing a few bugs. This post has a movie showing various features at the end.
Properly spawning and walking NPCs
I’ve had exterior NPCs in before but they didn’t move or spawn properly – sometimes they’d come in at invalid spots. I decided to try raycasting to determine if a spot was valid but there were multiple problems with that. There would be a lot of raycasts and collision checks every frame as NPCs were added, removed and move. In addition, the raycasts would determine a spawn to be valid but it really isn’t, it’d be in a bad area or too close to a building. To fix that would require multiple raycasts to cover an area or other more costly solution. Instead, I gave up on the raycast / collision idea and picked a simpler solution. When a block is loaded, each vertex on its ground plane (16×16) is considered a valid spawn point. Then right after load (this is done only once) every building is checked – any spawn points inside it’s bounding box is considered invalid. Each row of 16 points is stored in a bitfield – so there is an array of 16 of these bitfields, one per row. So now a grid is generated around the player, where each vertex on the grid is a valid spawn point or not. When spawning a new NPC, it randomly picks a valid spawn point that is outside the field of view and within a certain range of the player. The beautiful thing about this system is that the NPCs use the same grid for movement. The NPC randomly picks a destination valid grid point from the 8 vertex region around its current point and that is used as a target point for the NPC to move towards. Once it reaches the new grid point it then selects another one and moves towards that. Full movement without any collision detection – except for guards when they are chasing the player, which act like enemies (these will not be in the demo). Finally when an NPC is outside a certain range and not in the player’s field of view, it is recycled – it respawns at a closer valid point and changes NPC skin.
Here you can see some screenshots of the NPC grid, green points are valid spawn points, whereas red points are outside of range or invalid.
I implemented the first pass of the climbing ability, although it’s a little fickle still. Anyway when the player collides with the world, if the “final” slide plane (i.e. the plane of the collision polygon(s) relative to the player velocity) causes the player to stop moving on the first collision iteration is purely vertical (i.e. the “up” component of the normal is 0.0) then the player can potentially climb that surface. Once the game decides that the player can climb, decided based on skill eventually – there is no skill check yet, then gravity is disabled and the player moves upward when pushing into the wall. As soon as the player stops moving forward or moves past the vertical surface, climbing mode ends and regular gravity is activated. It still needs some work but you’ll see climbing in action in the movie.
The fog color now matches the sky color, as you’ll see in the movie. This is done by rendering the sky background into a relatively low resolution texture. The vertex shader projects the object’s vertex position and generates texture coordinates into that texture. The color from that position is then used as the fog color, so objects will appear to “fade into the sky” no matter where they are.
There have been other miscellaneous tasks completed and issues fixed, but these are the major items.
In the movie below, the player starts in a small town roughly South of Daggerfall. The player runs through the woods and you’ll notice that the walls of Daggerfall (and a few tall houses) are visible the whole time even though it takes about a minute and a half to run there. Various interiors are shown as well as NPCs walking around. You’ll also notice the smooth sky transitions as the time of day changes. There are some bugs and I accidently bring up the inventory in part of the movie, but it’s coming along.
High Resolution Movie
August 17, 2009
Lire ce message en français
Przeczytaj tę wiadomość po polsku
Work on the demo continues. This post does not have any new screenshots but there is a movie. You can click on the high resolution link below the movie to download a higher resolution version. Much of the work was in optimizations, music and sound – hard to show screenshots of that stuff.
Music & Sound
Midi music and sound effects have been implemented, though some of the midi loops a little roughly, which will be fixed later. Note that at night you can hear the crickets (though it’s harder to hear in the video then while playing the game for some reason), the cries for vengeance as well as the appropriate night time music. It also switches music tracks based on the interior type as well, you’ll see this when the player goes inside a tavern in the movie. In the next post I’ll put a movie showing more of the wilderness (during the day) and more building interiors.
Mesh & Flat Rendering
(Much of this has been discussed on the forums already) Everything is rendered using a deferred “render queue” system, basically each mesh material or flat is submitted as a “entry” and then all the entries are rendered for a given frame. There are multiple lists: opaque materials with base lighting (character light, directional light outside, fog), opaque materials + points light passes (2 lights per pass right now) and translucent/transparent materials (flats). [Note: only those materials that are not culled get submitted. There is a hierarchical culling system not mentioned here as well as other systems such as contribution culling]. I will probably add the z-prepass and light stenciling soon, these are pretty easy with this system.
I’ve added sorting to this as well. So opaque materials are now sorted by shader (right now each list only uses 1 shader), then by texture, vertex buffer then index buffer. This reduces the state switching as much as possible.
Transparent materials are now sorted based on distance to the camera plane, which means that they are composited in the correct order – so no more weird edges around sprites (unless they are built into the texture itself). The only exception to this, is emissive flats such as streetlights. There is still an error, due to the way the emissive setting is handled, that causes dark edges around the flat. This will be fixed.
I also fixed various other issues as well, such as regenerating plant distributions more often than necessary.
There are still some improvements to be had here, but with the sorting it all looks right at least.
In the video below, you can see me walking around Daggerfall city at night. You’ll notice the sound effects, music, sky transition from day to night, bloom, interiors with lighting and interior NPCs. Note that there are some errors that need to be fixed:
* Dark edges around emissive flats (discussed above).
* Fringing around the edges of the screen from the bloom.
* Flickering/strobing of the bloom effect, this will be fixed before the demo.
August 6, 2009
This time around the interiors were almost completed. Now NPCs show up where they’re supposed to, you can even click on some of them – although right now you can loot them like dead bodies – except with no loot. Obviously they’ll talk eventually, though not in the next demo. Next up the interior textures are now corrected for region like the exteriors. The taverns, mage’s guild, temples, etc. look more fitting for the Daggerfall region now. The doors that connect the exterior and interior are fully functional, before they only worked if you were on the ground level. Now you can go through upper level doors, climb the spiral staircase and get on the wall and so on. And finally the interiors use the proper dungeon like lighting (no more directional lighting) and the lights work correctly now.
Exterior NPCs are now showing up in cities, although the work is still preliminary. The outdoor lighting intensity also changes with the time of day, so the lighting matches the sky better. The sky now smoothly fades between images, so you won’t see a pop when it changes. This cross fade happens over about 5 seconds, so the gradients actually change very smoothly. I also implemented an optional sky filter that smooths out the sky gradients and dithering but preserves the edges – the sky looks smooth but not blurry. This is done on load, if the option is enabled, so there is no additional runtime cost or memory consumption – so there’s no reason not to use it unless you don’t like the effect. The luminance range is computed for each image and used to automatically adjust the filter parameters to preserve edges and provide just enough smoothing regardless of how bright or dark the image is.
Windows now work correctly. No additional memory or textures is used and the palette information is lost once the textures are uploaded to the GPU, so it took a little work to get the proper color to change without any filtering artifacts and only changing the correct color and nothing else. The way the renderer works is that alpha controls opacity and emissiveness. However with outdoor textures, not including flats which have a different shader, no pixels need to be emissive except for the windows at night. So what I did is leave the color alone (a middle-dark gray) and set the alpha to fully emissive. Then in the exterior shader (for geometry) I blend in the proper window color over an alpha range that is otherwise unused, which gives a smooth bilinear look even though its blending in a different color. I also blend between different colors for the window based on time of day (represented as a single float in the shader), as well as different final emissive values. This way windows are full bright at night but are properly shaded during the day.
This leads to the last feature I want to talk about, an optional feature: bloom. Basically only those pixels that are marked as fullbright (windows when they’re fullbright at night, light source flats) glow and only if the intensity of the color is greater than a threshold – that way fire on top of a torch will glow but not the wood. The geometry is rendered only once, the intensity value is written into a second render target as the scene is being rendered. You can see the bloom in the screenshots below, they are the last set.
Interior NPCs, proper region texturing and proper interior lighting:
August 3, 2009
The next thing I implemented was proper time of day support. The city lights turn on and off based on the time and the lighting/fog get much darker at night. This leads to the next visual feature: skies! During the day, Daggerfall uses 2 textures for the sky – an East and West image, which form a sort of cylinder around the player. For a given region there are 32 different sets sky images, ranging from dusk to noon which are then played backwards from noon to evening – but with the east and west textures swapped in order to have the sun travel the whole arc through the sky. As you look up, DaggerXL limits how far up it scrolls the sky so that you can’t see past the top (which wasn’t a problem in Daggerfall since you couldn’t look up as far). No such limits are used when looking down since the bottom color is stretched as far as it needs to be. Night skies are simpler, there is only one texture that is tiled to form the “cylinder.” [Note: it's not really mapped to a cylinder because that would imply perspective distortion when looking up or down but its an easy way to visualize the effect]. I also, finally, adjust the exterior building textures based on region so all the buildings should now look correct from the outside.
In addition, if a building has an interior you can click on the door and enter. Interiors show up correctly, except for modifying texture indices based on region in some buildings, as do all the decorations and flats. The only things missing are doors (the internal doors that rotate, the doors leading outside are there) and NPCs. Those things are next on my list. Anyway you can also leave and go back outside too, of course. When you go inside, the exterior is turned off and only the proper interior (and it’s flats) is rendered. Conversely the interiors are not rendered when outside.
Sky screenshots at different times of day:
Screenshots of various interiors: