Thursday, 19 March 2009

LoD, Interpolated Hairs and Length Constraints

A large step in making the application more viable for use in an actual game is the Level of Detail filtering. As the hairs are built of polygonal strips it allows for a relatively simple algoritm to be implemented using an Index Buffer. Strips at current are built of 64 vertices, 2x8 for each section of the cubic splines. This number is handy also in that it is a power of 2 which allows recursive halving of the number of vertices making up a strip, i.e. 64, 32, 16, 8. This means that instead of creating new vertex data for each detail level only different sets of indices are needed to render with the same data in the vertex buffer. These sets of indices will iterate through every vertex, every second pair of vertices, every fourth pair of vertices and every eighth set of vertices. While the actual implementation is not as smooth as this theory suggests the addition has become critical to the performance with the addition of a geometry shader.


The interpolated hairs are added to the application using a geometry shader. Geometry shaders are a relatively new addition to the shader architecture but of most significance is their ability to produce more primitives than what they take in. The basis for duplicating the hairs using the geometry shader is simple:
  1. Take in three vertices
  2. Add those vertices to the current triangle stream
  3. Restrart the strip
  4. Add those same vertices again but slightly displaced
  5. Repeat 4 and 5 as needed
The main problem to note when using the geometry shader is that things can quickly become expensive as all these strips must still pass through the pixel shader after being created.


Length constraints proved elusive at first and the problems caused by slight inconsistencies proved to come in an interesting range. One of the first mistakes when implementing was using the old vertex data as opposed to the new, this for a while had vertices shooting off into infinity. A good deal of head scratching, debugging and class rearranging solved this problem to present another. The next problem in the constraints is probably best described as imploding/exploding hair as the very rigid constraints and the mass spring system seemed to have conflicting aims. At this points it must be pointed out that the method of constraint went something like this:

vMoving = (vFixed) + Normalize((vMoving) - (vFixed)) * (fIntendedDistance);

Where pmoving is the vector to be moved and pfixed is static. This method it turns out is only viable for so much of the constraints. To prevent the imploding/exploding effect most of the points for the hair must be constrained using a slightly different approach which is:

vector3 vDelta = (v2) - (v1);
float fDistance = vDelta .x*vDelta .x+vDelta .y*vDelta .y+vDelta .z*vDelta .z;
fDistance = sqrt(fDistance);
vDelta *= 0.5f * (((fIntendedDistance) - fDistance) / fDistance);
(v1) -= vDelta;
(v2) += vDelta;


In all it now looks something like this:

No comments: