 Rant and depth-of-field |
Posted - 8/28/2007 4:05:21 PM | Rant
Time for a small rant. On various topics. I'll keep it short to not bore people to death. Some things are somewhat irritating:
1) People who want to test the ICP, have a crash, and post or send me e-mails / PMs saying "it does not work, can you help ?". No, I cannot help. At least, not if you don't explain what the problem is. What are your system specs ? Do you have the latest drivers ? Did you use the search function to see if your problem has been answered ? What happens exactly, can you login, is it crashing, is it freezing, or what ? Sorry, I don't have telepathy skills, I cannot read your mind. The point is: if you're going to ask for help, be precise! I don't have time to waste to extract the useful information for you point by point.
2) People who don't read the dev journals. Seriously, I'm sometimes spending an hour or two writing those journals. Nothing is irritating me more than people who criticize something when that thing was described and explained in the journal a few posts up. Things such as "omg vertex popping".. "omg it all looks the same, boring texture" when I explicitely said that geo-morphing isn't implemented yet, and that the terrain uses only big tiled textures.. wow.
I certainly have no problems with people commenting and criticizing the features that are shown in the video, but please, don't criticize or comment on things that are not done yet.
And please.. read the dev journal before flooding the thread with tons of questions.
By the way, this section is dedicated to SinKing from moddb.com who said the motion blur didn't look good and was unrealistic, thinking he was looking at depth-of-field. Hi :)
Depth-of-field
To be clear, motion blur is the act of bluring pixels in the direction of the motion. Play a DVD, put it on pause, and look at the image of your TV ( especially when the camera or something is fast moving ). That is motion blur.
Depth-of-field is another kind of blur, but this time based on a focal distance. It's the effect you see in movies when the focus is on an object in the middle of the scene: what is close to the camera is blurred, and what is far too.
Keep in mind that I'm exagerating the effects a bit, mostly to debug.
My implementation of depth-of-field is based on a pretty standard technique: the scene is rendered to a texture ( like many effects ); the scene is also rendered to a depth buffer. In a post-processing pass, those two textures are read back: the depth is sampled, compared with the focal plane distance, and the further the pixel is from this plane, the more blurry the scene pixel becomes.
The quality of the blur isn't very good ( by my standards ), as it does not use a separable gaussian yet. It's your basic blur taking N samples in a circular kernel around the center pixel, and averaged together. The size of the kernel is depending on the absolute distance to the focal plane ( and some magic formulas to "feel" good ).
One important thing is also missing: the focal plane distance is currently a constant, that I can change with 2 keys; in the future, I will have to cast some rays in the scene to determine the focus area near the center of the camera. Nothing too advanced technically, I'm not worried.
Pictures







| |
| Saturday, August 25, 2007 |
 Motion blur and physics video |
Posted - 8/25/2007 5:25:30 PM | Short update tonight. I've created a new video showing off the ball physics and collisions, the planetary terrain ( and please.. I've repeated it many times, but since many people have already commented on it, again, it's using one big tiling texture and it has some vertex popping ), and finally the motion blur ( more visible if you pause the video at a moment the camera is moving quickly ).
You can get the video here:
Physics and motion blur ( Divx 5, 22 MB )
And here are two pictures of motion blur in the asteroid field:


| |
 Planetary engine, Part VIII and Motion blur |
Posted - 8/24/2007 5:14:36 AM | Performance optimizations
I spent some time to add some classes to the code to handle multi-threading tasks. This allows to scale performance-hungry code to any number of cores / cpus. Of course, this optimization can only apply to code that is easily parallelizable, for example heavy processing on sequential or independant data.
One area that benefits a lot from multi-threading is the terrain patch generation. A terrain patch is made of NxN vertices, with N = 2^i + 1 ( i is an integer ). The default is 33x33 vertices.
When the quadtree gets subdivided ( you zoom on the terrain ), 4 child terrain patches are created: that's a total of 33x33x4 vertices ( 4356 ) to generate. Each vertex requires various processing, listed here by decreasing order of complexity.
- generating the height value by evaluating many procedural noise functions ( by far the slowest ).
- generating two displacement values for the cliff/overhangs effect
- generating a normal at this vertex.
- generating the vertex attributes such as position, tangent space and texture coordinates.
The first two tasks are the important ones ( as far as performance goes ). The height generation requires, for each vertex, to evaluate 3 or 4 procedural functions ( typically, ridged fbm, a few fractals, terrace effect, maths operations ). Because you need enough details when you descend at ground level, I'm forced to use a high amount of octaves in those procedurals ( the main one, the ridged fbm, is 16 octaves ). Counting the total, I'm probably calling the 3D perlin noise basis 30-40 times per vertex, and that's still excluding all the intermediary maths operations which add some serious overhead.
The displacement for cliffs/overhangs require evaluating two fractals that are 7-8 octaves each, so it's also pretty performance-hungry.
The net result is that on complex planets, when you are moving around and a node gets subdivided in its 4 children, you see a small slowdown. It's very short ( like 20 milliseconds ), but long enough to make the camera motion feel unsmooth. This problem cannot be fixed due to the nature of procedurals ( else I'd go back to diamond-square and have boring planets but okay performance ) but it can be lessened with various tricks, and one of them is this multi-threading.
I have a quad-core Q6600 at home, it's good to know that it'll eventually be used in something :)
Another idea to improve performance is to write SSE-optimized noise generation code, but it's a pretty low-level optimization, so I'd rather do that as a "last resort" solution.
About procedural details
The good thing with using procedural generation is that you are more future-proof than other engines/games.
What I mean is this: just by changing a detail level in the config dialogs, you will be able to increase the quality and details to extreme levels. No computer that exists today has enough memory, or video cards and cpus good enough to make it run on the highest detail levels, simply because there's no hard limit to how far those details can go.
Case in point: at the moment the terrain patches are 33x33 vertices; that's the default for medium to high-end gaming computers, for example AMD FX/Intel Core2Duos on a NV7800, NV8800 or ATIX1800.
If your computer is good enough, you can try to increase the details by 4: terrain patches of 65x65. I tried on my Quad-core machine ( Q6600 with a 8800 GTX ), and as expected it slowed down quite a lot, but it was still real-time ( 40-50 fps ). Compare the screenshots below, and notice how the silhouette of mountains, and the details in lighting / shadows are better in the bottom version.
The 65x65 version almost brings my Q6600+8800 to its knees. But it doesn't stop here. Although I haven't been able to see it myself, I'm guessing the best computers out here, with 4 gigs of ram, extreme quad-core cpus and a 8800 ultra, would be able to run a 129x129 version at low framerates. Of course that wouldn't be good enough to play comfortably, but..
Imagine in a few years. The graphical details will scale to your new computers/video cards.
33x33 terrain patches:

65x65 terrain patches:

Planetary surface types
I've cleaned the code a bit to support multiple planetary types ( I was previously experimenting everything in the same class, commenting / uncommenting pieces of code ). Now I do have some factories for different planet types with different procedural noise functions.
The first one, which I've already presented in depth in the previous updates, are what I described as a "Gaian" planet.
I added a "Desert" planet type, and a "Selenian" planet type. The desert one is based on ridged perlin noise to generate sand dunes. It's extremely boring, so I need to work on it a bit before presenting it ( plus texturing will be important ).
The "Selenian" type is basically a planetary surface based on craters. Lots of them. To implement that, I created a new type of noise which I called "spherical", and which is based on the idea on Voronoi diagrams. A set of spheres are pre-generated, randomly placed in a cube, and when I evaluate the noise at run-time, I calculate the distance between the position and each sphere, and based on the distance, I generate a value that looks like the one of a crater.
It works pretty well, although it's quite slow, but it's no big deal, as there is lots of room to optimize this "spherical" noise.
Why spherical by the way ? Craters are 2D, but the noise basis must be 3D so that you don't get strange seams on the planet ( since all the noise functions are based on the position of the vertex on the planet sphere surface ).
While playing with craters, I found an interesting place, that I didn't know could even exist. It's basically some small craters that got displaced by some extreme cliffs/overhangs. It's hard to see in still pictures, but when you're exploring it really in 3D, it looks surreal. Like alien rock formations.
I love getting surprised by my own creations :)

Motion blur
Last but not least, I spent some time to add a render pipe for motion blur. The basic motion blur technique is rendering the scene to a texture and alpha-blending it with the previous frame, but it's tricky and doesn't look very good ( but it's extremely fast, so I might fall back on that method on computers that have performance problems ).
What I implemented is "true" motion blur: each object gets transformed both by the current frame's transformation matrices and by the old frame's, and a velocity is computed in eye-space. This velocity is stored in a velocity texture. The scene is also rendered into a texture. In post-processing, each pixel samples the velocity texture, and blurs the scene texture N times ( in my current shader, N = 32 ) in the direction of the velocity vector.
The results are pretty good in motion, but show lots of artifacts on screenshots. One of the problem is that no blur is happening outside the silhouette of a moving object, the so-called "occlusion" problem.
In OpenGL shader tricks GDC 2003, Nvidia describes a "solution" to that problem by computing in the shader the dot product between the normal and the motion vector, and using as a vertex either the one of the current frame ( angle > 0 ), either the one of the previous frame ( angle < 0 ). The idea is to extrude the object in the inverse direction of the motion.
I have experimented that idea, but unfortunately it creates more artifacts than it solves.
Project offset apparently uses a similar technique but has found a way to reduce / remove all those artifacts. If anybody has an idea about what they did to solve it, I'm interested.
Because the motion blur requires rendering the scene to a separate velocity texture ( a second pass ), and because there's already 200-300K triangles per frame, there's a serious slowdown ( 50% performance hit ) to enabling true motion blur.


| |
 Planetary engine, Part VII |
Posted - 8/19/2007 12:05:40 PM | Planetary engine
See previous journal update for reference.
Displacements
As I mentionned in the previous update, I've experimented horizontal displacements to create cliffs, overhangs and hard edges. It also creates interesting rock formations, similar to what you'd find on volcanoes. The result is looking quite nice, but as expected there are some issues:
- texture deformations
- terrain is no longer a heightmap, so you can't take a world-space position and cast a ray down anymore, and sample the height in the heightfield to get back the world-space position on the terrain.
- lighting is messed up ( more about that soon ), as the deformation only moves the vertex and not the normal
- performance goes down yet a bit lower
- terrain can self-intersect if the displacement is too high
An overview of the algorithm:
- generate a planetary tangent space for the given sample position
- generate a height from procedural algorithms
- generate a vertex in planet space by displacing the vector going from the planet center to the surface by the planet radius plus the height
- use this new vertex as input to fractal noise - get 2 displacement values, one along x coordinate, another along z coordinate
- displace the mesh by using the tangent space and the given 2 displacement values.
Lighting
To generate normals I was simply derivating the heightfield ( taking the 4 adjacent heights ). But after displacement the mesh is no longer a heightfield, so there are two possibilities:
- the wrong ( but easy ) one, is to not do anything and ignore the displacement: lighting is not correct anymore, but it doesn't look too bad. The only real thing I'm worried about is when adding shadow maps later, the diffuse lighting won't match the angle at which the shadow map starts, so you might see strange artifacts.
- the right ( but hard ) way, is to generate the triangles on the cpu and perform a cross product between the adjacent triangles. Unfortunately, the hard part comes from the fact that you get seams between terrain patches, as you only have access to an adjacent patch's heightfield ( and not mesh ). Fixing it would require a few design changes in the terrain code.
I haven't decided which solution I'll finally use, I guess this will mostly depend on how serious the shadow mapping artifacts will be.
Collisions
Yesterday I also implemented collisions on the terrain, just for fun. Wasn't really hard to do it in the "brute force" way: when the mesh of a terrain patch is generated, I also create a collision mesh for it. I then implemented a canon-ball launcher with the left mouse click, and played with launching balls on the terrain for a good half-an-hour. It was funny to see them bounce and roll on this complex terrain. Performance was okay on the collision tests, but generating the collision mesh ( especially as each time a terrain patch gets subdivided in 4, it generates 4 children, each with its collision mesh ) causes small slowdowns.
Pictures time
As usual, click on an image for the 1024x768 version.






| |
 Planetary engine, Part VI |
Posted - 8/17/2007 6:39:26 PM | Rings/asteroid fields
See the previous dev journal update for reference.
I've been in vacation in France for one week, during which usual development stopped. I used a bit of that time to add a couple of chapters to the new SDD.
A few days before and a few days after my trip, I continued the work on the procedural asteroid fields. I added some dust to the rings to give them a less artifical aspect; but most of the work was actually spent into the interfaces design and the ability to render gas giants ( the last gas giant dev update was only a prototype - I suspect that many people don't realize that less than half the work is done once a prototype is done, it needs to be integrated with the actual engine and game ), the GLSL atmosphere shaders, a brand new GLSL library with helper functions, etc..
FBOs on Vista
I also spent a couple of days tracking the mysterious slowdowns under Windows Vista when rendering to a framebuffer texture. Render-to-texture is heavily used in any modern engine, so it was quite a shock to learn that the overhead was coming from Vista itself. The overhead is actually so huge that it makes render-to-texture impractical performance-wise for any modern effect. To give you an idea, simply rendering to a couple of 64x64 textures goes at 900 fps on a 8800 GTS under XP, and less than 80 fps on my 8800 GTX under Vista. Nice to have such a good ( and expensive! ) video card, to get a 1100% performance hit compared to a 8800 GTS under XP ...
I have contacted NVidia, they have acknowledged the problem and are currently investigating.
Terrain engine
In the past two weeks I've been working quite intensively on the new terrain engine ( and again, the interfaces: things that are extremely important, but that cannot be shown in screenshots ).
I completely rewrote the kernel library to handle procedural functions and noise. Before, everything was in a single source code file, with tons of macros and ifdefs in order to enable / disable tests in the code ( for example the "fast noise" that I described a few months ago in one of the dev journals ). I felt that it was time for a clean rewritting. Various noise types are now available through a CPerlinNoise class, and fractal classes implement more complex behaviors ( CFractalNoise, CMultifractalNoise, CRidgedMultifractalNoise ). Each of those classes can use a callback to a noise type ( simplex noise, improved noise, fast noise ), and has its own set of parameters. At the moment I only have functions for 3D noise, so I still need to find some time to re-implement 2D noise or 3D noise with wrapping, but those are not used very much so far in the code, so I'm not in a hurry.
Heightfield generation
In the previous version of the terrain engine, I was using the following system to generate the heightfield for each terrain chunk:
- a global heightmap is generated from the 6 cube faces of the planet. Each face is usually a 1024x1024 heightmap.
- when vertices are generated, the height is first looked up in this heightmap. When the depth level increases ( you get closer to the ground ), the resolution of this heightmap becomes insufficient. At this point, the Diamond-Square algorithm is used to generate missing heights.
The big advantage with this approach is that Diamond-Square is lightning fast.
The big disadvantage is that it tends to generate terrains that are extremely homogeneous. What that means is that, wherever you go on the planet, you see the same kind of terrain features, the same sort of hills, the same shape of mountains, etc.. Basically, it makes anything under the global heightmap level extremely repetitive and boring.
I played with a lot of tricks in order to add variety, but I only had ( at the time I wrote the old version of the terrain engine ) only half successes. The main problem is that Diamond-Square doesn't have a lot of parameters to it, except its frequency ( how sharp the terrain becomes ). So while I could vary the frequency based on planetary-latitudes/longitudes, it was never possible to generate "interesting" landscapes.
In the new terrain engine, that I've been working on in the past days, I'm working with customizable classes that can redefine the terrain functions. The one I've been experimenting the most is based on Ridged Perlin noise. The main interest with ridged perlin noise is that it generates mountains and shapes that are heterogeneous ( they don't look the same everywhere on the planet ), and mountains that look ridged. Erosion cannot be implemented on procedural planets, but ridged noise gives a pretty realistic aspect to the mountains, so while it's not perfect it's definately a major step towards a more realistic terrain.
The main disadvantage with ridged noise is its performance cost: we're talking tens, if not hundreds of times slower than Diamond-square. Fortunately, everything is relative, and it remains quite fast provided that you don't go too fast at low altitudes. Fortunately, it's not a problem, because any player that tries to go too fast at low altitudes will end up being disintegrated either by colliding with the ground or mountains, either by gameplay mechanics ( friction -> rise of temperature -> ship explodes ). At the moment, I can navigate on the planet at more than 100 fps, and it should be quite easy later to generate noise in multiple threads ( that's an operation that is easily parallelize-able ).
A pure ridged perlin noise generated landscape is already interesting to explore alone, but it's possible to go further by combining it with other functions. One of those is a standard fractal noise ( with only 3 octaves ) that gives an artibrary parameter at the planetary level. This parameter is used to change the frequency or the offset of the noise, to make it even more varied.
Another function is the infamous "terrace" effect. It acts by splitting the altitudes in "steps" and changing the shape of the terrain ( sharper or smoother ) between those altitude steps. This gives a canyoning / terrace effect that is pretty nice to see. Of course, this effect is also affected by the global parameter, so that you don't find terraces on all mountains on the planet.
All the screenshots below show a typical Earth-like planet with the functions described above. Notice how each of them show different landscapes, all on the same planet. I waste a lot of time just playing around and exploring those landscapes.
Future work
In no particular order:
- real terrain texturing ( at the moment, only one texture is used, but it's tiled over a lot )
- experimenting craters
- binding some parameters to a key, and seeing the terrain morph in real-time. It's mostly for debugging, to see how parameters affect the terrain look.
- horizontal displacements, might form cliffs and overhangs
- use diamond square for the very high frequencies
Pictures time
Click on an image to see the 1024x768 version.







| |
|
| S | M | T | W | T | F | S | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | | 18 | | 20 | 21 | 22 | 23 | | | 26 | 27 | | 29 | 30 | 31 | |
OPTIONS
Track this Journal
ARCHIVES
October, 2009
August, 2009
July, 2009
May, 2009
April, 2009
March, 2009
February, 2009
January, 2009
November, 2008
October, 2008
July, 2008
June, 2008
May, 2008
April, 2008
March, 2008
January, 2008
December, 2007
November, 2007
October, 2007
September, 2007
August, 2007
July, 2007
June, 2007
May, 2007
April, 2007
March, 2007
February, 2007
January, 2007
December, 2006
November, 2006
October, 2006
September, 2006
August, 2006
July, 2006
June, 2006
May, 2006
April, 2006
March, 2006
February, 2006
January, 2006
December, 2005
November, 2005
October, 2005
September, 2005
August, 2005
July, 2005
June, 2005
May, 2005
April, 2005
March, 2005
February, 2005
January, 2005
December, 2004
October, 2004
September, 2004
August, 2004
|