Environmental Bump Mapping with GLSL Cube MappingThe program The textures used in this demo are here:
The Museum environment texture is taken from http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/stereographics/stereopanoramic/, curtesy by Peter Murphy. The result looks like this: Program descriptionTo create a reflecting sphere (optionally with a rough surface), we display a cube map on the surface of the sphere. Which point in the six square textures of the cube is displayed on a certain spot on the sphere determined by the reflected eye vector. This reflection calculation is controlled by the surface normal vector - and therefore can be easily manipulated by a bumpmap shown in a previous example. We define the key “Z” for switching the Bumpmap on and off, and the keys “N” and “B” (conviniently located next to each other on the keyboard) to control the intensity of the effect: elif symbol == key.Z: togglebump = not togglebump print 'Toggle Bump ', togglebump elif symbol == key.N: normalweight += 0.05 print 'Normal Weight = ', normalweight elif symbol == key.B: normalweight -= 0.05 print 'Normal Weight = ', normalweight The mirrored image can optionally made “dirty” or “scratched” by a classic texture map, toggled by the “T”-key: elif symbol == key.T: print 'Texture toggle' textureon = not textureon Finally we want to zoom in and out (”+” and ”-” keys): elif symbol == key.PLUS: dist += 0.5 print 'Distance now ', dist elif symbol == key.MINUS: dist -= 0.5 print 'Distance now ', dist The Cube MapThe cube map occupies 6 consecutive texture indices we reserve in one step (after the “texturecnt” maps we used up to now). We tell the shader program the index of the reservation: glActiveTexture(GL_TEXTURE0+texturecnt) glEnable(GL_TEXTURE_CUBE_MAP) glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap) shader.uniformi('my_cube_texture', texturecnt) and load the images: glEnable(GL_TEXTURE_CUBE_MAP) cubemap = GLuint() glGenTextures( 1, byref(cubemap)) cubemap = cubemap.value print "CubeTexture is bound to", cubemap glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap) glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) # GL_NEAREST) glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) # GL_NEAREST) cubename = ['cube_map_positive_x.jpg', 'cube_map_negative_x.jpg', 'cube_map_negative_y.jpg', 'cube_map_positive_y.jpg', 'cube_map_negative_z.jpg', 'cube_map_positive_z.jpg'] for i in range (6): cubefile = cubename[i] print "Loading Cube Texture", cubefile cube = resource.texture(cubefile) # instance of class AbstractImage data = cube.get_image_data().get_data('RGBA', cube.width * 4) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA8, # texture.format, # 0, # format cube.width, cube.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data) glDisable(GL_TEXTURE_CUBE_MAP) The Shader ProgramWe declare the cube map in the shader program by: uniform samplerCube my_cube_texture; and access it (again we use the Tangent Space Coordinate System - this makes the calculations surprisingly easy): vec3 refl = reflect(norm, eye); // in tangent space ! vec3 reflw = vec3( 1.0, -1.0, 1.0) * (TBNMatrix * refl); reflex = textureCube(my_cube_texture, reflw); if ( textureon > 0 ) gl_FragColor = mix( reflex, vec4(color, 1.0), smoothstep( 0.7, 1.5, length(color)) ); else gl_FragColor = reflex; The brighter the “color” value is, the more it overrides the “reflex” color. So a black Texture Image would represent a perfect mirror, while a white image would hide the reflections completely (see the “pythonstuff”-Label on the screenshot). Now let's go crazy: Example 9 - adding realtime video ! (have you seen Example 7 - Anisotropic Specular Highlights ?) |