Pages

Showing posts with label technical. Show all posts
Showing posts with label technical. Show all posts

Deferred Texturing ?

  One method I tried, that didn't end up working very well, was deferred texturing for the terrain.

The terrain texture coordinates are based on its world coordinates and normal.  Using the GBuffer normal + depth buffer to reconstruct world position gave me what I needed.

 And while this worked and produced identical texture coordinates, the gradients were not always correct, resulting in some nasty looking aliasing anywhere that the depth buffer contained a large difference between adjacent pixels(because originally they were separate objects).

 My understanding is that the graphics card works on 2x2 pixels--

AB
CD

So the world coordinates are calculated in the four pixels, the difference between the adjacent pixels world coordinates is used as the derivative for MIP calculation.

But if pixel A was from a completely different mesh than pixel C, and 1000 meters closer to the camera, it ends up with really large derivatives and selects the lowest MIP--this is not what you want!

 So everything ends up with a blocky/pixelated outline that shimmers and looks just awful.

 If you passed down the derivative information perhaps you could work around it, but that is quite a large amount of extra data, and I didn't want to go down that route.

Components system + Flow Graph

 Like lots of other games, my game uses a component system.

This system is designed to allow for improved cache usage and easy parallelization.
It is loosely based on this article published by Insomniacs.

For cache friendly behavior all components of a given type live in contiguous memory, and are all updated together.

To specify attributes for components I have a Lua file,  which for each component type indicates, among other things, how they should update(parallel, serial), and which other component types they depend on.

 I use TBB Flow Graph to express dependencies, any component that has a dependency on another being updated prior to it, just lists that component as a dependency in the Lua file.


For instance this is the declaration of my Occlusion Rasterizer component in Lua.

reg("occlusion_rasterizer",    no_inteface,   TM.MULTI,  0.0,  3, {"commands"}) 

The parameters in order are:

name      - name in C++, this matches them up
interface - specifies which interface, if any, the component implements, if Occlusion Rasterizer had implemented an interface this would be the name of that component.  This allows for things like finding all components that implement a given interface.
parallel      - either SINGLE or MULTI, SINGLE means each component of this type is updated sequencially, MULTI means they are all updated in parallel
time delay - how long between updates to this type, so if you want a given type to only update  4 times per second make this value 0.25 etc
count      - how many components to reserve, this allocates a contiguous block of memory. It will grow as needed, but this allows for the equivalent of a vector.reserve()
dependencies - list of any components that must update prior to this component, TBB flow graph guarantees they will finish updating prior to this component updating. Occlusion Rasterizer depends on a command list being generated, so it lists "commands" as a dependency.

 Each component type derives from a base component type in C++, currently this adds 12 bytes of overhead to each instance in 32 bit builds, and 16 bytes in 64 bit builds.

The base component contains this:
vtable ptr -  4/8 bytes. Removing this is possible but makes the system somewhat clumsier to use.
chain index  - 4 bytes, which chain it is on, chains are a series of components
type            - 2 bytes, each component type has a unique ID
offset          - 2 bytes,  index into the pool containing components of its type


 I've been pretty happy with this system, my components are small self contained little objects,  they are cache friendly, and can be allocated and destroyed in large numbers. Adjusting dependencies as new types are added is also a very simple since no recompilation is needed, just a chance to a Lua script file.


 A major advantage of component systems, which I think does not get stated clearly enough, is how much glue code they save you from writing.  Having to create classical C++ game objects and populate them with appropriate member data, worry about all the fragile and arbitrary hierarchies, and then writing all the systems that control them is a huge amount of unnecessary code.

Occlusion Culling #1

(this is a very old post, I no longer use any of this)

 Recently I decided to try adding real occlusion system to my game.  There are a bunch of different ways to accomplish this, here are some common ones.

1) GPU occlusion queries
2) Software rendering for occlusion testing
3) Manual artist created portals and other similar systems(like Quake)

 #3 is a non-starter for me as I want a dynamic game world, and don't have artists to throw around.

 #1 I have tried before, but found that the inherit latency of CPU->GPU->CPU too large.  I tried cheating by issuing a query for each rendered object every frame, and simply not drawing in if it failed the query test from the previous frame, but this suffered from pop-in.

 #2 has become rather popular of late, and it is the method I decided to try this time.

 A software renderer could be implemented as either a rasterizer or a ray tracer, and since I already had support for ray casting into my scene, via Bullet,  I decided to try that first.

  I wrote a little program to generate depth map of the scene by casting rays through the physics system, it was trivial to parallelize it since each ray was independent of the others.

 Unfortunately performance was not good , as it turned out Bullet just wasn't fast enough to be ray casting 20,000+ rays each frame. I believe part of this is the fault of my levels which have far more objects than a typical game.



 So I went back on that idea and switched to rasterisation.  I stumbled across this post on devmaster by Nick, which was very helpful in getting a basic triangle rasterizer up and running.

 I am at the point now where I can rasterize the scene on the CPU and performance is overall much better than the previous ray tracing attempt.  I haven't even parrallelized or SSE'd it yet and it performs quite well(rendering ~50,000 triangles).


  For my terrain I am using convex hulls of each chunk, these typically use a small fraction of  the actual number of triangles that the rendered terrain contains. Unfortunately the generated hulls aren't exactly conservative(meaning they sometimes extend beyond the bounds of the source mesh), so I am certain I will see situations where the occlusion system says something is occluded when it really isn't...

 ...more on this later.