从0开始的视觉学习

[demo3].再进阶一次,数学与代码的完美碰撞

2020-07-05  本文已影响0人  NealDN

跳去目录


接着 [demo2].进阶啦,来一个可以移动的多边形吧 的代码继续

  1. 删掉不再需要的代码
// //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]);
//    }
  1. 将vTops设置为全局变量(放到triangleBatch下面)

  2. 将SpecialKeys函数中的movie_tops修改为vTops

//triangleBatch.CopyVertexData3f(movie_tops);
triangleBatch.CopyVertexData3f(vTops);

​ Run一下,五边形正常,按键全部无效

  1. 接着开始准备矩阵算法,我们需要设置一个全局的x和y的向量参数
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;
  1. 在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中,这个时候就轮到矩阵登场了(线性代数)锵~锵~锵~

  1. 在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一遍,然后移动,边界碰撞就出现了,完美! 👏👏👏👏

  2. 但是每次都要这样手动去算,我不要!所以我们先创建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起来,完美!!!!

    demo点这里下载啦


问题又双叒叕来了,如果我想让它旋转呢?

  1. 设置一个全局变量,用来记录当前的旋转角度(0 ~ 360)

    再设置一个全局变量用来设置每次旋转角度(旋转的步长?旋长?旋度?)

    GLFloat angel = 0.0f;
    GLfloat stepAngel = 10.0f;
    
  2. 在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的角度是逆时针旋转的,所以右旋得减,左旋得加

  3. 然后在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);
    
  4. 然后将前面的平移矩阵和旋转矩阵合并起来,并将结果存入上面设置了完全没用过的mFinalTransform中,就得到最终的矩阵了

    m3dMatrixMultiply44(mFinalTransform, mTransfromMatrix, mRotationMartix);
    
  5. 最后,将着色器的绘制矩阵替换为最终矩阵

    //    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransfromMatrix, vPencil);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vPencil);
    

    Run一下,棒~ 👏👏👏👏👏👏👏

  6. 然后将旋转的轴更换下试试

    //m3dRotationMatrix44(mRotationMartix, m3dDegToRad(angel), 0, 0, 1);
    m3dRotationMatrix44(mRotationMartix, m3dDegToRad(angel), 1, 0, 0);
    

    Run,成功绕着x轴旋转,棒~ 👏👏👏👏👏👏👏

    点这里下Demo啦


跳去目录

上一篇下一篇

猜你喜欢

热点阅读