OpenGL蓝宝书源码学习(二十一)第七章——SphereWorld矩阵纹理

将OpenGL图标的纹理贴图,通过矩形纹理的方式加载,渲染到小球的图形上。

// SphereWorld.cpp
// OpenGL SuperBible
// New and improved sphere world, this time with a texture rect
// Program by Richard S. Wright Jr.

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 

#ifdef __APPLE__
#include 
#else
#define FREEGLUT_STATIC
#include 
#endif

#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

GLShaderManager		shaderManager;			// Shader Manager
GLMatrixStack		modelViewMatrix;		// Modelview Matrix
GLMatrixStack		projectionMatrix;		// Projection Matrix
GLFrustum			viewFrustum;			// View Frustum
GLGeometryTransform	transformPipeline;		// Geometry Transform Pipeline
GLFrame				cameraFrame;			// Camera frame

GLTriangleBatch		torusBatch;
GLTriangleBatch		sphereBatch;
GLBatch				floorBatch;
GLBatch				logoBatch;

GLuint				uiTextures[4];
GLint				rectReplaceShader;
GLint				locRectMVP;
GLint				locRectTexture;


void DrawSongAndDance(GLfloat yRot)		// Called to draw dancing objects
	{
	static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
	
	// Get the light position in eye space
	M3DVector4f	vLightTransformed;
	M3DMatrix44f mCamera;
	modelViewMatrix.GetMatrix(mCamera);
	m3dTransformVector4(vLightTransformed, vLightPos, mCamera);
	
	// Draw the light source
	modelViewMatrix.PushMatrix();
	modelViewMatrix.Translatev(vLightPos);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, 
								 transformPipeline.GetModelViewProjectionMatrix(),
								 vWhite);
	sphereBatch.Draw();
	modelViewMatrix.PopMatrix();
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    for(int i = 0; i < NUM_SPHERES; i++) {
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[i]);
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                     modelViewMatrix.GetMatrix(),
                                     transformPipeline.GetProjectionMatrix(),
                                     vLightTransformed, 
                                     vWhite,
                                     0);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }
	
	// Song and dance
	modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
	modelViewMatrix.PushMatrix();	// Saves the translated origin
	modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
	
	// Draw stuff relative to the camera
	glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
								 modelViewMatrix.GetMatrix(),
								 transformPipeline.GetProjectionMatrix(),
								 vLightTransformed, 
								 vWhite,
								 0);
	torusBatch.Draw();
	modelViewMatrix.PopMatrix(); // Erased the rotate
	
	modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
	modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
	
	glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
								 modelViewMatrix.GetMatrix(),
								 transformPipeline.GetProjectionMatrix(),
								 vLightTransformed, 
								 vWhite,
								 0);
	sphereBatch.Draw();
	}
	
	
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
	{
	GLbyte *pBits;
	int nWidth, nHeight, nComponents;
	GLenum eFormat;
	
	// Read the texture bits
	pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
	if(pBits == NULL) 
		return false;
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
		
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,
				 eFormat, GL_UNSIGNED_BYTE, pBits);
	
    free(pBits);

    if(minFilter == GL_LINEAR_MIPMAP_LINEAR || 
       minFilter == GL_LINEAR_MIPMAP_NEAREST ||
       minFilter == GL_NEAREST_MIPMAP_LINEAR ||
       minFilter == GL_NEAREST_MIPMAP_NEAREST)
        glGenerateMipmap(GL_TEXTURE_2D);
            
	return true;
	}


bool LoadTGATextureRect(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
	{
	GLbyte *pBits;
	int nWidth, nHeight, nComponents;
	GLenum eFormat;
	
	// Read the texture bits
	pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
	if(pBits == NULL) 
		return false;
	
	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, wrapMode);
	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, wrapMode);
	
	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, minFilter);
	glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, magFilter);
		
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexImage2D(GL_TEXTURE_RECTANGLE, 0, nComponents, nWidth, nHeight, 0,
				 eFormat, GL_UNSIGNED_BYTE, pBits);
	
    free(pBits);

	return true;
	}

//////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering
// context. 
void SetupRC()
    {
	// Make sure OpenGL entry points are set
	glewInit();
	
	// Initialze Shader Manager
	shaderManager.InitializeStockShaders();
	
	glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
	
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	
	// This makes a torus
	gltMakeTorus(torusBatch, 0.4f, 0.15f, 40, 20);
	
	// This makes a sphere
	gltMakeSphere(sphereBatch, 0.1f, 26, 13);
	
	
	// Make the solid ground
	GLfloat texSize = 10.0f;
	floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
	floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f);
	
	floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
    floorBatch.Vertex3f(20.0f, -0.41f, 20.0f);
	
	floorBatch.MultiTexCoord2f(0, texSize, texSize);
	floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
	
	floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
	floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
	floorBatch.End();
	

	int x = 500;
	int y = 155;
	int width = 300;
	int height = 155;
	logoBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
	
        // Upper left hand corner
        logoBatch.MultiTexCoord2f(0, 0.0f, height);
        logoBatch.Vertex3f(x, y, 0.0);
        
        // Lower left hand corner
        logoBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        logoBatch.Vertex3f(x, y - height, 0.0f);

        // Lower right hand corner
        logoBatch.MultiTexCoord2f(0, width, 0.0f);
        logoBatch.Vertex3f(x + width, y - height, 0.0f);

        // Upper righ hand corner
        logoBatch.MultiTexCoord2f(0, width, height);
        logoBatch.Vertex3f(x + width, y, 0.0f);

	logoBatch.End();

	// Make 4 texture objects
	glGenTextures(4, uiTextures);
	
	// Load the Marble
	glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
	LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
	
	// Load Mars
	glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
	LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, 
				   GL_LINEAR, GL_CLAMP_TO_EDGE);
	
	// Load Moon
	glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
	LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
				   GL_LINEAR, GL_CLAMP_TO_EDGE);

	// Load the Logo
	glBindTexture(GL_TEXTURE_RECTANGLE, uiTextures[3]);
	LoadTGATextureRect("OpenGL-Logo.tga", GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);

    rectReplaceShader = gltLoadShaderPairWithAttributes("RectReplace.vp", "RectReplace.fp", 
			2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
                 

	locRectMVP = glGetUniformLocation(rectReplaceShader, "mvpMatrix");
	locRectTexture = glGetUniformLocation(rectReplaceShader, "rectangleImage");


    // Randomly place the spheres
    for(int i = 0; i < NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x, 0.0f, z);
        }
    }

////////////////////////////////////////////////////////////////////////
// Do shutdown for the rendering context
void ShutdownRC(void)
    {
    glDeleteTextures(3, uiTextures);
    }



        
// Called to draw scene
void RenderScene(void)
	{
	static CStopWatch	rotTimer;
	float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	modelViewMatrix.PushMatrix();	
	M3DMatrix44f mCamera;
	cameraFrame.GetCameraMatrix(mCamera);
	modelViewMatrix.MultMatrix(mCamera);
	
	// Draw the world upside down
	modelViewMatrix.PushMatrix();
	modelViewMatrix.Scale(1.0f, -1.0f, 1.0f); // Flips the Y Axis
	modelViewMatrix.Translate(0.0f, 0.8f, 0.0f); // Scootch the world down a bit...
	glFrontFace(GL_CW);
	DrawSongAndDance(yRot);
	glFrontFace(GL_CCW);
	modelViewMatrix.PopMatrix();
	
	// Draw the solid ground
	glEnable(GL_BLEND);
	glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	static GLfloat vFloorColor[] = { 1.0f, 1.0f, 1.0f, 0.75f};
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
								 transformPipeline.GetModelViewProjectionMatrix(),
								 vFloorColor,
								 0);
	
	floorBatch.Draw();
	glDisable(GL_BLEND);
	
	
	DrawSongAndDance(yRot);
	
	modelViewMatrix.PopMatrix();

	// Render the overlay
    
    // Creating this matrix really doesn't need to be done every frame. I'll leave it here
    // so all the pertenant code is together
    M3DMatrix44f mScreenSpace;
    m3dMakeOrthographicMatrix(mScreenSpace, 0.0f, 800.0f, 0.0f, 600.0f, -1.0f, 1.0f);
        
    // Turn blending on, and depth testing off
	glEnable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);

	glUseProgram(rectReplaceShader);
	glUniform1i(locRectTexture, 0);
	glUniformMatrix4fv(locRectMVP, 1, GL_FALSE, mScreenSpace);
	glBindTexture(GL_TEXTURE_RECTANGLE, uiTextures[3]);
	logoBatch.Draw();

    // Restore no blending and depth test
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
        
    // Do the buffer Swap
    glutSwapBuffers();
        
    // Do it again
    glutPostRedisplay();
    }



// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
    {
	float linear = 0.1f;
	float angular = float(m3dDegToRad(5.0f));
	
	if(key == GLUT_KEY_UP)
		cameraFrame.MoveForward(linear);
	
	if(key == GLUT_KEY_DOWN)
		cameraFrame.MoveForward(-linear);
	
	if(key == GLUT_KEY_LEFT)
		cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
	
	if(key == GLUT_KEY_RIGHT)
		cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);	
    }


void ChangeSize(int nWidth, int nHeight)
    {
	glViewport(0, 0, nWidth, nHeight);
	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
	
	viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
	projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
	modelViewMatrix.LoadIdentity();
	}

int main(int argc, char* argv[])
    {
	gltSetWorkingDirectory(argv[0]);
		
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800,600);
  
    glutCreateWindow("OpenGL SphereWorld with Texture Rectangle");
 
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);

    SetupRC();
    glutMainLoop();    
    ShutdownRC();
    return 0;
    }
// Rectangle Texture (replace) Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 140

// Incoming per vertex... position and texture coordinate
in vec4 vVertex;
in vec2 vTexCoord;

uniform mat4   mvpMatrix;

// Texture Coordinate to fragment program
smooth out vec2 vVaryingTexCoord;


void main(void) 
    {
    // Pass on the texture coordinates 
    vVaryingTexCoord = vTexCoord;
    
    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
    }
// Rectangle Texture (replace) Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 140

out vec4 vFragColor;

uniform sampler2DRect  rectangleImage;

smooth in vec2 vVaryingTexCoord;

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



一、矩形纹理基础

纹理目标GL_TEXTURE_RECTANGLE。这个纹理目标模式的工作方式和GL_TEXTURE_2D非常相似,但又几点不同。首先,它们不能进行Mip贴图,意味着只能加载glTextImage2D的第0层;第二,纹理坐标不是标准化,意味着纹理坐标实际上对像素寻址,而不是从0.0到1.0的范围覆盖图像的。

此外,纹理坐标不能重复,并且不支持纹理压缩。

相对于使用纹理来获得3D模型表面特征,这种方式对于许多OpenGL用来处理和提交图像数据的应用程序来说更加方便,对于纹理矩形的硬件支持也比对通常的2D纹理贴图更加简单,并且更快、效率更高。

二、Client源码解析

SphereWorld.cpp

1、全局变量

//声明随机的小球角色,允许使用GLFrame类型的对象来代替一个完整的矩阵

#define NUM_SPHERES 50

GLFrame spheres[NUM_SPHERES];  


GLShaderManager shaderManager; // 着色器管理器
GLMatrixStack modelViewMatrix;// 模型视图矩阵堆栈
GLMatrixStack projectionMatrix;// 投影矩阵堆栈
GLFrustum viewFrustum;// 视锥体
GLGeometryTransform transformPipeline;// 管线管理
GLFrame cameraFrame;// 照相机角色


GLTriangleBatch torusBatch; //花托图元批次
GLTriangleBatch sphereBatch;    //球体图元批次
GLBatch floorBatch;  //地面图元批次
GLBatch logoBatch;  //Logo图元批次


GLuint uiTextures[4];   //纹理标识数组(4个)
GLint rectReplaceShader; //着色器标识
GLint locRectMVP;  //返回着色器的模型视图投影矩阵
GLint locRectTexture; //返回着色器的纹理单元对象

2、函数解析

1)void SetupRC()

{

glewInit();//初始化glew,确保可以使用OpenGL的API

shaderManager.InitializeStockShaders();//初始化着色器管理器

glEnable(GL_DEPTH_TEST);//开启深度测试

glEnable(GL_CULL_FACE); //开启表示禁用多边形正面或者背面上的光照、阴影和颜色计算及操作,消除不必要的渲染计算。

glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //设置清除窗口的清除颜色,即设置窗口的背景颜色


gltMakeTorus(torusBatch, 0.4f, 0.15f, 40, 20);//绘制一个花托图形

gltMakeSphere(sphereBatch, 0.1f, 26, 13);//绘制一个球形

//绘制构造一个“地面”的图形

GLfloat texSize = 10.0f;

floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);//开始绘制,使用三角形扇,4个顶点和1个纹理单元创建“地面”

//类似立即模式创建图元批次

floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);  //设置纹理坐标。参数1:纹理单元标识;参数2和3:纹理坐标s和t
floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f); //设置顶点坐标。参数:x、y和z坐标

floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
 
      floorBatch.Vertex3f(20.0f, -0.41f, 20.0f);

floorBatch.MultiTexCoord2f(0, texSize, texSize);
floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);

floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
floorBatch.End();                  //完成“地面”图形的绘制

//设置Logo位置坐标的局部参考变量

int x = 500;   
int y = 155;
int width = 300;
int height = 155;
logoBatch.Begin(GL_TRIANGLE_FAN, 4, 1);      //开始绘制“Logo”图元。使用三角形扇形,4个顶点和1个纹理单元

        // 左上角的纹理坐标和顶点坐标的设置。
        logoBatch.MultiTexCoord2f(0, 0.0f, height);
        logoBatch.Vertex3f(x, y, 0.0);

        // 左下角的纹理坐标和顶点坐标的设置
        logoBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        logoBatch.Vertex3f(x, y - height, 0.0f);

       // 右下角的纹理坐标和顶点坐标的设置
        logoBatch.MultiTexCoord2f(0, width, 0.0f);
        logoBatch.Vertex3f(x + width, y - height, 0.0f);

        // 右上角的纹理坐标和顶点坐标的设置
        logoBatch.MultiTexCoord2f(0, width, height);
        logoBatch.Vertex3f(x + width, y, 0.0f);

注意纹理坐标的恰好与图元的坐标一一映射

logoBatch.End(); //完成“Logo”图元的绘制

glGenTextures(4, uiTextures); //生成纹理,4个纹理对象即纹理对象标识符数组(4个元素)

//绑定纹理对象,加载纹理贴图并设置收缩和拉伸的过滤模式及环绕模式

glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);

glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR, 
  GL_LINEAR, GL_CLAMP_TO_EDGE);

glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
  GL_LINEAR, GL_CLAMP_TO_EDGE);

glBindTexture(GL_TEXTURE_RECTANGLE, uiTextures[3]);
LoadTGATextureRect("OpenGL-Logo.tga", GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);

//载入着色器。参数1和2:着色器程序文件;参数3:顶点着色器中输入属性的个数;

后面参数:顶点着色器输入属性的类型,即顶点和纹理坐标。

rectReplaceShader = gltLoadShaderPairWithAttributes("RectReplace.vp", "RectReplace.fp", 
2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");

//获取着色器中的模型视图投影矩阵统一值

locRectMVP = glGetUniformLocation(rectReplaceShader, "mvpMatrix");

//获取着色器中的纹理单元统一值

locRectTexture = glGetUniformLocation(rectReplaceShader, "rectangleImage");

//随机绘制小球图元。即直接设置角色的位置坐标

    for(int i = 0; i < NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x, 0.0f, z);
        }

}

2)void ShutdownRC(void)

//删除纹理纹理对象,对应SetupRC中生成的4个纹理对象

    {
    glDeleteTextures(3, uiTextures);
    }

3)void RenderScene(void)

{

 //定义一个时间的对象

static CStopWatchrotTimer; 

//定义沿y轴随时间旋转的参数
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

//清空颜色和深度缓冲区

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  

//默认向模型视图矩阵中放入单位矩阵

modelViewMatrix.PushMatrix();

//声明一个4x4的浮点类型的矩阵
M3DMatrix44f mCamera;        
 

//通过照相机角色的得到照相机矩阵
cameraFrame.GetCameraMatrix(mCamera); 

//把栈顶的矩阵与照相机矩阵相乘
modelViewMatrix.MultMatrix(mCamera);

//把上面得到的矩阵压栈到模型视图矩阵堆栈中

modelViewMatrix.PushMatrix(); 

// 创建一个缩放矩阵矩阵再乘以矩阵堆栈顶部的矩阵(即沿y轴缩放变换,-1.0f也可以看成是翻转了180度)
modelViewMatrix.Scale(1.0f, -1.0f, 1.0f); 

// 创建一个旋转矩阵再乘以矩阵堆栈顶部的矩阵(即沿y轴向上平移0.8f像素变换)
modelViewMatrix.Translate(0.0f, 0.8f, 0.0f); 

//顶点顺序为为顺时针方向的表面时正面(因为使用了剔除面片)
glFrontFace(GL_CW);

//渲染绘制花托和小球,即可以看作是倒映在地面上的图形
DrawSongAndDance(yRot);

//窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面
glFrontFace(GL_CCW); 

//把模型视图矩阵堆栈顶部矩阵出栈
modelViewMatrix.PopMatrix();

//开启颜色混合模式

glEnable(GL_BLEND);         

//绑定第一个纹理对象
glBindTexture(GL_TEXTURE_2D, uiTextures[0]); 

//设置颜色混合的方式
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

//定义一个颜色值
static GLfloat vFloorColor[] = { 1.0f, 1.0f, 1.0f, 0.75f}; 

//使用纹理调整着色器渲染图元
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
transformPipeline.GetModelViewProjectionMatrix(),
vFloorColor,
0);

//提交“地面”图元进行渲染绘制,由于开启了颜色混合,倒映的的图形和“地面”会混合

floorBatch.Draw();

//关闭颜色混合模式

glDisable(GL_BLEND);

//渲染绘制花托和球体

DrawSongAndDance(yRot);

//模型视图矩阵堆栈栈顶矩阵出栈(单位矩阵出栈)

modelViewMatrix.PopMatrix();

//声明一个4x4的浮点类型矩阵

 M3DMatrix44f mScreenSpace;

//设置正投影,分别设置3个轴的范围

 m3dMakeOrthographicMatrix(mScreenSpace, 0.0f, 800.0f, 0.0f, 600.0f, -1.0f, 1.0f);

//开启颜色混合模式

glEnable(GL_BLEND); 

//关闭深度测试模式
glDisable(GL_DEPTH_TEST);

//使用着色器程序

glUseProgram(rectReplaceShader); 

 //设置着色器程序中的纹理单元统一值,默认是0的纹理单元
glUniform1i(locRectTexture, 0);

//设置着色器中统一矩阵,即用mScreenSpace矩阵设置着色器中的模型视图投影矩阵,1代表矩阵的数量
glUniformMatrix4fv(locRectMVP, 1, GL_FALSE, mScreenSpace);

//绑定第4个纹理对象,即“OpenGLLogo”的纹理贴图
glBindTexture(GL_TEXTURE_RECTANGLE, uiTextures[3]);

//提交图元进行渲染绘制
logoBatch.Draw();  

//关闭颜色很合模式

glDisable(GL_BLEND); 

//开启深度测试模式

glEnable(GL_DEPTH_TEST);

//交换缓冲区

glutSwapBuffers();

//重新进行窗口显示

glutPostRedisplay();

}

4)void ChangeSize(int nWidth, int nHeight)

//根据窗口的宽高大小设置视口的大小

glViewport(0, 0, nWidth, nHeight);

//设置进行管线管理的矩阵堆栈(模型视图和投影矩阵堆栈)

transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

//设置透视投影

viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);

//投影矩阵堆栈加载从视锥体得到的投影矩阵

projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

//模型视图矩阵堆栈加载单位矩阵

modelViewMatrix.LoadIdentity(); 

5)void DrawSongAndDance(GLfloat yRot)

{

 //定义颜色向量

static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };

//定义光源位置坐标
static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };

//声明一个视坐标系中的光源

M3DVector4fvLightTransformed;

//声明一个照相机角色
M3DMatrix44f mCamera; 

//从模型视图矩阵中得到照相机矩阵
modelViewMatrix.GetMatrix(mCamera); 

//将固定的光源位置变换到视觉坐标系中

m3dTransformVector4(vLightTransformed, vLightPos, mCamera);

//把光源位置压栈到模型视图矩阵堆栈中

modelViewMatrix.PushMatrix();  

//创建一个平移向量,再与模型视图矩阵堆栈的栈顶矩阵相乘
modelViewMatrix.Translatev(vLightPos);

//使用平面着色器渲染绘制图形,在这里加入了光线
shaderManager.UseStockShader(GLT_SHADER_FLAT, 
transformPipeline.GetModelViewProjectionMatrix(),
vWhite);

//提交图元进行渲染绘制
sphereBatch.Draw(); 
modelViewMatrix.PopMatrix();

//绑定第3个纹理对象,渲染绘制随机的小球图形

 glBindTexture(GL_TEXTURE_2D, uiTextures[2]); 
    for(int i = 0; i < NUM_SPHERES; i++) {
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[i]);
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                     modelViewMatrix.GetMatrix(),
                                     transformPipeline.GetProjectionMatrix(),
                                     vLightTransformed, 
                                     vWhite,
                                     0);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }

//创建一个平移矩阵与栈顶矩阵相乘,即对当前栈顶矩阵做平移变换

modelViewMatrix.Translate(0.0f, 0.2f, -2.5f); 

// 把得到矩阵压栈,存储得到的矩阵
modelViewMatrix.PushMatrix();

//创建一个旋转矩阵矩栈顶矩阵相乘,即对当前栈顶矩阵做旋转变换
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f); 

//绑定第2个纹理对象,使用点光源着色器渲染绘制“花托图形”

glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightTransformed, 
vWhite,
0);
torusBatch.Draw();

// 清除栈顶的矩阵(旋转矩阵)
modelViewMatrix.PopMatrix(); 

//创建一个旋转矩阵矩栈顶矩阵相乘,即对当前栈顶矩阵做旋转变换

modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);

//创建一个平移矩阵与栈顶矩阵相乘,即对当前栈顶矩阵做平移变换
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);

//绑定第3个纹理对象,使用纹理着色器渲染绘制“球形”

glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
modelViewMatrix.GetMatrix(),
transformPipeline.GetProjectionMatrix(),
vLightTransformed, 
vWhite,
0);
sphereBatch.Draw();

}

6)bool LoadTGATextureRect(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)

....

//包装的像素格式

glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 

//载入纹理,这里是矩形纹理(GL_TEXTURE_RECTANGLE)
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, nComponents, nWidth, nHeight, 0, 
eFormat, GL_UNSIGNED_BYTE, pBits);

注意:这个载入矩阵纹理数据的就是要渲染绘制OpenGLLogo的纹理对象的形式。

Client程序就解析到这里,有些没解析到的在之间的学习过程中已经了解学习到了。

三、Server程序源码解析

1、RectReplace.vp顶点程序

1)变量

in vec4 vVertex;      //顶点坐标
in vec2 vTexCoord; //纹理坐标

uniform mat4   mvpMatrix; //模型视图投影矩阵统一值

smooth out vec2 vVaryingTexCoord;//要输出到片段着色器的纹理坐标(2分量的向量)

2)函数

void main(void)

{
   
//赋值纹理坐标值
    vVaryingTexCoord = vTexCoord;
    
    //顶点的几何变换
    gl_Position = mvpMatrix * vVertex;
    }

2、RectReplace.fp片段程序

1)变量

out vec4 vFragColor;//要进行栅格化的颜色输出值

uniform sampler2DRect  rectangleImage;//2维的矩阵纹理采样器:将要进行采样的纹理所绑定的纹理单元

smooth in vec2 vVaryingTexCoord;//从顶点程序输出来的纹理坐标值

2)函数

void main(void)
    { 

//使用纹理坐标对纹理纹理单元进行采样得到的颜色值赋值给要输出的颜色值
    vFragColor = texture(rectangleImage, vVaryingTexCoord);
    }

四、小结

此示例几何了之前学习过的照相机跟随透视投影中三维图形的应用,在RenderScene渲染函数中,又重新使用了正投影的形式以及加载了纹理矩阵的方式载入了OpenGLLogo的纹理贴图,开启颜色混合模式,关闭深度测试模式,使用着色器并绑定对应的矩阵纹理对象,进行渲染绘制矩形纹理。而且在源码中学习到,设置右下角的Logo的顶点坐标和纹理坐标时准确一一对应起来的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值