TEXTURE MAPPING PART II CS 4363/6353 WHAT WE KNOW • We can open image files for reading • We can load them into texture buffers • We can link that texture buffer to a variable in the fragment shader • We can access the texture in the fragment shader using a sampler2D RECTANGLE TEXTURES • There’s another mode called GL_TEXTURE_RECTANGLE • Works just like GL_TEXTURE_2D, but… • Texture coordinate range is the width and height of the image (not normalized) • Can’t be mipmapped • Texture coordinates cannot repeat • Do not support compression • Useful for when you need to process image data (image processing), not just texture • Typically, you create an orthographic projection with 0,0 on the bottom left • First quadrant of the Cartesian system OpenGL SuperBible Example CUBE MAPPING • Used for “skyboxes” • Used for faking reflections • Comprised of 6 individual images • Treated as one texture • Can be mipmapped (glGenerateMipmap (GL_TEXTURE_CUBE_MAP) ) • We’re going to have 3 texture coordinates! • S • T • R • It’s easiest to think of this as a normal because the cube “surrounds” you Neg Z OpenGL SuperBible – Chapter 7 Neg Y Neg X Pos Z Pos X Pos Y LOADING CUBE MAPS • Create/Bind a buffer like normal • Still load using glTexImage2D, but must pass: • • GL_TEXTURE_CUBE_MAP_POSITIVE_X • GL_TEXTURE_CUBE_MAP_NEGATIVE_X • GL_TEXTURE_CUBE_MAP_POSITIVE_Y • GL_TEXTURE_CUBE_MAP_NEGATIVE_Y • GL_TEXTURE_CUBE_MAP_POSITIVE_Z • GL_TEXTURE_CUBE_MAP_NEGATIVE_Y Example: glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, bitmap_data); TEXTURE PARAMETERS • Still have MAG and MIN filters, but… • Specify it’s a GL_TEXTURE_CUBE_MAP • Specify how to wrap each texture coordinate • Example glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 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); SKYBOXES • Literally just a giant box with a texture on it • It follows the camera! • It doesn’t rotate with the camera • How do we map the cube map to the cube? • What are the texture coordinates? SKYBOXES • Literally just a giant box with a texture on it • It follows the camera! • It doesn’t rotate with the camera • How do we map the cube map to the cube? • What are the texture coordinates? The same as their positions! SKYBOXES • Literally just a giant box with a texture on it • It follows the camera! • It doesn’t rotate with the camera • How do we map the cube map to the cube? • What are the texture coordinates? • How do we sample the texture in our fragment shader? Using a sampleCube variable // Skybox Shader by Richard S. Wright, Jr. #version 330 in vec4 vVertex; uniform mat4 mvpMatrix; varying vec3 vVaryingTexCoord; void main (void) { vVaryingTexCoord = normalize (vVertex.xyz); gl_Position = mvpMatrix * vVertex; } #version 330 out vec4 vFragColor; uniform samplerCube cubeMap; varying vec3 vVaryingTexCoord; void main (void) { vFragColor = texture (cubeMap, vVaryingTexCoord); } REFLECTIONS OpenGL SuperBible – Chapter 7 // Reflection Shader – Richard S. Wright Jr. #version 330 in vec4 vVertex; in vec3 normal; uniform mat4 mvpMatrix; uniform mat4 mvMatrix; uniform mat3 normalMatrix; // Just the rots of the mv uniform mat4 mInverseCamera; // The camera matrix inverted smooth out vec3 vVaryingTexCoord; void main (void) { // Normal in eye space – only rots vec3 vEyeNormal = normalMatrix * vNormal; // Vertex in eye space vec4 vVert4 = mvMatrix * vVertex; vec3 vEyeVertex = normalize(vVert4.xyz/vVert4.w); // Calculate a reflection vector, then invert it vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), 1.0); vCoords = mInverseCamera * vCoords; vVaryingTexCoord.xyz = normalize(vCoords.xyz); gl_Position = mvpMatrix * vVertex; } USING MULTIPLE TEXTURES • Second texture useful for: • Adding multiple colors together • Using it as a bump map • Using it as a specular map • Using it as a transparency map FOR COLOR ALONE BUMP MAPPING • Used to approximate very rough surfaces • Using the second texture to adjust the normals of the surface • Per fragment, not per vertex • In the case below, all N◦L is the same BUMP MAPPING • Used to approximate very rough surfaces • Using the second texture to adjust the normals of the surface • Per fragment, not per vertex • In the case below, all N◦L is not the same • Gives off a different amount of light! • Note – the geometry has not changed! EXAMPLE EXAMPLE FROM BOOK AN EXTREME EXAMPLE http://www.chromesphere.com/Tutorials/Vue6/Optics-Basic.html PARALLAX MAPPING • Approximate parallax • Changes the texture coordinate based on view vector and normal • Need a height map http://www.jpjorge.com/index.php?headfile=portfolio.php&topic=4 http://www.virtualworldlets.net/Resources/Hosted/Resource.php?Name=ParallaxFlash BILLBOARDING • Image always faces the camera (think of the math!) • Typically has transparency • Useful for trees • Useful for particle effects http://www.neotos.de/en/content/megaview-jogl-opengl-java-3d-engine POINT SPRITES • OpenGL 1.5 • Based on billboarding • Can place a 2D texture using a single point! • Previously, needed two triangles • 1/4th the bandwidth • No aligning the quad to face the camera • Using them • Bind a 2D texture • Draw using http://www.whatsthelatest.net/tutorials/run-macs-flurry-screensaver-windows-xp/ glPolygonMode (GL_FRONT, GL_POINTS) TEXTURE ARRAYS • Packing several images into a single texture units (GL_TEXTURE0) • Good for 2D animations • Similar use: • • glBindTexture (GL_TEXTURE_2D_ARRAY, texBufID); • glTexParameteri (GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); However, to load the image, we are now in 3D! glTexImage3D (GL_TEXTURE_2D_ARRAY, level, internal_format, w, h, depth, border, format, NULL); • The depth parameter specifies how many images are in the array LOADING THE ARRAYS for (int i = 0; i < num_images; i++) { data = loadBitmap (“image”+i+”.bmp”); glTexSubImage(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, w, h, 1, GL_BGR, GL_UNSIGNED_BYTE, data); } ACCESSING THE IMAGES • Normally, you specify the image index from the client side GLuint loc = glGetUniform (progID, “image_num”); glUniform1f (loc, counter); // some int • Then, in the vertex shader, use it as the 3 rd texture coordinate: uniform float image_num; in vec4 vTexCoords; smooth out vec3 imageTexCoords; void main (void) { imageTexCoords.st = vTexCoords.st; imageTexCoords.p = image_num; … } YOUR FRAGMENT SHADER • Must have a sampler2DArray variable • Must use the texture2DArray function uniform sampler2DArray texture; smooth in vec3 imageTexCoords; out vFragColor; void main () { vFragColor = texture2DArray (texture, imageTexCoods.stp); }