2
\$\begingroup\$

In Dungeon Keeper 2, the walls of the dungeon have different random shapes depending on its state (freshly dug or reinforced, and so on).

They look like they are cubes of 3x3 vertices that have a x-z planar jitter or distortion. However, the corner vertices are shared by adjacent cubes, so there must be some kind of algorithm rather than just a random jitter.

enter image description here

How could I achieve a similar effect?

\$\endgroup\$
  • \$\begingroup\$ "How did X do Y?" is not a good question for this site, since very few users can actually answer it (unless they worked on X and built Y, users can only speculate). I edited your question to instead ask how you can achieve a similar-looking effect, which is more answerable and broadly applicable. \$\endgroup\$ – Josh Dec 16 '13 at 20:10
1
\$\begingroup\$

The shared vertices are either not distorted, or they're distorted in the same way for adjacent cubes. When placing a new cube check the neighbor cubes to get the shared vertex position information, apply the same distortion (to make the position the same), or create a new distortion to be shared by both cubes.

\$\endgroup\$
  • \$\begingroup\$ For example jitter value can be a lookup into an array of e.g. 16 values: JITTER_X = Lookup[POSITION_X mod 16] or some other procedural function (JITTER_X = sin(POSITION_X) * 2 + cos(POSITION_X)) \$\endgroup\$ – Kromster Dec 16 '13 at 6:42
1
\$\begingroup\$

I did this once using a volume texture applied in the vertex shader. The texture was a small tiling block of RGB noise.

I used the worldspace position of the vertex to look-up into the volume texture, interpreting the RGB values as a worldspace displacement vector. That way, all vertices sharing that coordinate would get the same displacement, and not peel apart.

If you do this on a surface like a wall, you'll likely want to slightly rotate/skew your coordinates passed to the texture lookup, so that the tiling is less obvious over large axis-aligned planes.

\$\endgroup\$
0
\$\begingroup\$

If the distortion is done in a shader it can be done by passing the world coordinates of the vertices like this:

uniform float strength;

void main(void)
{
   vec4 pos = gl_Vertex;
   vec4 noisePos = pos;

   pos.x = pos.x + random( vec4( pos.xyz, 0 ) ) * strength;
   pos.y = pos.y + random( vec4( pos.xyz, 1 ) ) * strength;
   pos.z = pos.z + random( vec4( pos.xyz, 2 ) ) * strength;

   gl_Position = gl_ModelViewProjectionMatrix * noisePos;

}

random is not a openGL built in, see https://stackoverflow.com/a/17479300/31151 for implementations

This will have the effect of having each vertex be offset in a pseudo-random fashion, this will also work for corners where the vertices aren't shared (different textures), because the seed is the world position.

If you are rendering multiple textures in a single mesh what I would do is pass in a per vertex int type (from which you can calculate/look up the UV coordinates in the fragment shader) and make the strength parameter an array.

Some possible improvements that might make the effect look better would be:

  • Making the strength uniform a vec3 rather than a straight float to tweak the strength per direction (or vec2 if you only care about changing the height differently).
  • Calculating the offset in a temporary vector and normalizing it, then scaling it.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.