OpenGL学习笔记三(旋转带纹理的花托,球体,地板,点光源)
程序员文章站
2024-03-24 11:16:22
...
#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版)》这本书
上一篇: Flex页面翻转效果
下一篇: 摇杆是如何实现的