## Example 4 - GLSL Dot3 Bump MappingBased on the previous example we add a Dot3 Bump Map (Normal map). You may be making Bumpmaps yourself soon! The result looks like this: - Source Code is here: Pyglet GLSL Bumpmap Shader Code
The textures are in the Texture Pack 1 and Texture Pack 2 . To run this demo, you need Pyglet and Tristam Macdonald's Library Shader.py. You find everything on the installation page. ## Program descriptionTo implement dot3 bumpmaps, we want to change the normal vector of a surface element according to a direction vector in a selfmade bumpmap (normal map) image.
A bumpmap image contains direction information encoded as RGB-Color values. A flat surface
would be represented by normal vectors pointing straight up - a vector with the value 0/0/1.
Generally the value of the vector components will vary between -1
and 1 (strictly speaking, the z-component just between 0 and 1 - it never
points - 1 ⇒ 0, 0 ⇒ 127, 1 ⇒ 255
So a vector pointing straight up will be R/G/B = 127/127/255: this is a pastel blue tone. This is the reason why most bumpmaps look blueish. For illustration, here is a convex (pointing out) half-sphere: We load this image: texturecnt = 2 # Texturemap0.jpg = Colormap Texturemap1.jpg = Bumpmap Then a button would be nice to turn the effect on and off (let's take “B”) and make its state known to the shader program: global togglebump def on_draw(): .... shader.uniformi('togglebump', togglebump ) .... def on_key_press(...): .... elif symbol == key.B: togglebump = not togglebump print 'Toggle Bumpmap ', togglebump
This out of the way, we face a challenge: up to this point it was sufficient to know what point in the
texture map we are dealing with. Now we need to know in This is called “uv-mapping”, because we need to know in which direction the texture coordinates (traditionally called u and v) point for every vertex. This direction vector is interpolated between the vertices. We can have our tiny little coordinate system for every point on the surface - this is called “tangent space”. We hide the direction vector for “u” in the vertex color (gl_Color.rgb). “v” is not needed - we want an orthogonal coordinate system, so we can get “v” by calculating a vector that points 90 degrees off “u” and 90 degrees off the Normal vector (gl_Normal.xyz). Color components go from 0 to 255 in OpenGL, so we store the vector like this: tangents.extend([ int(round(255 * (0.5 - 0.5 * tx))), int(round(255 * (0.5 - 0.5 * ty))), int(round(255 * (0.5 - 0.5 * tz))) ]) for every vertex in our polygon model. Well, there is another change in the example program. I did away with the rather complicated code for a sphere (remember, you can toggle between “sphere” and “torus” with the “F” key) and thereby simplified the code and made it faster. The only drawback is the non-uniform size of the triangles, but that seems to be a small price to pay. Look at the code for sphere generation, it is quite readable. ## GLSL Dot3 BumpmappingNow that we have added the “u” vector to the polygon model, we can have a look at the shader. In the vertex shader we build the “tiny little coordinate system” - 3 orthogonal vectors: // Create the Texture Space Matrix normal = normalize(gl_NormalMatrix * gl_Normal); tangent = normalize(gl_NormalMatrix * (gl_Color.rgb - 0.5)); binormal = cross(normal, tangent); mat3 TBNMatrix = mat3(tangent, binormal, normal); The “T”angent/“B”inormal/“N”ormal Matrix code is ok, when you know that the “cross” (or “outer”) product of two vectors produces a new vector 90 degrees off as we needed. If we want to do further calculations in “tangent space”, we need to transform the light- and eye-vectors to this coordinate system. Sorry that this sounds dreadful : vVertex = vec3(gl_ModelViewMatrix * gl_Vertex); lightDir0 = vec3(gl_LightSource[0].position.xyz - vVertex) * TBNMatrix; lightDir1 = vec3(gl_LightSource[1].position.xyz - vVertex) * TBNMatrix; eyeVec = -vVertex * TBNMatrix; Once all relevant vectors are transformed, you can do your calculations (in the pixel shader) just as before. The “dot3” calculation is done in the line vec3 norm = normalize( texture2D(my_color_texture[1], gl_TexCoord[0].st).rgb - 0.5); .... vec3 N = (togglebump != 0) ? normalize(norm) : vec3(0.0, 0.0, 1.0 ); We sample the color from the Texturemap1 (0.0 to 1.0), shift it to -0.5..0.5 an normalize (-1.0 to 1.0). If you have not activated bumpmapping, the normal vector will point “straight up” (x=0,y=0,z=1) - remember, this is the “tangent space” coordinate system! With togglebump != 0 the normal will point in the direction given by the bumpmap. Enjoy ! But there is more - let us look at Example 5 - Parallax Mapping with GLSL. References: |