在上一篇笔记中, 我们已经实现了一个简单三角形的绘制. 本文将介绍图形移动的两种实现方式及图形的旋转, 以及在移动过程中对窗口边界的检查, 以免图形移动到窗口外部.
图形的移动
绘制图形
在上一篇笔记中, 我们绘制了一个三角形. 为了方便观察, 本文中将三角形改为四边形.
// 四边形边长
GLfloat length = 0.1f;
// 设置四边形顶点位置, 设置为全局变量, 方便改变坐标实现移动
GLfloat verts[] = {
-length, -length, 0.0f,
length, -length, 0.0f,
length, length, 0.0f,
-length, length, 0.0f,
};
void setupRC() {
// 设置清屏颜色
glClearColor(0.0f,0.0f,1.0f,1.0f);
// 初始化管线
shaderManager.InitializeStockShaders();
// 开始绘制
triangleBatch.Begin(GL_POLYGON, 4);
triangleBatch.CopyVertexData3f(verts);
triangleBatch.End();
}
复制代码
监听键盘事件
在 main 函数中, 注册监听事件
// 注册特殊函数
glutSpecialFunc(specialKeys);
复制代码
方法一: 直接改变顶点的位置
void specialKeys(int key, int x, int y) {
GLfloat stepLength = 0.025f;
// 获取左上角顶点的坐标值
GLfloat originX = verts[0];
GLfloat originY = verts[10];
// 判断按下的是哪个键
if (key == GLUT_KEY_UP) {
originY += stepLength;
} else if (key == GLUT_KEY_DOWN) {
originY -= stepLength;
} else if (key == GLUT_KEY_LEFT) {
originX -= stepLength;
} else {
originX += stepLength;
}
// 修改各个点的坐标
verts[0] = originX;
verts[1] = originY - length * 2;
verts[3] = originX + length * 2;
verts[4] = originY - length * 2;
verts[6] = originX + length * 2;
verts[7] = originY;
verts[9] = originX;
verts[10] = originY;
// 刷新顶点坐标
triangleBatch.CopyVertexData3f(verts);
// 重新渲染
glutPostRedisplay();
}
复制代码
至此, 便实现了使用上下左右键控制四边形移动.
窗口边界检查
使用上述方法实现四边形移动后, 会存在这样一个问题: 当四边形移动到窗口边沿后, 继续移动将会移出窗口范围, 最终消失不见.
为了防止此类问题出现, 需要在移动过程中对窗口边界进行判断.
// 在判断按键并改变顶点坐标值后进行触碰到边界(4个边界)的处理
// 当正方形移动超过最左边的时候
if (originX < -1.0f) {
originX = -1.0f;
}
// 当正方形移动到最右边时
// 1.0 - length * 2 = 总边长 - 正方形的边长 = 最左边点的位置
if (originX > (1.0 - length * 2)) {
originX = 1.0f - length * 2;
}
// 当正方形移动到最下面时
// -1.0 - length * 2 = Y(负轴边界) - 正方形边长 = 最下面点的位置
if (originY < -1.0f + length * 2 ) {
originY = -1.0f + length * 2;
}
// 当正方形移动到最上面时
if (originY > 1.0f) {
originY = 1.0f;
}
复制代码
此时, 四边形移动到窗口边界时就不会出界了.
方法二: 使用矩阵实现移动
定义 x, y 轴上的偏移量
//x轴上移动的距离
GLfloat offsetX =0.0f;
//y轴上移动的距离
GLfloat offsetY =0.0f;
复制代码
在 specialKeys
中设置偏移量
// 判断按下的是哪个键
if (key == GLUT_KEY_UP) {
offsetY += stepLength;
} else if (key == GLUT_KEY_DOWN) {
offsetY -= stepLength;
} else if (key == GLUT_KEY_LEFT) {
offsetX -= stepLength;
} else {
offsetX += stepLength;
}
//触碰到边界(4个边界)的处理
if(offsetX < -1.0f + length) {
offsetX = -1.0f + length;
}
if(offsetX > 1.0f - length) {
offsetX = 1.0f - length;
}
if(offsetY < -1.0f + length) {
offsetY = -1.0f + length;
}
if(offsetY > 1.0f - length) {
offsetY = 1.0f - length;
}
复制代码
在 renderScene
在重新渲染
//利用矩阵帮助移动
//finalMatrix 结果矩阵
//transformMatrix 平移矩阵
//rotationMatrix 旋转矩阵
M3DMatrix44f finalMatrix, transformMatrix, rotationMatrix;
//平移 x,y,z,w(缩放因子 = 1)
//3D中平移的原理与矩阵之间关系
/*
参数1:矩阵
参数2、3、4:X,Y,Z上平移距离
*/
m3dTranslationMatrix44(transformMatrix, offsetX, offsetY, 0.0f);
//平面着色器
/*
1.平移矩阵 transformMatrix 与 每个顶点 相乘 -> 新顶点 (顶点着色器
2.将片元着色红色 (片元着色器)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformMatrix, redColor);
triangleBatch.Draw();
复制代码
图形旋转
在平移的基础上, 使用矩阵实现边移动边旋转.
// 设置平移属性
static float degree = 0.0f;
/*
参数1:矩阵
参数2:弧度
参数3:X:1,0 1:围绕X轴旋转,0不围绕X轴旋转
参数4:Y:1,0
参数5:Z:1,0
*/
m3dRotationMatrix44(rotationMatrix, m3dDegToRad(degree), 0.0f, 0.0f, 1.0f);
// 修改旋转度数
degree +=5.0f;
// 结合2个矩阵的结果 平移矩阵 * 旋转矩阵 = 最终结果矩阵
m3dMatrixMultiply44(finalMatrix, transformMatrix, rotationMatrix);
shaderManager.UseStockShader(GLT_SHADER_FLAT, finalMatrix, redColor);
复制代码
运行结果: