• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
  • entries
  • comment
  • views

Tri-planar textures and bump mapping

Sign in to follow this  
Followers 0


Last summer I started on a project that stalled largely due to my apparent compulsion to write engines, not games, excessively ambitious scope, lack of a realistic project plan and a masochistic hardware target (OpenGL 4.x). However, since ATI seem to have fixed a couple of driver bugs that were plaguing development (for loops with uniform conditionals, and a hideous driver crash), I spent the weekend fiddling with lighting and bump mapping. Even with just two rather amateur test textures I don't think it looks too bad:


The bump mapping was a bit painful, due to using tri-planar texturing for the terrain. While the relevant GPU Gems article touches on the subject of bump mapping, it doesn't really go into detail. Still, I seem to have ended up using a hacky method similar to the code in the article.

The scribbles below show my thinking out the tri-planar texturing method, and the coordinates needed. I'm using the same texture on multiple "sides" of the projection for the moment, and seem to have a slightly different mapping from the article (notice that on all the sides of the cube UP is upwards, not on its side). Splitting out the 6 cases I wanted, the correct texture coordinates can be figured out from the world (/object) space position (they can be combined into 3 by using the sign of the relevant normal).


So far I've not managed to properly generate tangents to perturb the normal, so I'm just swapping the x / y displacement to the relevant world-space axis each for the tri-planar projection, adding it to the normal and normalizing. This is what the bump vector is on the right of the scribbles.

And here's a test image of the terrain using the tri-planar projection:


The snippet of glsl below shows the end result of the scribbles in code. I'm currently using a default texture, and an array of alpha maps / other textures - I might simplify this to include the default in the array at some point. I'm using noise to sharpen and randomise the transition between different textures - this could also be improved, perhaps taking into account the bump map.

// get terrain normal (already normalized)
vec3 normal = texture(NormalsTexture, TexCoords).rgb;

// calculate triplanar texture weights
vec3 tpweights = abs(normal);
tpweights = (tpweights - 0.2) * 7.0;
tpweights = max(tpweights, vec3(0.0));
tpweights /= tpweights.x + tpweights.y + tpweights.z;

vec3 signs = sign(normal);

vec2 tpcoord1 = vec2(vec2(-signs.x * Position.z, Position.y) * DetailTexCoordScale);
vec2 tpcoord2 = vec2(vec2(signs.y * Position.x, -Position.z) * DetailTexCoordScale);
vec2 tpcoord3 = vec2(vec2(signs.z * Position.x, Position.y) * DetailTexCoordScale);

// noise value for blending
float noise = 0.0;
noise += tpweights.x * texture(NoiseTexture, tpcoord1 * NoiseCoordScale).r;
noise += tpweights.y * texture(NoiseTexture, tpcoord2 * NoiseCoordScale).r;
noise += tpweights.z * texture(NoiseTexture, tpcoord3 * NoiseCoordScale).r;

// collect detail texture data based on alpha maps
float alpha_accum = 0.0;
vec3 detail_color = vec3(0.0);
vec3 detail_normal = vec3(0.0);

for (int i = 0; i != NumDetailTextures; ++i) {
float alpha = texture(AlphaTextureArray, vec3(TexCoords, i)).r;

// modulate alpha value with noise, to get sharper, but noisy transitions
alpha = smoothstep(0.48, 0.52, alpha + noise - 0.5);

// calclate triplanar detail colour
vec3 dc = vec3(0.0);
dc += tpweights.x * texture(AlbedoTextureArray, vec3(tpcoord1, i)).rgb;
dc += tpweights.y * texture(AlbedoTextureArray, vec3(tpcoord2, i)).rgb;
dc += tpweights.z * texture(AlbedoTextureArray, vec3(tpcoord3, i)).rgb;

detail_color += min(alpha, 1.0 - alpha_accum) * dc;

vec3 bump1 = tpweights.x * normalize(texture(NormalTextureArray, vec3(tpcoord1, i)).rgb * 2.0 - 1.0);
vec3 bump2 = tpweights.y * normalize(texture(NormalTextureArray, vec3(tpcoord2, i)).rgb * 2.0 - 1.0);
vec3 bump3 = tpweights.z * normalize(texture(NormalTextureArray, vec3(tpcoord3, i)).rgb * 2.0 - 1.0);

vec3 dn = vec3(0.0);
dn += vec3(0.0, bump1.y, -signs.x * bump1.x);
dn += vec3(signs.y * bump2.x, 0.0, -bump2.y);
dn += vec3(signs.z * bump3.x, bump3.y, 0.0);

detail_normal += min(alpha, 1.0 - alpha_accum) * dn;

alpha_accum = min(1.0, alpha_accum + alpha);

// fill remaining alpha "space" with default detail colour
vec3 ddc = vec3(0.0);
ddc += tpweights.x * texture(DefaultAlbedoTexture, tpcoord1).rgb;
ddc += tpweights.y * texture(DefaultAlbedoTexture, tpcoord2).rgb;
ddc += tpweights.z * texture(DefaultAlbedoTexture, tpcoord3).rgb;

detail_color += (1.0 - alpha_accum) * ddc;

vec3 bump1 = tpweights.x * normalize(texture(DefaultNormalTexture, tpcoord1).rgb * 2.0 - 1.0);
vec3 bump2 = tpweights.y * normalize(texture(DefaultNormalTexture, tpcoord2).rgb * 2.0 - 1.0);
vec3 bump3 = tpweights.z * normalize(texture(DefaultNormalTexture, tpcoord3).rgb * 2.0 - 1.0);

vec3 ddn = vec3(0.0);
ddn += vec3(0.0, bump1.y, -signs.x * bump1.x);
ddn += vec3(signs.y * bump2.x, 0.0, -bump2.y);
ddn += vec3(signs.z * bump3.x, bump3.y, 0.0);

detail_normal += (1.0 - alpha_accum) * ddn;

// hacky normal mapping
normal = normalize(normal + detail_normal * BumpScale);

I'm still not 100% satisfied with this, and will probably try out the method of generating a tangent basis touched upon in the GPU Gems article and see if it looks better. In the mean time I'd love to hear if anyone else has done any bump mapping with tri-planar texturing, and how you got it to work.



Sign in to follow this  
Followers 0


There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now