OpenGL学习笔记三(旋转带纹理的花托,球体,地板,点光源)

#include <GLTools.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <StopWatch.h>

#define FREEGLUT_STATIC
#include <GL/glut.h>

#define SPHERE_NUM 30

GLFrame cameraFrame;
GLMatrixStack modelViewStack;
GLMatrixStack projectionStack;
GLGeometryTransform transformPipeLine;
GLShaderManager shaderManager;
GLFrustum viewFrustum;
GLFrame spheres[SPHERE_NUM];

GLBatch batch_floor;
GLTriangleBatch batch_torus;
GLTriangleBatch batch_sphere;

GLfloat vWhite[] = {1.0f, 1.0f, 1.0f, 0.75f};
const char *texFileName[] = {"Marble.tga", "Marslike.tga", "MoonLike.tga"};
GLuint texIdArray[3] = {0};

//加载纹理并设置相关参数
bool LoadTgaTexture(const char *fileName, GLenum filterParam, GLenum wrapParam)
{
	GLbyte *pbits = NULL;
	GLint width, height, components;
	GLenum eFormat;
	//从tga文件获取纹理图像的地址和相关参数
	pbits = gltReadTGABits(fileName, &width, &height, &components, &eFormat);
	if (NULL == pbits)
	{
		return false;
	}
	//设置缩放算法
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filterParam);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterParam);
	//设置纹理边界外的填充方法
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapParam);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapParam);
	//根据获取的相关参数创建2D纹理
	glTexImage2D(GL_TEXTURE_2D, 0, components, width, height, 0, eFormat, GL_UNSIGNED_BYTE, pbits);
	free(pbits);
	return true;
}

bool SetupRC()
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	shaderManager.InitializeStockShaders();
	//开启深度测试
	glEnable(GL_DEPTH_TEST);
	//剔除背面渲染
	glEnable(GL_CULL_FACE);
	//生成3个纹理ID
	glGenTextures(3, texIdArray);

	glBindTexture(GL_TEXTURE_2D, texIdArray[0]);
	if (!LoadTgaTexture(texFileName[0], GL_LINEAR, GL_REPEAT))
	{
		return false;
	}
	glBindTexture(GL_TEXTURE_2D, texIdArray[1]);
	if (!LoadTgaTexture(texFileName[1], GL_LINEAR, GL_CLAMP_TO_EDGE))
	{
		return false;
	}
	glBindTexture(GL_TEXTURE_2D, texIdArray[2]);
	if (!LoadTgaTexture(texFileName[2], GL_LINEAR, GL_CLAMP_TO_EDGE))
	{
		return false;
	}
	//纹理坐标和顶点坐标的加载顺序不能反过来
	batch_floor.Begin(GL_TRIANGLE_FAN, 4, 1);
	batch_floor.MultiTexCoord2f(0, 0.0f, 0.0f);
	batch_floor.Vertex3f(-20.0f, -0.4f, 20.0f);

	batch_floor.MultiTexCoord2f(0, 10.0f, 0.0f);
	batch_floor.Vertex3f(20.0f, -0.4f, 20.0f);

	batch_floor.MultiTexCoord2f(0, 10.0f, 10.0f);
	batch_floor.Vertex3f(20.0f, -0.4f, -20.0f);
	
	batch_floor.MultiTexCoord2f(0, 0.0f, 10.0f);
	batch_floor.Vertex3f(-20.0f, -0.4f, -20.0f);
	batch_floor.End();

	//初始化花托的顶点批次
	gltMakeTorus(batch_torus, 0.4f, 0.15f, 40, 20);
	//初始化球体的顶点批次
	gltMakeSphere(batch_sphere, 0.1f, 26, 13);
	//初始化X-Z平面零散球体的坐标
	for (int n=0; n<SPHERE_NUM; n++)
	{
		GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
		GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
		spheres[n].SetOrigin(x, 0.0, z);
	}
	return true;
}

void DrawSongAndDance(GLfloat yRot)
{
	static GLfloat vLightPos[] = {0.0f, 3.0f, 0.0f, 1.0f};

	//绘制点光源,PushMatrix和PopMatrix要成对使用
	modelViewStack.PushMatrix();
	modelViewStack.Translatev(vLightPos);
	shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeLine.GetModelViewProjectionMatrix(), vWhite);
	batch_sphere.Draw();
	modelViewStack.PopMatrix();

	//绘制随机球体
	glBindTexture(GL_TEXTURE_2D, texIdArray[1]);
	for (int n=0; n<SPHERE_NUM; n++)
	{
		modelViewStack.PushMatrix();
		modelViewStack.MultMatrix(spheres[n]);
		modelViewStack.Rotate(3*yRot, 0.0f, 1.0f, 0.0f);
		shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, transformPipeLine.GetModelViewMatrix(),
			transformPipeLine.GetProjectionMatrix(), vLightPos, vWhite, 0);
		batch_sphere.Draw();
		modelViewStack.PopMatrix();
	}

	modelViewStack.PushMatrix();
	//在当前视点位置的前上方绘制花托和绕行球体,不然视点位置会看不到
	modelViewStack.Translate(0.0f, 0.2f, -3.5f);

	//绘制旋转花托
	modelViewStack.PushMatrix();
	modelViewStack.Rotate(yRot, 0.0f, 1.0f, 0.0f);
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, transformPipeLine.GetModelViewMatrix(),
		transformPipeLine.GetProjectionMatrix(), vLightPos, vWhite, 0);
	batch_torus.Draw();
	modelViewStack.PopMatrix();

	//绘制绕花托旋转的球体
	modelViewStack.PushMatrix();
	//以2倍反向速度旋转,注意旋转和平移的顺序不能反,不同顺序效果不一样
	modelViewStack.Rotate(-2*yRot, 0.0f, 1.0f, 0.0f);
	modelViewStack.Translate(0.8f, 0.0f, 0.0f);
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, transformPipeLine.GetModelViewMatrix(),
		transformPipeLine.GetProjectionMatrix(), vLightPos, vWhite, 0);
	batch_sphere.Draw();
	modelViewStack.PopMatrix();
	modelViewStack.PopMatrix();
}

void RenderScene()
{
	static CStopWatch rotTimer;
	//1秒钟转60度角的速度
	float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	modelViewStack.PushMatrix();
	//乘视图矩阵
	M3DMatrix44f mCamera;
	cameraFrame.GetCameraMatrix(mCamera);
	modelViewStack.MultMatrix(mCamera);

	//翻转、往下平移
	modelViewStack.PushMatrix();
	modelViewStack.Scale(1.0f, -1.0f, 1.0f);
	modelViewStack.Translate(0.0f, 0.8f, 0.0f);
	
	//绘制地板下的倒影,因为Y轴朝下了,所以背面剔除的方向应也要改变
	glFrontFace(GL_CW);
	DrawSongAndDance(yRot);
	//倒影绘制完成,恢复提出面方向
	glFrontFace(GL_CCW);
	modelViewStack.PopMatrix();

	//绘制地板
	//开启混合
	glEnable(GL_BLEND);
	//设置混合计算方程
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	//绑定地板纹理,绘制地板
	glBindTexture(GL_TEXTURE_2D, texIdArray[0]);
	static GLfloat vFloorColor[] = {1.0f, 1.0f, 1.0f, 0.75f};
	shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, 
		transformPipeLine.GetModelViewProjectionMatrix(), vFloorColor, 0);
	batch_floor.Draw();
	glDisable(GL_BLEND);

	//绘制地板上的球体、花托
	DrawSongAndDance(yRot);
	modelViewStack.PopMatrix();
	//将本次渲染的动画替换上一次渲染的动画
	glutSwapBuffers();
	//渲染后循环触发,保证动画连续
	glutPostRedisplay();
}

void SpecialKeys(int key, int x, int y)
{
	GLfloat delta = 0.1f;
	GLfloat angular = float(m3dDegToRad(5.0f));
	//设置方向键的前进后退和左右方向键的绕Y轴方向旋转
	switch(key)
	{
	case GLUT_KEY_UP:
		cameraFrame.MoveForward(delta);
		break;
	case GLUT_KEY_DOWN:
		cameraFrame.MoveForward(-delta);
		break;
	case GLUT_KEY_LEFT:
		cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
		break;
	case GLUT_KEY_RIGHT:
		cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
		break;
	default:
		break;
	}
}

void ChangeSize(int w, int h)
{
	glViewport(0, 0, w, h);
	//设置投影矩阵的视景体
	viewFrustum.SetPerspective(35.0f, float(w)/h, 1.0f, 100.0f);
	projectionStack.LoadMatrix(viewFrustum.GetProjectionMatrix());
	//模型视图矩阵设置单位矩阵
	modelViewStack.LoadIdentity();
	//将投影矩阵和模型视图矩阵设置到渲染管线对象
	transformPipeLine.SetMatrixStacks(modelViewStack, projectionStack);
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	//设置显示模式
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	//创建窗口
	glutInitWindowSize(800, 600);
	glutCreateWindow("show");
	//设置窗口尺寸回调函数
	glutReshapeFunc(ChangeSize);
	//设置特殊键回调函数
	glutSpecialFunc(SpecialKeys);
	//设置渲染回调函数
	glutDisplayFunc(RenderScene);

	GLenum ret = glewInit();
	if (GLEW_OK != ret)
	{
		fprintf(stderr, "glew error: %s", glewGetErrorString(ret));
		return 1;
	}
	//初始化函数
	if (!SetupRC())
	{
		return 1;
	}
	//接收一些外部事件,如键盘鼠标之类的,关闭窗口是退出
	glutMainLoop();
	//删除全局纹理对象
	glDeleteTextures(3, texIdArray);

	return 0;
}

匹配的纹理打包文件可以在此处下载https://download.csdn.net/download/gk_2014/10643475
这个示例基于《OpenGLchao超级宝典(第5版)》这本书

猜你喜欢

转载自blog.csdn.net/GK_2014/article/details/82353263