 Terrain texturing |
Posted - 3/28/2008 3:38:00 PM | This journal will cover terrain texturing, and since I haven't taken new screenshots since the last time, it's probably going to lack nice images. But I'll explain a bit the approaches I took with terrain texturing so far, the algorithm I finally settled on, and its limitations.
If you usually don't understand the technicalities of my journals, move on ! because this one will be particularly tough.
State of the art
Preprocessed textures with detail maps
Textures are generated from real photos, retouched by artists, or pre-processed by another software ( like Terragen ). They are stored in files on disk, usually split into areas, and each area is applied to a part of the terrain. For example, Google Earth, Flight Simulator, etc.. are based on real photos, but other games use artist-made textures.
The size of the world is essentially limited by disk space. Because the resolution isn't good enough for close up views, most games apply some detailed textures. Old games only had one detailed texture ( grayscale ), but more recent ones use a set of colored detailed textures.
If I'm not mistken, this is also the technique used in Far Cry / Crysis.
Tiles
In this approach, artists create small textures, called tiles, that contain all the possible transitions between various terrain types. Many of them are packed together in a bigger texture, a set / pack, for efficient usage. This is quite fast and requires less artistic work, but it's an old technique.
Its main flaw is its difficulty to be applied on a terrain with level of detail, and the lack of variety, the repetition patterns, although that can be hidden with a high amount of tiles.
Think of Warcraft 3.
Texture splatting
With this technique, a set of layers ( grass, rock, snow, etc.. ) are blended together depending on local terrain parameters such as slope / altitude.
Most of the time, the algorithm runs at the vertex level: the cpu computes the parameters, and blending weights are passed to the vertex shader. In the pixel shader, the layers are all sampled and combined based on the weights. For example, with 3 layers (GLSL):
vec4 tex0 = texture2D(grassTex, uv);
vec4 tex1 = texture2D(rockTex, uv);
vec4 tex2 = texture2D(snowTex, uv);
vec4 color = tex0 * weight.x + tex1 * weight.y + tex2 * weight.z
One huge problem with this technique is its cost: it's not too bad for 3 layers, but the higher the number of layers, the slower it becomes. Imagine 10 layers. Now, imagine that you also need to sample the normal maps; you're now sampling 20 textures.
I will come back on this technique since it is the heart of what I've finally chosen, with important changes.
Disk space is minimal. Since pixel shading is dependant on the amount of layers that must be combined, a good way to optimize this technique is to compute the N layers the most important per terrain patch, and only sample those.
The old approach
Back in 2005, my first terrain texturing prototype used a derivative of the splatting algorithm. This is, to date, the one still used in the screenshots of the terrain on the website.
The algorithm allocated a unique texture per terrain patch ( let's say 128x128 ), and used the GPU to render to this texture to generate the texturing per slope and altitude, combining N layers.
At this time, I was using 8 layers, and no bump/normal maps. So all it required to work was 8 texture units and pixel shaders 2.0.
There were some real drawbacks though:
- video memory usage: for 1000 patches, a 256x256x4 per patch consume dup to 256 MB of video memory. At 128x128, only 64, but it started to look more blurry.
- small stalls that depend on how fast the pixel shader is at rendering one texture patch.
- no texture compression is possible, as the textures get computed on the gpu, and the compression is implemented in the drivers on the CPU. Enabling texture compression caused the texture to be downloaded from the gpu to the cpu, compressed, then reuploaded cpu to gpu, which cause insane freezes.
- because there's a unique texture per patch, when the terrain LOD stops at the maximum depth level ( lowest to the ground ), textures of course cannot get more refined, and you get a blurry mess.
- screen resolutions always increase. At that time, 128x128 might have been okay in 800x600, but unacceptable for 1680x1050. 256x256 better, but still blurry. The next step would be to use 512x512, but this would cost 1 GB of video memory.
- of course, some video memory must remain for ship textures, backgrounds, effects, GUI, effects buffers, etc.. So it isn't realistic to use 100% of the video memory just for terrain texturing. 50% would be a better number.
- no bump/normal mapping. This would require another renderable texture per patch, multiplying the video memory cost by 2 again.
Summary
If I simply reused this technique today, the results would be:
- let's assume a video card with 512 MB of video memory.
- the budget is 256 MB for terrain texturing
- divided by 2 to have bump mapping, so the real budget is 128 MB
- for 1000 patches, this means the highest resolution the patches could be is 128x128.
- clearly this wouldn't look too good in high resolutions (1280x1024, 1680x1050, etc.. )
Experiments
In January 2008, when I reimplemented the terrain texturing, I experimented many ideas.
The basic one is texture splatting, pretty much as everybody implements it.
But, unlike everybody, I don't have a 10 Km x 10 Km zone to texture. I have a whole planet.
In my early experiments, I have found that 10 layers is the absolute minimum per planet to recreate believable variety. The quota is quickly reached: for an Earth like planet for example: 2 grass, 2 rocks, 2 snow, 2 sand, 1 mud, 1 forest. 16 layers would be more comfortable. But let's stick to 10 layers for now.
The first problem is that most video cards under the latest generation ( GF8 ) only have 16 texture units. Working in multiple passes is a sure framerate killed. So how to do texturing with 10 layers in 1 pass ?
If you want at least some bump mapping, you need 20 texture units. Then you have additional effects that require TMUs too. For example, at the highest quality, shadow maps use 4 TMUs.
So what could be done ? Make a choice:
- goodbye bump mapping
- goodbye special effects (and particularly shadows)
- goodbye variety (reducing the number of layers to 6, which would just fit the 6*2+4 = 16 TMUs).
- goodbye framerate (going to multi-pass and re-render 300K triangles per frame, and keep in mind that the per-object overhead is higher in I-Novae than in other engines due to it working in camera space for high precision).
Clearly, none of this sounds too good either...
Texture sampling explosion
Another problem with the technique described above is that it quickly leads to an explosion of texture sampling instructions. Let's see:
- 10 layers, requires 10 sampling operations.
- with bump mapping, multiply this by 2 -> 20
- UVs must be adjusted to work at any level, from close ground views up to space orbits. For this, you need to sample once for a given UV, adjust the frequency, sample again, and then interpolate. The global cost is x2, so we're now at -> 40
- finally, to avoid popping of textures, blending must be done between 2 textures too. The global cost is again x2, so we're now at -> 80.
You read this right: for 10 layers, a proper shader would need to sample our 10 textures 80 times !
Volumetric textures
My first problem was how to keep all those features in a single pass within 16 TMUs: The Quest For Reducing The Number Of Texture Units (tm), and if possible, reduce the number of samples instructions.
I quickly thought it would be possible to trick it, by packing all the texture layers together as a "stack" into a 3D ( volumetric ) texture.
It worked.. kinda. The TMUs count problem disapeared, but new ones appeared: mipmapping. I though that by playing with filters, it would be possible to only mipmap in 2D but not in the stack / Z direction, but the hardware doesn't work that way..
Disabling mipmaps ? Say bye bye to your framerate, especially in high altitudes views, as all your pixels are high frequency and need to access the volume texture in a random order.
Later I realized that this could be properly implemented ( with good mipmapping and performance ) with texture arrays. But this is a GF8+ extension, so this would mean requiring pixel shaders 4.0. Maybe in a few years..
Texture packs
I was starting to run out of ideas when I realized the layers could be packed together into a huge texture. For example, if all texture layers are 512x512, you can pack 16 of them (4x4) in a single 2048x2048 pack.
Mipmapping wasn't obvious anymore, as mipmaps had to be recreated manually by taking care of the packing and adjacent pixels.
Tiling wasn't obvious anymore, as what you actually need is sub-tiling: tiling UVs within a region of a bigger texture. But this could be faked in the shader..
Mipmapping also required special care, as you need to compute the mipmap level yourself in the shader ( rather than letting the hardware do it ), else you get seams when mipmapping between tiles within the pack.
Fortunately, all of those, while tricky, are relatively inexpensive, a few instructions each. And they are not per-layer, but per pack, so finally, you only need to do it once or twice in the complete shader..
The procedural texturing had to be changed, too. Instead of getting blending weights, I had to sample for a texture ID given a slope/altitude. This ID is then used to compute the UVs for the tile within the pack. This is also a fast operation.
In total, to have mipmapping + bump mapping + 10 or more layers + morphing + UVs at all altitudes, the shader only needs 12 texture samples. Much better than the 80s of the previous algorithm.
The downside is that it's no longer a pure texturing bottleneck, as all the tricks require arithmetic operations. While each one is cheap, it quickly sums up and becomes expensive.
The final shader is around 300 instructions, and the texturing part only consumes 3 TMUs:
- one TMU for the diffuse texture pack
- one TMU for the bump texture pack
- one TMU for the lookup table (slope/altitude -> layerID).
If you have followed so far, you would have noticed something else: the LUT gives a single layerID. So only one layer is used per pixel. This leads to the "sharp edges" in terrain features that many people have noticed and criticized in the latest terrain screenshots.
The LUT can of course be used to store a second layerID, but this multiplies the number of samples by 2. Since the shader is already super slow.. I'm living with this "limitation".
The future ?
The terrain shader is by far the most complex and tricky shader I've ever written, but there's still a lot of room for optimizations. I already have ideas to save 20-30 instructions in the shader without too much effort. By optimizing even more, I'm confudent I can get it down to 250 instructions. That's still a lot, so in high resolutions ( and even not-so-high ones ), the game tends to be heavily pixel-shader limited.
This is of course assuming max quality settings. The shaders all have pre-processing directives, so complete features / effects can be disabled to save performance on slower video cards.
I have no plans to continue to work on the terrain shader in the short term. Maybe in 1 or 2 years, I will come back to it, especially as more and more video cards become pixel shaders 4.0+ able, the texture arrays approach would allow to reimplement this shader in a much more efficient way. Combine that + the rise of video cards powers, and it is likely that in 2 years, a texture-arrays shader on a next-gen cards would be 2 or 3 times faster than what I currently have on my GF8.
If people are interested in all those tricks for the shader, I can post some snippets.
In a future dev journal, I will also come back on noise, and how I need to combine 10 octaves per pixel ( so 10 additional texture samples ) in order to make the features more natural. I'll also mention a few words about geometry ( procedural heightmaps generation ), clouds and water.

| |
 Two years of contributions: the mega thread (56K n |
Posted - 3/24/2008 9:31:10 AM | No way in hell I could have done that manually, so I asked OrangyTang from gamedev.net his python script to collect all pictures posted in gamedev.net's journals, and adapted it for the contributions forum.
The result is a mega thread of 25 pages, each containing hundreds of thumbnails of pictures that have been posted in the contributions forum. That's around 12000 images !
All the pages directory can be seen here. Sorted by time, so the more recent pages are in the 20-30:
http://www.infinity-universe.com/Infinity/Contribs/
Clicking on a thumbnail will lead to the thread it has been posted in.
The Python script used to produce those images is also in the above directory. I had to adapt it to parse phpbb forums, ignore unaccessible/deleted threads, ignore avatars/signatures/smileys, etc.. I also made it multi-threaded (20 threads yey!) so that it processes faster.
| |
 Terrain engine |
Posted - 3/18/2008 3:27:32 PM | Nitpicking
- clouds don't have a coriolis effect
- no storm effect
- motion blur / bluriness in starfield
- clouds have patterns
- terrain too blue
- atmosphere too thick
- over saturation to white
- areas too sharp / contrasted
- terrain only based on altitude / too randomized
- texture pack for ship is too low contrast / flat
- jagged / aliased shadows
- too strong stars reflections
- lack of bloom
- star field edges are visible
- only one type of clouds
I'm not complaining. Just noticing. I'm getting more and more scared of posting updates. The amount of anticipation, hype and expectation is rising, and honnestly, while many of those remarks are valid and will be fixed, many of them are just not on my todo list.
Take the comment about jagged shadows for example. I've explained in great lengths in past dev journals that a technical choice had to be made between shadow resolution / aliasing, shadowing range and performance. If you increase the range and keep the same number of shadow maps, you'll get more aliasing. If you increase the shadow resolution or amount of shadow maps to decrease the aliasing and keep the same shadowing range, you'll hurt performance ( which is already quite low ).
It's a bit annoying as a programmer to say "this can't be fixed, or I don't have more time to spend to improve that", but really, I have to progress on the game itself.. all I'm saying, nit-pick as long as you want, but don't expect everything to be perfect at release time.
Screenshots time
Sorry for the lack of anti-aliasing, I forgot to enable it before taking those pictures, and I didn't want to spend another half an hour just to take a new set.
Behold, lots of pictures today !
Terrain texturing, sun shafts / god rays, vegetation ( not procedural, modeled and textured by SpAce ), etc...




















| |
 Stormhawk and Bellerophon + space views |
Posted - 3/16/2008 3:11:57 PM | Anti-aliasing with multiple render targets
It took me months to figure out ( of course, not full time. Just a couple of hours here and there ), but I had a serious problem to combine anti-aliasing with multiple render targets.
Inn OpenGL, it all comes down to how to make the EXT_framebuffer_object, ARB_draw_buffers, EXT_framebuffer_blit and EXT_framebuffer_multisample extensions work together.
The geniuses who wrote the specification were apparently too lazy to make this case work. According to the specification,
Quote:12) Should we add support for multiple ReadBuffers, so that multiple color buffers may be copied with a single call to BlitFramebuffer?
Resolved: No, we considered this but the behavior is awkward to define and the functionality is of limited use. |
It is infuriating me to hear, in 2008, that combining anti-aliasing with multiple render targets is of "limited use".
To make a long story short, I found a workaround by blitting all the render targets manually one-by-one. It's not as optimized ( thanks to Vista, where binding FBOs many times is horribly slow ), but at least it works.. unfortunately I haven't got the chance to test it on ATI cards yet, so I'm expected loads of problems on them.
Spherical Harmonics
I researched a bit on spherical harmonics in order to improve the shading a bit. One thing I wanted to achieve is, for a ship in orbit around a blue planet, to have a subtle blue-ish color coming from the direction of the planet. A good way to do that is a cube map, but the details are too high frequency, so I would have had to blur this cube map. A better approach is to encode some infinite lights in spherical harmonics at a very low frequency.
While I was at it, I also added some slight reflectance on ships between each other, also added to the spherical harmonics. The intensity is estimated based on an approximation of the relative size of a ship from the viewpoint of another one. So this means that if two ships get close to eath other, a bit of light will be reflected between each other.
All those calculations are done on the CPU, and all that is left on the GPU is to evaluate the 9 spherical harmonics terms in the pixel shader; this is a relatively low cost.
Oren-Nayar lighting model
I modified the ships lighting model to use Oren-Nayar instead of Lambert. At the moment, the whole equation is evaluated per pixel, but I'm planning to encode it in a lookup texture instead. To be honest, the difference with lambert on ships isn't that visible, so I'll probably only apply it in high settings. However, asteroids ( which are rougher ) do look significantly better with it.
Sun shafts / god rays
I will come back on it in a later update, but I have added a sun shaft ( god ray ) effect ala Crysis. It's a screen space effect, but it looks volumetric, and it matches the actual shadows. It looks really good, although it requires to take various samples in screen space, up to 64. Sampling a screen buffer 64 times per pixel isn't exactly fact, even on a 8800 GTX, but this is of course for the highest quality. On slower cards, it is possible to only sample 32 or 16 times, although sampling patterns start to appear.
The implementation is rather easy: project the light source ( sun ) into screen-space, and perform a radial blur while accumulating and fading out samples. I improved the initial ideas a bit with all sorts of optimizations, and clipping the light source to the screen boundaries, fading with the camera-to-light angle, etc..
I'll post some pictures later, but this is definately a nice effect that was quickly implemented ( in like 2 hours ) and that adds a lot to the realism and rendering quality, especially on planets at sunsets :)
High-dynamic range
I've also spent a lot of time to reimplement HDRI in GLSL, and fine tune all the parameters; making the bloom not too strong, etc.. I ended up using the improved Reinhard tone-mapping operator. The basic Reinhard operator was washing-out the colors ( they never achiever pure white ); but the improved version is better, as you can specifiy the intensity of the white color in HDR space.
Still, HDR was and is still a real pain to tune. Especially in space scene. Imagine a small ship inside a starfield. The camera is quite far, so the ship is only a few hundred pixels on screen. All tone-mapping operators make use of the average scene luminance.. which is extremely low in a space scene, since 90% of the pixels are black. The result is that the ship is naturally over-exposed. Fortunately, Reinhard's operator does a decent job at avoiding over-exposition, but you can immediately forget any linear operator.
Databases
A few words about databases. I've done some performance tests with Mysql about the amount of queries and operations I can do per second, and although it's very dependant on the complexity of queries, amount of bandwidth between the mysql client/server, size of the tables, etc.. I believe I will not be able to exceed the order of 10K queries per second on a decent machine. That sounds a lot, but I think I can do a lot better by implementing a high-performance, memory cached database myself. The code is already ready, but I have to do some performance tests to compared with a "real" Mysql server. I'm expecting a x10 performance boost, but it won't use SQL as the query language, but instead a specific restricted interface. The final plan is to mix mysql were reliable data is needed ( accounts for example ) with my high-performance simplified database when unrealiable data is acceptable.
New screenshots
Last but not least, a brand new serie of screenshots. With anti-aliasing back :)
Showing the Stormawk, modeled by CJ and textured by Juan; and the Bellerophon, by Spectre, with its temporary texturing by me.








| |
 Horizon culling |
Posted - 3/4/2008 10:06:49 AM | Status:
First of all, a little status check. I know I haven't posted a lot of dev journals in the past 2 months, but there's a good reason for that. And it's not because I've been inactive, quite the contrary. I easily spent 80+ hours of work ( split 50/50 between normal job and Infinity work ) in the past 3 weeks.
I feel extremely tired.
Other than the main reason, work, I must also say ( even if I've already complained about it before ) that the pressure is increasing. By pressure, I mean community / management pressure, of course. Private messages, people disturbing me on IRC to ask simple questions ( killing my train-of-thought - if you're no programmer, don't try to understand ), e-mails, requests to get informations on tons of topics..
I think I will soon arrive to a point where, to be able to continue to get actual work done, I'll have to stop coming on IRC or answering emails/PMs at all.
Anyway, back on topic:
I had to re-prioritize a bit the development due to "business opportunities". Nothing that I can announce yet ( if it even gets done ) though. In any case, other than the priorities shift, it shouldn't affect Infinity or its development in any way.
In the past 2 months, I've mostly finished the development of the terrain engine. It's coming along very well. I'm also integrating a lot of older prototypes into the game client. Not particularly hard, but it can be quite long, and a lot of shaders had to be rewritten in GLSL, and tested..
I've added a lot of new features, but I will post more detailed journals about each of them in the coming days.
For now, I just want to make a quick journal about horizon culling.
Horizon culling
If you're no programmer/mathematician, you can stop reading here: you will not understand.
I've been using HC for a while, but the algorithm I've been using wasn't mathematically correct; it was also computationally expensive.
The goal of HC is to hide terrain patches that are hidden by the curvature of the planet's surface.
In maths term, the idea is to find whether a sphere ( approximating the object / terrain patch ) is totally inside the "shadow cone" of another sphere ( the whole planet ) from a camera viewpoint.
Surprisingly, it looks like it's very hard to find such an algorithm on the web. So with my coworker Inigo Quilez, who is better at maths than me, we came up with the following equations. First, a diagram showing the setup in 2D:

- the red circle represents the first sphere ( planet ), at an origin O with a radius R.
- the blue frustum represents the shadow cone. The camera viewpoint is called C and is located at the apex. This cone is tangent to the red sphere. In 3D, it forms an ellipsis, but in 2D, I've represented it as a point Q.
- the yellow sphere represents the object, at an origin O' with a radius R'.
Some other definitions:
- D is the distance between the camera C and the red sphere's origin O;
- D' is the distance between C and the yellow sphere's origin O'.
- T is the distance between C and Q ( Q being a tangent point on the red sphere ).
In order to determine whether the object ( yellow sphere ) is occluded by the red sphere ( planet ), there are two conditions:
- it must be in the shadow cone ( blue frustum ) AND
- it must be behind the capping plane drawn in brown in the diagram, defined by the plane at point P with normal N.
Those are two different problems with their own equations. Let's have a look at the first one.
Cone test
- alpha is the angle for the planet's cone.
- beta is the angle for the object's cone.
- gamma is the angle between the camera and the two sphere's origins.
Calculating gamma is easy:
- normalize OC = |OC|
- normalize O'C = |O'C|
- perform a dot product between the two to get the cosine:
cos(gamma) = dot(|OC|,|O'C|)
The object is visible iif gamma < alpha - beta
Unfortunately, you should notice that we need to subtract two angles. We cannot do that directly with dot-products ( cosine of angles ), but we can use a little transformation of the original formula, as cos(a + b)=cos(a).cos(b) - sin(a). sin(b):
cos(gamma) < cos(alpha).cos(beta) + sin(alpha).sin(beta)
From now on we'll refer to cos(gamma) as K.
Next step: let's find the values of cos(alpha), cos(beta), sin(alpha) and sin(beta):
In triangle COQ we get:
cos(alpha) = T / D
Using pythagoras theorem on COQ we also get:
D.D = T.T + R.R
T = sqrt(D.D - R.R)
so
cos(alpha) = sqrt(D.D - R.D) / D
In the same way,
cos(beta) = sqrt(D'.D' - R'.R') / D'
For the sine it's even more easy: from triangle COQ again we get:
sin(alpha) = R / D
and
sin(beta) = R' / D'
Are we done ? Not yet. Notice that there are some square roots and slow divisions. Those can be optimized. The equation now is:
cos(gamma) < cos(alpha).cos(beta) + sin(alpha).sin(beta)
K < (sqrt(D.D - R.D) / D).(sqrt(D'.D' - R'.R') / D') + (R.R')/(D.D')
D.D' can be put in common and moved to the left of the equation:
K.D.D' < sqrt(D.D - R.R).sqrt(D'.D' - R'.R') + R.R'
K.D.D' - R.R' < sqrt(D.D - R.R).sqrt(D'.D' - R'.R')
We square both sides:
K.K.D.D.D'.D' - 2.K.D.D'.R.R' + R.R.R'.R' < (D.D - R.R).(D'.D' - R'.R')
NOTE: we are only allowing to do this when the left term is positive. Fortunately, the right term is always positive, so if the left term is negative, the result of the equation is TRUE and we can stop here.
We develop the right side:
K.K.D.D.D'.D' - 2.K.D.D'.R.R' + R.R.R'.R' < D.D.D'.D' - R.R.D'.D' - D.D.R'.R' + R.R.R'.R'
After simplifying and re-arranging:
-2.K.R.R'.D.D' + R.R.D'.D' + R'.R'.D.D < (1 - K.K).D.D.D'.D'
Dividing by D.D.D'.D' twice gives:
-2.K.(R / D).(R' / D') + (R / D).(R / D) + (R' / D').(R' / D') < 1 - K.K
The fantastic thing is that if you set K1 = R / D and K2 = R' / D', you get an equation without any square root nor division:
-2.K.K1.K2 + K1.K1 + K2.K2 < 1 - K.K
Finding P and N for the clipping plane:
N is easy: it equals -|CO|
To create the clipping plane, we also need a point on this plane, which we called P:
P = O + N.y
Let's find the value of y:
In triangle CQP we have:
T.T = x.x + h.h ( Pythagoras theorem )
In triangle POQ:
R.R = h.h + y.y
So h.h = R.R - y.y
We replace in the first equation:
T.T = x.x + R.R - y.y
But we also know that T.T = D.D - R.R and x = D - y (by definition)
So
D.D - R.R = (D - y).(D - y) + R.R - y.y
D.D - 2.R.R = D.D + y.y - 2.D.y - y.y
-2.R.R = -2.D.y
y = R.R / D
Final algorithm:
So many formulas.. the code must be complex, right ? Not really. Let's have a look:
///
/// Performs horizon culling with an object's bounding sphere, given a view point.
/// This function checks whether the object's sphere is inside the view cone formed
/// by the view point and this sphere. The view cone is capped so that the visibility
/// is false only in the 'shadow' of this sphere.
/// @param view Position of view point in world space
/// @param obj Bounding sphere of another object.
/// @return true if the object's bounding sphere is visible from the viewpoint, false if the
/// sphere is in the shadow cone AND not in front of the capping plane.
///
TBool SSphere3DF::horizonCulling(const SVec3D& view, const SSphere3DF& obj) const
{
SVec3D O1C = m_center - view;
SVec3D O2C = obj.m_center - view;
const TFloat D1 = O1C.getLength();
const TFloat D2 = O2C.getLength();
const TFloat R1 = m_radius;
const TFloat R2 = obj.m_radius;
const TFloat iD1 = 1.0f / D1;
const TFloat iD2 = 1.0f / D2;
O1C *= iD1;
O2C *= iD2;
const TFloat K = O1C.dot(O2C);
const TFloat K1 = R1 * iD1;
const TFloat K2 = R2 * iD2;
TBool status = true;
if ( K > K1 * K2 )
{
status = (-2.0f * K * K1 * K2 + K1 * K1 + K2 * K2 < 1.0f - K * K);
}
TFloat y = R1 * R1 * iD1;
SVec3D P = m_center - y * O1C;
SVec3D N = -O1C;
SPlane plane(N, P);
status = status || (plane.getDistance(obj.m_center) > obj.m_radius);
return status;
}
The algorithm has of course been extensively tested and validated, so you can safely use it in your own projects ( if you find a use for it ) :)
| |
|
| S | M | T | W | T | F | S | | | | | | | 1 | 2 | 3 | | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | | 17 | | 19 | 20 | 21 | 22 | 23 | | 25 | 26 | 27 | | 29 | 30 | | | | | | |
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
|