OpenGL -正方形键位控制
2020-07-10 本文已影响0人
windy_3c22
结果图.gif
用到的函数及功能说明
-
main函数(int main(int argc, char * argv[])):程序入口(初始化、注册自定义函数)。
初始化:GLUT库,GLEW库,双缓存窗口,窗口大小,标题,
注册自定义函数:重塑函数,显示函数,特殊键位函数 -
setupRC函数(void setupRC(void)):⾃定义函数,设置你需要渲染的图形的相关顶点数据/颜⾊色数据等数据准备⼯作。
设置清屏颜色 ->初始化存储着色器->设置图元连接方式->用GLBatch将顶点数据传入顶点着色器 -
changeSize函数 (void changeSize(int w ,int h)):⾃定义函数。通过glutReshaperFunc(函数名)注册为重塑函数。屏幕⼤⼩发⽣变化/或者第⼀次创建窗⼝时会调用该函数调整窗⼝⼤小/视⼝⼤⼩
-
RenderScene函数(void RenderScene(void)):⾃定义函数。通过glutDisplayFunc(函数名)注册为显示渲染函数.当屏幕发⽣变化/或者开发者主动渲染会调⽤此函数,用来实现数据->渲染过程
-
SpecialKey函数():自定义函数,键盘(上下左右)处理,并触发重绘。
绘制正方形
定义需要的数据及工具类
/*定义着色器*/
GLShaderManager shaderManager;
/*批次容器,GLTool的一个简单的容器类*/
GLBatch triangleBatch;
/*blockSize 边长为blockSize*2*/
GLfloat blockSize = 0.1f;
/*正方形的4个顶点坐标*/
GLfloat vVerts[] = {
-blockSize,-blockSize,0.0f,
blockSize,-blockSize,0.0f,
blockSize,blockSize,0.0f,
-blockSize,blockSize,0.0f
};
重绘函数
/**
* 屏幕尺寸改变时接收新的宽高 w,h表示像素
*/
void ChangeSize(int w,int h){
glViewport(0, 0, w, h);
};
渲染函数
/**
* 渲染
*/
void RenderScene(void){
// 1. 清除一个或一组特定的缓存区
/**
* 缓冲区是一块存在图像信息的存储空间,R G B Alpha分量通常一起分量,通常一起作为颜色缓存区或像素缓存区引用。
* OpenGL中不止一种缓冲区(颜色缓存区,深度缓存区,模版缓存区)
* 清除缓存区对数值进行预置
* 参数 :
* 指定将要清除的缓存
* GL_COLOR_BUFFER_BIT :指示当前激活的用来进行颜色写入的缓存区。
* GL_DEPTH_BUFFER_BIT :指示深度缓存区
* GL_STENCIL_BUFFER_BIT :指示模板缓存区
*/
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
/*设置一组浮点数来表示红色*/
GLfloat red[]={1.0f,0.0f,0.0f,1.0f};
/**
*传递到着色器 ,GLT_SHADER_IDENTITYGL着色器。
*这个着色器只是使用指定颜色以默认的迪卡尔坐标在屏幕上渲染几何图形
*/
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,red);
/*提交着色器*/
triangleBatch.Draw();
/**
*在开始设置OpenGL窗口的时候,我们指定要一个双缓冲区的渲染环境。这就意味着将在后台缓冲区进行渲染。
*渲染结束后交换给前台。这个方式可以防止观察者看到可能伴随着动画帧和动画帧之间的闪烁的渲染过程。
*缓冲区交换平台将以平台特定的方式进行。
*/
/*将后台缓冲区进行渲染。结束后交换给前台*/
glutSwapBuffers();
}
setupRC函数
/**
*进行OpenCL窗口设置
*/
void setupRC(){
/*设置清屏颜色(背景颜色)*/
glClearColor(0.98f, 0.4f, 0.7f, 1);
/**
* 没有着色器,我们无法在OpenGL进行任何渲染。初始化一个颜色着色器。
* 先以固定管线来渲染。以后用OpenGL着色语言写着色器。
*/
shaderManager.InitializeStockShaders();
/*指定定点*/
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
main函数
int main(int argc,char *argv[]){
//设置当前工作目录,针对MAC OS X
/*`GLTools`函数`glSetWorkingDrectory`用来设置当前工作目录。
*实际上在Windows中是不必要的,因为工作目录默认就是与程序可执行执行程序相同的目录。
*但是在Mac OS X中,这个程序将当前工作文件夹改为应用程序捆绑包中的`/Resource`文件夹。
*`GLUT`的优先设定自动进行了这个中设置,但是这样中方法更加安全。 */
gltSetWorkingDirectory(argv[0]);
//初始化GLUT库,这个函数只是传说命令参数并且初始化glut库
glutInit(&argc, argv);
/*
初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
--GLUT_DOUBLE`:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果;
--GLUT_DEPTH`:标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试;
--GLUT_STENCIL`:确保我们也会有一个可用的模板缓存区。
深度、模板测试后面会细致讲到
*/
/*开启渲染模式*/
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//GLUT窗口大小、窗口标题
glutInitWindowSize(800, 600);
glutCreateWindow("Triangle");
/*
GLUT 内部运行一个本地消息循环,拦截适当的消息。然后调用我们不同时间注册的回调函数。我们一共注册2个回调函数:
1)为窗口改变大小而设置的一个回调函数
2)包含OpenGL 渲染的回调函数
*/
//注册重塑函数
glutReshapeFunc(ChangeSize);
//注册显示函数
glutDisplayFunc(RenderScene);
//注册特殊函数
glutSpecialFunc(SpecialKeys);
/*
初始化一个GLEW库,确保OpenGL API对程序完全可用。
在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题
*/
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error:%s\n",glewGetErrorString(status));
return 1;
}
//设置我们的渲染环境
setupRC();
glutMainLoop();
return 0;
}
至此我们的正方形绘制完成。
键位控制效果
坐标移动方式
正方形移动点坐标的变化及边界位置
坐标移动边界
void SpecialKeys(int key, int x, int y){
/*每次移动的距离*/
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0];
GLfloat blockY = vVerts[10];
if (key==GLUT_KEY_UP) {
blockY += stepSize;
}
if (key==GLUT_KEY_DOWN) {
blockY -= stepSize;
}
if (key==GLUT_KEY_LEFT) {
blockX -= stepSize;
}
if (key==GLUT_KEY_RIGHT) {
blockX += stepSize;
}
/*移动触碰到边界处理*/
/*左边届*/
if (blockX <= -1.0f) {
blockX = -1.0f;
}
/*右边界 1.0-正方形边长=左边点位置 */
if (blockX >= 1.0 - (blockSize * 2)) {
blockX = 1.0f - blockSize * 2;
}
/*上边界*/
if (blockY >= 1.0f) {
blockY = 1.0f;
}
//当正方形移动到最下面时
//-1.0 - blockSize * 2 = Y(负轴边界) - 正方形边长 = 最下面点的位置
if (blockY < -1.0f + blockSize * 2 ) {
blockY = -1.0f + blockSize * 2;
}
printf("blockX = %f\n",blockX);
printf("blockY = %f\n",blockY);
// Recalculate vertex positions
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize*2;
printf("(%f,%f)\n",vVerts[0],vVerts[1]);
vVerts[3] = blockX + blockSize*2;
vVerts[4] = blockY - blockSize*2;
printf("(%f,%f)\n",vVerts[3],vVerts[4]);
vVerts[6] = blockX + blockSize*2;
vVerts[7] = blockY;
printf("(%f,%f)\n",vVerts[6],vVerts[7]);
vVerts[9] = blockX;
vVerts[10] = blockY;
printf("(%f,%f)\n",vVerts[9],vVerts[10]);
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
矩阵方式
根据图形在x、y轴上移动的距离生成平移矩阵,通过图形矩阵*平移矩阵=移动后的图形。
矩阵平移边界
//渲染函数
void RenderScene(void){
// 1. 清除一个或一组特定的缓存区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
/*设置一组浮点数来表示红色*/
GLfloat vRed[]={1.0f,0.0f,0.0f,1.0f};
//************* 矩阵相乘***************//
M3DMatrix44f mFinalTransform,mTransfromMatrix,mRotationMartix;
//平移
m3dTranslationMatrix44(mTransfromMatrix, xPods, yPods, 0.0f);
// //每次平移时,旋转5度
// static float yRot = 0.0f;
// yRot += 5.0f;
m3dRotationMatrix44(mRotationMartix, 0.0, 0.0f, 0.0f, 1.0f);
//将旋转和移动的矩阵结果 合并到mFinalTransform (矩阵相乘)
m3dMatrixMultiply44(mFinalTransform, mTransfromMatrix, mRotationMartix);
//将矩阵结果 提交给固定着色器(平面着色器)中绘制
shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinalTransform,vRed);
triangleBatch.Draw();
/*将后台缓冲区进行渲染。结束后交换给前台*/
glutSwapBuffers();
}
/*记录图形x,y轴平易的距离*/
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
//键位函数
void SpecialKeys(int key, int x, int y){
GLfloat stepSize = 0.025f;
if (key == GLUT_KEY_UP) {
yPos += stepSize;
}
if (key == GLUT_KEY_DOWN) {
yPos -= stepSize;
}
if (key == GLUT_KEY_LEFT) {
xPos -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
xPos += stepSize;
}
//碰撞检测
if (xPos < (-1.0f + blockSize)) {
xPos = -1.0f + blockSize;
}
if (xPos > (1.0f - blockSize)) {
xPos = 1.0f - blockSize;
}
if (yPos < (-1.0f + blockSize)) {
yPos = -1.0f + blockSize;
}
if (yPos > (1.0f - blockSize)) {
yPos = 1.0f - blockSize;
}
glutPostRedisplay();
}