Multitexture

Notes:

Convert the last assignment to support multiple surface textures.

Reflection Vertex Shader:

// Reflection Shader
// Vertex Shader
#version 330 core

// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;
in vec2 vTexCoords;

uniform mat4   mvpMatrix;
uniform mat4   mvMatrix;
uniform mat3   normalMatrix;
uniform mat4   mInverseCamera;

// Texture coordinate to fragment program
smooth out vec3 vVaryingTexCoord;
smooth out vec2 vTarnishCoords;

void main(void) 
{
    // Normal in Eye Space
    vec3 vEyeNormal = normalMatrix * vNormal;
    
    // Vertex position in Eye Space
    vec4 vVert4 = mvMatrix * vVertex;
    vec3 vEyeVertex = normalize(vVert4.xyz / vVert4.w);
    
    // Get reflected vector
    vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), 1.0);
   
    // Rotate by flipped camera
    vCoords = mInverseCamera * vCoords;
    vVaryingTexCoord.xyz = normalize(vCoords.xyz);

    vTarnishCoords = vTexCoords.st;

    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
}

Reflection Fragment Shader:

// Reflection Shader
// Fragment Shader
#version 330 core

out vec4 vFragColor;

uniform samplerCube cubeMap;
uniform sampler2D   tarnishMap;

smooth in vec3 vVaryingTexCoord;
smooth in vec2 vTarnishCoords;

void main(void)
{ 
    vFragColor = texture(cubeMap, vVaryingTexCoord.stp);
    vFragColor *= texture(tarnishMap, vTarnishCoords);
}

Sky Box Vertex Shader:

// Skybox Shader
// Vertex Shader
#version 330 core

// Incoming per vertex... just the position
in vec4 vVertex;

uniform mat4   mvpMatrix;  // Transformation matrix

// Texture Coordinate to fragment program
varying vec3 vVaryingTexCoord;

void main(void) 
{
    // Pass on the texture coordinates 
    vVaryingTexCoord = normalize(vVertex.xyz);

    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
}

Sky Box Fragment Shader:

// Skybox Shader
// Fragment Shader
#version 330 core

out vec4 vFragColor;

uniform samplerCube  cubeMap;

varying vec3 vVaryingTexCoord;

void main(void)
{ 
    vFragColor = texture(cubeMap, vVaryingTexCoord);
}
    

Source:

// MultiTexture.cpp
// Use multiple textures on one surface.

#include <GLTools.h>	// OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdlib.h>

#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <GL/glu.h>

GLFrame             viewFrame;
GLFrustum           viewFrustum;
GLTriangleBatch     sphereBatch;
GLBatch             cubeBatch;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transformPipeline;
GLuint              cubeTexture;
GLuint              tarnishTexture;
GLint               reflectionShader;
GLint               skyBoxShader;

GLint               locMVPReflect, locMVReflect, locNormalReflect, locInvertedCamera;
GLint               locCubeMap, locTarnishMap;
GLint	            locMVPSkyBox;


//Screen dimension constants
//const int SCREEN_WIDTH = 256;
//const int SCREEN_HEIGHT = 256;
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

// Six sides of a cube map
const char *szCubeFaces[6] = { "pos_x.tga", "neg_x.tga", "pos_y.tga", "neg_y.tga", "pos_z.tga", "neg_z.tga" };

GLenum  cube[6] = {  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_Z };

// This function does any needed initialization on the rendering
// context. 
bool SetupRC()
{
    bool success = true;

    // test for GL support for more than one texture unit, quit if not more than one supported
    GLint iUnits = 0;
    glGetIntegerv(GL_MAX_TEXTURE_UNITS, &iUnits);
    if (iUnits < 1)
    {
        printf("Your computer does not support enough texture units!\n");
        success = false;
        return success;
    }
    else
    {
        printf("Your computer supports %i texture units.\n", iUnits);
    }

    GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    int i;
       
    // Cull backs of polygons
    glCullFace(GL_BACK);
    glFrontFace(GL_CCW);
    glEnable(GL_DEPTH_TEST);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Load the tarnish texture
    glGenTextures(1, &tarnishTexture);
    glBindTexture(GL_TEXTURE_2D, tarnishTexture);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);

    pBytes = gltReadTGABits("tarnish.tga", &iWidth, &iHeight, &iComponents, &eFormat);
    glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
    free(pBytes);
    glGenerateMipmap(GL_TEXTURE_2D);
        
    // Load the cube texture
    glGenTextures(1, &cubeTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);

    // Set up texture maps        
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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);       
        
  
    // Load Cube Map images
    for(i = 0; i < 6; i++)
    {        
        // Load this texture map
        pBytes = gltReadTGABits(szCubeFaces[i], &iWidth, &iHeight, &iComponents, &eFormat);
        glTexImage2D(cube[i], 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        free(pBytes);
    }
    glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
    
    viewFrame.MoveForward(-4.0f);
    gltMakeSphere(sphereBatch, 1.0f, 52, 26);
    gltMakeCube(cubeBatch, 20.0f);
    
    reflectionShader = gltLoadShaderPairWithAttributes("Reflection.vp", "Reflection.fp", 3, 
                                                GLT_ATTRIBUTE_VERTEX, "vVertex",
                                                GLT_ATTRIBUTE_NORMAL, "vNormal",
                                                GLT_ATTRIBUTE_TEXTURE0, "vTexCoords");
                                                
    locMVPReflect = glGetUniformLocation(reflectionShader, "mvpMatrix");
    locMVReflect = glGetUniformLocation(reflectionShader, "mvMatrix");
    locNormalReflect = glGetUniformLocation(reflectionShader, "normalMatrix");
    locInvertedCamera = glGetUniformLocation(reflectionShader, "mInverseCamera");
    locCubeMap = glGetUniformLocation(reflectionShader, "cubeMap");
    locTarnishMap = glGetUniformLocation(reflectionShader, "tarnishMap");
                                                
    skyBoxShader = gltLoadShaderPairWithAttributes("SkyBox.vp", "SkyBox.fp", 2, 
                                                GLT_ATTRIBUTE_VERTEX, "vVertex",
                                                GLT_ATTRIBUTE_NORMAL, "vNormal");

    locMVPSkyBox = glGetUniformLocation(skyBoxShader, "mvpMatrix");

    // Set texture to their texture units
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, tarnishTexture);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);
    
    viewFrustum.SetPerspective(70.0f, float(SCREEN_WIDTH)/float(SCREEN_HEIGHT), 1.0f, 1000.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    return success;
}

// Called to draw scene
void RenderScene(void)
{
    // Clear the window
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
    M3DMatrix44f mCamera;
    M3DMatrix44f mCameraRotOnly;
    M3DMatrix44f mInverseCamera;
    
    viewFrame.GetCameraMatrix(mCamera, false);
    viewFrame.GetCameraMatrix(mCameraRotOnly, true);
    m3dInvertMatrix44(mInverseCamera, mCameraRotOnly);

    modelViewMatrix.PushMatrix();    
        // Draw the sphere
        modelViewMatrix.MultMatrix(mCamera);
        glUseProgram(reflectionShader);
        glUniformMatrix4fv(locMVPReflect,       1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
        glUniformMatrix4fv(locMVReflect,        1, GL_FALSE, transformPipeline.GetModelViewMatrix());
        glUniformMatrix3fv(locNormalReflect,    1, GL_FALSE, transformPipeline.GetNormalMatrix());
	glUniformMatrix4fv(locInvertedCamera,   1, GL_FALSE, mInverseCamera);
        glUniform1i(locCubeMap, 0);
        glUniform1i(locTarnishMap, 1);

	glEnable(GL_CULL_FACE);
        sphereBatch.Draw();
	glDisable(GL_CULL_FACE);
    modelViewMatrix.PopMatrix();

    modelViewMatrix.PushMatrix();
        glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
	modelViewMatrix.MultMatrix(mCameraRotOnly);
	glUseProgram(skyBoxShader);
	glUniformMatrix4fv(locMVPSkyBox, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
	cubeBatch.Draw();       
        glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
    modelViewMatrix.PopMatrix();
}

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//OpenGL context
SDL_GLContext gContext;

bool init()
{
    bool success = true;

	//Initialize SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
		success = false;
	}
	else
	{
		//Use OpenGL 3.3 core
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

		//Create window
		gWindow = SDL_CreateWindow("Multi Texture", 
                                    SDL_WINDOWPOS_UNDEFINED, 
                                    SDL_WINDOWPOS_UNDEFINED, 
                                    SCREEN_WIDTH, 
                                    SCREEN_HEIGHT, 
                                    SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
		if(gWindow == NULL)
		{
			printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
			success = false;
		}
		else
		{
			//Create context
			gContext = SDL_GL_CreateContext(gWindow);
			if(gContext == NULL)
			{
				printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
				success = false;
			}
			else
			{
				//Initialize GLEW
				glewExperimental = GL_TRUE; 
				GLenum glewError = glewInit();
				if(glewError != GLEW_OK)
				{
					printf("Error initializing GLEW! %s\n", glewGetErrorString(glewError));
				}

				//Use Vsync
				if(SDL_GL_SetSwapInterval(1) < 0)
				{
					printf("Warning: Unable to set VSync! SDL Error: %s\n", SDL_GetError());
				}

				//Initialize OpenGL
				if(!SetupRC())
				{
					printf("Unable to initialize OpenGL!\n");
					success = false;
				}
                // Capture mouse
                SDL_CaptureMouse(SDL_TRUE);
                SDL_ShowCursor(0); 
                SDL_SetRelativeMouseMode(SDL_TRUE);;
			}
		}
	}
    return success;
}

void ShutdownRC(void)
{
    glDeleteTextures(1, &cubeTexture);
    glDeleteTextures(1, &tarnishTexture);

    glDeleteProgram(reflectionShader);
    glDeleteProgram(skyBoxShader);

    // Destroy Window
    SDL_DestroyWindow(gWindow);
    gWindow = NULL;

    SDL_Quit();
}

int main(int argc, char* argv[])
{
	//Start up SDL and create window
	if(!init())
	{
		printf("Failed to initialize!\n");
	}
	else
	{
	//Main loop flag
	bool quit = false;

        // Time variables
        unsigned int lastTime = 0, currentTime = 0;

	//Event handler
	SDL_Event e;
	
	//Enable text input
	SDL_StartTextInput();

        // Mouse x and y
        float mouseX;
        float mouseY;

		//While application is running
		while (!quit)
		{
			//Handle events on queue
			while (SDL_PollEvent(&e) != 0)
			{
				switch( e.type )
				{
				    /* Look for a keypress */
				    case SDL_KEYDOWN:
					/* Check the SDLKey values and move change the coords */
					switch( e.key.keysym.sym )
					{
					    case SDLK_LEFT:
						viewFrame.RotateLocalY( 0.1);
						break;
					    case SDLK_RIGHT:
						viewFrame.RotateLocalY(-0.1);
						break;
					    case SDLK_UP:
						viewFrame.MoveForward( 0.1);
						break;
					    case SDLK_DOWN:
						viewFrame.MoveForward(-0.1);
						break;
					    case SDLK_q:
						quit = true;
					    default:
						break;
					}
					break;
				    case SDL_MOUSEMOTION:
					mouseX = e.motion.xrel * -0.001;
					mouseY = e.motion.yrel * 0.001;
					//printf("mouseX: %f\n", mouseX);
					//printf("mouseY: %f\n", mouseY);
					// This has to be inverted for SDL2
					viewFrame.RotateLocalX(mouseY);
					viewFrame.RotateLocalY(mouseX);
					break;
				    default:
					break;
				}
				//User requests quit
				if (e.type == SDL_QUIT)
				{
					quit = true;
				}
			}
			//Render
			RenderScene();
			
			//Update screen
			SDL_GL_SwapWindow(gWindow);
		}
		//Disable text input
		SDL_StopTextInput();
	}

	//Free resources and close SDL
	ShutdownRC();
        
	return 0;
}

Answer:


Back to index