Pythonstuff GLSL in English Pythonstuff GLSL auf Deutsch Pythonstuff GLSL Pythonstuff
PythonStuff Home
 

 

Environmental Bump Mapping mit GLSL Cube Maps

Erst mal das Programm:

Die Texturen die in dieser Demo verwendet werden sind hier:

  • textures4.zip File (Das Verzeichnis “textures” dorthin entpacken, wo auch “env_bump_map.py” liegt)

Die Museums-Ansicht stammt von http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/stereographics/stereopanoramic/, sie gehört Peter Murphy.

Das Ergebnis sieht so aus:

Ball mit Environment Cube Map Ball mit Environment Cube Map und Textur Torus mit Environment Cube Map - ohne rauhe Oberfläche

Programm Beschreibung

Um eine reflektierende Kugel (mit wahlweise rauher Oberfläche) zu erzeugen, zeigen wir eine “Cube Map” auf der Oberfläche an. Welcher Punkt der sechs quadratischen Texturen an einer bestimmten Stelle der Kugel angezeigt wird, bestimmt der reflektierte Augen-Vektor.

Diese Reflektionsberechnung wird durch die Oberflächen-Normale gesteuert - das ist damit auch die Stelle, wo wir einfach den Normalenvektor durch eine Bumpmap verändern können, wie im vorigen Beispiel gezeigt.

Wir definieren die Taste “Z”, um die Bumpmap ein- und auszuschalten und die Tasten “N” und “B” (die auf der Tastatur praktischerweise nebeneinander liegen) um die Stärke des Effektes zu beeinflussen:

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

Das Spiegelbild können wir optional durch eine ganz normale Textur “schmutzig” oder “zerkratzt” aussehen lassen - das steuern wir mit der “T”-Taste:

elif symbol == key.T:
    print 'Texture toggle'
    textureon = not textureon

Schliesslich wollen wir auch noch zoomen können(”+” und ”-” Taste):

elif symbol == key.PLUS:
    dist += 0.5
    print 'Distance now ', dist
elif symbol == key.MINUS:
    dist -= 0.5
    print 'Distance now ', dist

Die Cube Map

Die Cube Map belegt 6 hintereinander liegende Textur-Indizes, die wir in einem Schritt reservieren (nach den schon bisher belegten “texturecnt” Texturen).

Wir teilen dem Shader Programm den Index der Reservierung mit:

glActiveTexture(GL_TEXTURE0+texturecnt)
glEnable(GL_TEXTURE_CUBE_MAP)
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap)
shader.uniformi('my_cube_texture', texturecnt)

und laden die Bilder:

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)

Das Shader Programm

Wir deklarieren die Cube Map im Shader Programm durch:

uniform samplerCube my_cube_texture;

und verwenden sie (wieder unter Verwendung des Tangent Space Coordinate System - das macht die Berechnung erstaunlich einfach) wie folgt:

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;

Je heller der “color” Wert ist, desto mehr setzt sich diese Farbe gegenüber der “reflex” Farbe durch. Eine schwarze Textur ist also ein perfekter Spiegel, eine weisse Textur würde die Reflektion komplett überdecken (wie man an dem “pythonstuff”-Label im Bildschirm-Foto sieht).

Und jetzt noch eines obendrauf: Beispiel 9 - Echtzeit-Video !

(auch schon Beispiel 7 - Anisotrope Reflexe gesehen ?)


English version, Start
Impressum & Disclaimer