与上篇中的绘制三角形的主要区别:修改了图元链接方式、增加了键位控制
void setupRC() //函数中修改一行代码
//修改图元链接方式GL_TRIANGLE_FAN
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
int main(int argc,char *argv[]) //函数中新增两行代码
//针对MAC OS X,为了更加安全,设置当前工作目录
gltSetWorkingDirectory(argv[0]);
//添加新的特殊函数
glutSpecialFunc(SpecialKeys);
坐标更新方法
一个非常形象的正方形运行可以发现:每次点击键位进行移动的时候,都会走一次RenderScene方法
此外还需要考虑超出边界的问题,增加限制条件
#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>
//定义一个着色管理器
GLShaderManager shaderManager;
//简单的批次容器,是GLTools的一个简单的容器类
GLBatch triangleBatch;
//设置顶点到X/Y轴距离 = 正方形边长的一半
GLfloat blockSize = 0.1f;
//正方形的4个点坐标
GLfloat vVerts[] = {
-blockSize,-blockSize,0.0f,//A点
blockSize,-blockSize,0.0f,//B点
blockSize,blockSize,0.0f,//C点
-blockSize,blockSize,0.0f//D点
};
void changeSize(int w,int h)
{
glViewport(0, 0, w, h);
}
//渲染方法,每次更新界面(或者图形进行移动就会触发)
void RenderScene(void)
{
//1、清除一个或一组特定缓存区
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//2、设置颜色
GLfloat vColor[] = {1.0,1.0,0.0,1.0f};
//3、传递到存储着色器中
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vColor);
//4、提交着色器
triangleBatch.Draw();
//5、将后台缓冲区进行渲染,渲染结束后交换给前台
glutSwapBuffers();
}
void setupRC()
{
//1、设置背景颜色
glClearColor(0.98f, 0.4f, 0.7f, 1);
//2、初始化渲染管理器
shaderManager.InitializeStockShaders();
//3、顶点已经声明在公共
//4、修改图元链接方式GL_TRIANGLE_FAN
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
void SpecialKeys (int key, int x,int y)
{
//每次移动的距离
GLfloat stepSize = 0.05f;
//拿到左上角顶点D的坐标
GLfloat squX = vVerts[9];
GLfloat squY = vVerts[10];
if (key == GLUT_KEY_UP) {
//向上移动,Y+size
squY += stepSize;
}
if (key == GLUT_KEY_DOWN) {
squY -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
squX += stepSize;
}
if (key == GLUT_KEY_LEFT) {
squX -= stepSize;
}
//===考虑到边界问题===
if (squX < -1.0f) {
squX = -1.0f;
}
if ((squX + blockSize *2) > 1.0f) {
squX = 1.0f - blockSize*2;
}
if (squY > 1.0f) {
squY = 1.0f;
}
if ((squY - blockSize *2) < -1.0f) {
squY = -1.0f + blockSize *2;
}
//然后更新ABCD四个顶点
//此时是根据D点的计算,A的Y比D的Y小 = DY-边长(边长 = blockSize*2)
vVerts[0] = squX;
vVerts[1] = squY - blockSize*2;
vVerts[3] = squX + blockSize*2;
vVerts[4] = squY - blockSize*2;
vVerts[6] = squX + blockSize*2;
vVerts[7] = squY;
vVerts[9] = squX;
vVerts[10] = squY;
//更新数据,触发重新渲染
triangleBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
int main(int argc,char *argv[])
{
//针对MAC OS X,为了更加安全,设置当前工作目录
gltSetWorkingDirectory(argv[0]);
//准备工作
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Square");
glutReshapeFunc(changeSize);
glutDisplayFunc(RenderScene);
//添加新的特殊函数
glutSpecialFunc(SpecialKeys);
GLenum status = glewInit();
if (GLEW_OK != status) {
printf("GLEW Error:%s\n",glewGetErrorString(status));
return 1;
}
setupRC();
glutMainLoop();
return 0;
}
矩阵方式
思考:如果一个图形有100个顶点,那坐标更新要写100次吗?
我们可以用矩阵方式修改代码进行简单实现。
并且在上述代码基础上,增加边移动边旋转效果(矩阵相乘)
我们先声明两个需要用到的参数,然后只需要修改如下2个方法就可以了。
//矩阵方法
//记录在X轴方向上偏移的距离
GLfloat xPos = 0.0f;
//记录在Y轴方向上偏移的距离
GLfloat yPos = 0.0f;
void RenderScene2(void)
{
//1、清除一个或一组特定缓存区
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//2、设置颜色
GLfloat vColor[] = {1.0,1.0,0.0,1.0f};
//设置矩阵 平移+旋转+最终
M3DMatrix44f mTransfrom,mRotation,mFinal;
//平移
m3dTranslationMatrix44(mTransfrom, xPos, yPos, 0.0f);
//旋转 (每次平移旋转5度)
static float yRot = 0.0f;
yRot += 5.0f;
m3dRotationMatrix44(mRotation, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
//矩阵相乘拿到mFinal
m3dMatrixMultiply44(mFinal, mTransfrom, mRotation);
//3、使用着色器:GLT_SHADER_IDENTITY不够用,换成平面着色器(是一个固定着色器)
shaderManager.UseStockShader(GLT_SHADER_FLAT,mFinal,vColor);
//4、进行绘制
triangleBatch.Draw();
//5、将后台缓冲区进行渲染,渲染结束后交换给前台
glutSwapBuffers();
}
void SpecialKeys2 (int key, int x,int y)
{
//每次移动的距离
GLfloat stepSize = 0.05f;
if (key == GLUT_KEY_UP) {
//向上移动,Y+size
yPos += stepSize;
}
if (key == GLUT_KEY_DOWN) {
yPos -= stepSize;
}
if (key == GLUT_KEY_RIGHT) {
xPos += stepSize;
}
if (key == GLUT_KEY_LEFT) {
xPos -= stepSize;
}
//===考虑到边界问题,碰撞检测===
//此处xPos yPos可以看成中心点
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();
}
网友评论