[demo3].再进阶一次,数学与代码的完美碰撞
接着 [demo2].进阶啦,来一个可以移动的多边形吧 的代码继续
- 删掉不再需要的代码
// //v0, v1, v2, v3, v4 相对于v0的相对位置
// GLfloat relate_tops[15] = { }; //删掉
// //v0, v1, v2, v3, v4 的新位置
// GLfloat movie_tops[15] = { }; //删掉
// GLfloat blockX = movie_tops[0]; //删掉
// GLfloat blockY = movie_tops[1]; //删掉
// blockY = blockY + stepSize;//这一系列的全部删掉
// for (int i = 0 ; i < 15; i++) { // 从这里开始删掉
// if (i % 3 == 0) {
// movie_tops[i] = relate_tops[i] + blockX;
// } else if (i % 3 == 1) {
// movie_tops[i] = relate_tops[i] + blockY;
// } else {
// movie_tops[i] = 0;
// }
// // printf("%.01f", movie_tops[i]);
// } // 到这里结束 全部删掉
//for (int i = 0 ; i < 15; i++) {
// movie_tops[i] = vTops[i];
// relate_tops[i] = vTops[i] - vTops[i % 3];
// printf("%.01f - %0.1f\n", movie_tops[i], relate_tops[i]);
// }
-
将vTops设置为全局变量(放到triangleBatch下面)
-
将SpecialKeys函数中的movie_tops修改为vTops
//triangleBatch.CopyVertexData3f(movie_tops);
triangleBatch.CopyVertexData3f(vTops);
Run一下,五边形正常,按键全部无效
- 接着开始准备矩阵算法,我们需要设置一个全局的x和y的向量参数
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
- 在SpecialKeys中,根据移动的方向去改变这个向量的大小
switch (key) {
//方向键 上
case GLUT_KEY_UP:
yPos += stepSize;
break;
//方向键 下
case GLUT_KEY_DOWN:
yPos -= stepSize;
break;
//方向键 左
case GLUT_KEY_LEFT:
xPos -= stepSize;
break;
//方向键 右
case GLUT_KEY_RIGHT:
xPos += stepSize;
break;
//键盘 i 上
case 105:
yPos += stepSize;
break;
//键盘 k 下
case 107:
yPos -= stepSize;
break;
//键盘 < 下
case 44:
yPos -= stepSize;
break;
//键盘 j 左
case 106:
xPos -= stepSize;
break;
//键盘 l 右
case 108:
xPos += stepSize;
break;
//键盘 u 左上
case 117:
yPos += stepSize;
xPos -= stepSize;
break;
//键盘 o 右上
case 111:
yPos += stepSize;
xPos += stepSize;
break;
//键盘 m 左下
case 109:
yPos -= stepSize;
xPos -= stepSize;
break;
//键盘 > 右下
case 46:
yPos -= stepSize;
xPos += stepSize;
break;
default:
printf("Unwork Key %d\n", key);
break;
}
这样,对键盘的响应时间就完成了,当然,这个时候Run还是无法操作的,因为vTops并没用发生任何变化,我们只是对向量xPos,yPos进行了操作,因此,我们需要将向量应用到vTops中,这个时候就轮到矩阵登场了(线性代数)锵~锵~锵~
-
在RenderScene中,新建一个局部变量,它是一个4*4的矩阵
M3DMatrix44f mFinalTransform;
这个值用于存放最终的结果(使用方法类似于NSError,用的时候千万别加上&,会报错的 T.T)
M3DMatrix44f mTransfromMatrix;
这个值用于存放每次变化后相对于原点的向量结果,使用方式同上
然后把向量代入平移的矩阵算法中
m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0f);
这样就能在每次刷新的时候得到相对于原点的向量结果,然后将这个结果提交给固定着色器,先试下会发生什么
//单元着色器, 并设置着色器的颜色 // shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vPencil); //改成下面的样子 shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransfromMatrix, vPencil);
Run一下,发现图形已经可以正常移动了,但是边界检测器却失效了,无法检测边界,这时候我们就需要修改边界条件了
最大侧边距离根据这张图,我们可以看到,向左最多可以移动0.6的距离,向上最多可以移动0.5的距离,向右最多可以移动0.4的距离,向下最多只能移动0.3的距离,那么换成向量则是
// for (int i = 0; i < 15; i++) { // if (tem_point[i] > 1 || tem_point[i] < -1) { // return; // } // } 替换成下面的 if (xPos <= -0.6) { xPos = -0.6; } else if (xPos >= 0.4) { xPos = 0.4; } if (yPos >= 0.5) { yPos = 0.5; } else if (yPos <= -0.3) { yPos = -0.3; }
再Run一遍,然后移动,边界碰撞就出现了,完美! 👏👏👏👏
-
但是每次都要这样手动去算,我不要!所以我们先创建4个全局变量,用于保存4个极值(就是到四条边的距离了)
GLfloat distanceRight = 1.0f; GLfloat distanceLeft = -1.0f; GLfloat distanceTop = 1.0f; GLfloat distanceBottom = -1.0f;
为什么要这样设置初始值呢?因为如果是0的话,就会卡在原点不动了,这个和下面的边界条件的判断相关
然后在SetupRC中将它们计算出来
for (int i = 0; i < 15; i++) { if (i % 3 == 0) { if (-1 - vTops[i] > distanceLeft) { distanceLeft = -1 - vTops[i]; } if (1 - vTops[i] < distanceRight) { distanceRight = 1 - vTops[i]; } } else if (i % 3 == 1) { if (1 - vTops[i] < distanceTop) { distanceTop = 1 - vTops[i]; } if (-1 - vTops[i] > distanceBottom) { distanceBottom = -1 - vTops[i]; } } }
然后再将碰撞的条件改为
// if (xPos <= -0.6) { // xPos = -0.6; // } else if (xPos >= 0.4) { // xPos = 0.4; // } // // if (yPos >= 0.5) { // yPos = 0.5; // } else if (yPos <= -0.3) { // yPos = -0.3; // } // if (xPos <= distanceLeft) { xPos = distanceLeft; } else if (xPos >= distanceRight) { xPos = distanceRight; } if (yPos >= distanceTop) { yPos = distanceTop; } else if (yPos <= distanceBottom) { yPos = distanceBottom; }
然后Run起来,完美!!!!
问题又双叒叕来了,如果我想让它旋转呢?
-
设置一个全局变量,用来记录当前的旋转角度(0 ~ 360)
再设置一个全局变量用来设置每次旋转角度(旋转的步长?旋长?旋度?)
GLFloat angel = 0.0f; GLfloat stepAngel = 10.0f;
-
在SpecialKeys中新监测两个Key,用于设置左旋右旋,就 "{"和"}"吧
//左旋 case 91: angel = angel + stepAngel; if (angel < 0) { angel = angel - 360; } break; //右旋 case 93: angel = angel - stepAngel; if (angel > 360) { angel = angel + 360; } break;
要注意,OpenGL的角度是逆时针旋转的,所以右旋得减,左旋得加
-
然后在RenderScene中,新建一个旋转的矩阵,将当前旋转的角度放入矩阵中进行运算
M3DMatrix44f mRotationMartix; // mRotationMartix 矩阵计算结果 // m3dDegToRad(angel) 当前旋转的角度 // 0, 0, 1 绕 (0,0,0) -> (0, 0, 1) 这条射线旋转,也就是绕Z轴旋转, 如果想绕x轴旋转就传 1, 0, 0 m3dRotationMatrix44(mRotationMartix, m3dDegToRad(angel), 0, 0, 1);
-
然后将前面的平移矩阵和旋转矩阵合并起来,并将结果存入上面设置了完全没用过的mFinalTransform中,就得到最终的矩阵了
m3dMatrixMultiply44(mFinalTransform, mTransfromMatrix, mRotationMartix);
-
最后,将着色器的绘制矩阵替换为最终矩阵
// shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransfromMatrix, vPencil); shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vPencil);
Run一下,棒~ 👏👏👏👏👏👏👏
-
然后将旋转的轴更换下试试
//m3dRotationMatrix44(mRotationMartix, m3dDegToRad(angel), 0, 0, 1); m3dRotationMatrix44(mRotationMartix, m3dDegToRad(angel), 1, 0, 0);
Run,成功绕着x轴旋转,棒~ 👏👏👏👏👏👏👏