[demo2].进阶啦,来一个可以移动的多边形吧

跳去目录


首先,来绘制一个多边形

  1. 在 [demo1].来一个最简单的三角形吧 的demo的基础上,将vTops里的顶点改成5个(或者6个7个8个...),并将全局容器内的绘制方式改为GL_POLYGON(或者改成其他的方式,见下图),并修改顶点个数
GLfloat vTops[] = {
    -0.4, -0.3, 0, //v0
    0.1, -0.7, 0, //v1
    0.6, -0.1, 0, //v2
    0.4, 0.5, 0, //v3
    -0.2, 0.4, 0 // v4
};
    
/**
 * GL_TRIANGLES 三角形
 */
triangleBatch.Begin(GL_POLYGON, 5);
image-20200705012351940.png

从上图可以看到有很多种绘图方式,可以根据需要选择自己需要的方式,这里是5个顶点,所以选择了GL_POLYGON(8个也可以选择POLYGON,会按照顺序依次连接并绘制封闭图形)。

  1. 直接运行,就可以看到一个5变形成功的绘制在窗口内了

    image-20200705013621924.png

接下来,让多边形动起来

  1. 设置一个全局变量,用于存放v0, v1, v2, v3, v4相对于v0的位置

    同时设置一个全局变量,用于存放v0,v1,v2,v3,v4的初始位置和新位置

    //v0, v1, v2, v3, v4 相对于v0的相对位置
    GLfloat relate_tops[15] = { };
    //v0, v1, v2, v3, v4 的新位置
    GLfloat movie_tops[15] = { };
    
  1. 在准备时计算相对位置

    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]);
    }
    
    

    这里是5个点,所以要循环3*5=15次,如果是n个点,则需要循环 3 *n次

  2. 注册一个新的函数,用于捕获键盘的输入

    /**
     * @param key 键盘输入的键
     */
    void SpecialKeys(int key, int x, int y) {
        
    }
    
    glutSpecialFunc(SpecialKeys);
    
  3. 设置步长stepSize,用作每次移动时的移动距离,以此来控制移动速度

    GLfloat stepSize = 0.01;
    

    这里设置为0.01,每次会移动屏幕0.5%的距离(屏幕总长度为 1 - (-1) = 2)

  4. 确定一个参考点,根据参考点与其他点的相对位置关系,得到其他点的位置

    GLfloat blockX = movie_tops[0];
    GLfloat blockY = movie_tops[1];
    

    这里将v0作为参考点,所有点会随着v0的移动而移动,之前设置相对点的时候也是以v0作为参考点的

  5. 检测键盘的输入,确认参考点的移动位置,向上移动,y增大,向下移动,y减小,向左移动,x减小,向右移动,x增大

    //向上移动
        switch (key) {
                //方向键 上
            case GLUT_KEY_UP:
                blockY = blockY + stepSize;
            break;
                //方向键 下
            case GLUT_KEY_DOWN:
                blockY = blockY - stepSize;
            break;
                //方向键 左
            case GLUT_KEY_LEFT:
                blockX = blockX - stepSize;
            break;
                //方向键 右
            case GLUT_KEY_RIGHT:
                blockX = blockX + stepSize;
            break;
                //键盘 i 上
            case 105:
                blockY = blockY + stepSize;
            break;
                //键盘 k 下
            case 107:
                blockY = blockY - stepSize;
            break;
                //键盘 < 下
            case 44:
                blockY = blockY - stepSize;
            break;
                //键盘 j 左
            case 106:
                blockX = blockX - stepSize;
            break;
                //键盘 l 右
            case 108:
                blockX = blockX + stepSize;
            break;
                //键盘 u 左上
            case 117:
                blockX = blockX - stepSize;
                blockY = blockY + stepSize;
            break;
                //键盘 o 右上
            case 111:
                blockX = blockX + stepSize;
                blockY = blockY + stepSize;
            break;
                //键盘 m 左下
            case 109:
                blockX = blockX - stepSize;
                blockY = blockY - stepSize;
            break;
                //键盘 > 右下
            case 46:
                blockX = blockX + stepSize;
                blockY = blockY - stepSize;
            break;
                
            default:
                printf("Unwork Key %d\n", key);
                break;
        }
    

    在这里,我额外根据按键时打印的信号另外增加了9个键,遗憾的是,E和D不知为何无法响应(就是按了没反应),所以并没用WSAD

  6. 再根据相对位置,将移动后的点和v0的关系求出

    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]);
      }
    
  7. 在将移动后新的位置复制进容器内,提交渲染

    这个时候已经有了一支画笔,所以只需要强制重新渲染就OK

    triangleBatch.CopyVertexData3f(movie_tops);
    glutPostRedisplay();
    
  8. 运行一下,5边形显示正常,按一下键盘,都正常,太棒了~

    但是!但是!奇怪的事情发生了,我再按E和D键,他们的功能和I和J的一模一样,E向上移动,D向左移动,真的神奇 =。=(有小伙伴知道吗?求解答)

  9. 到这里,可移动的多边形就搞定了,但是并不完善,还有边界的检测没做。

    为了做边界检测,我们需要设置一组临时数据,如果临时数据超出边界,就让这一次的移动无效

    GLfloat tem_point[15] = { };
    for (int i = 0 ; i < 15; i++) {
          if (i % 3 == 0) {
              tem_point[i] = relate_tops[i] + blockX;
          } else if (i % 3 == 1) {
              tem_point[i] = relate_tops[i] + blockY;
          } else {
              tem_point[i] = 0;
          }
    
          if (tem_point[i] > 1 || tem_point[i] < -1) {
              return;
          }
    
      }
    

    经测试,完美~ (也可以考虑将tem_point设置为全局变量)

    点我下载这个demo


但是,当点特别多的时候,循环上千次,上万次的时候,这种方式未免有些无用(一个精细的2d模型上万的点正常吧),该怎么办呢?这时候就要用上线性代数了。具体怎么用?看下一篇


跳去目录

你可能感兴趣的:([demo2].进阶啦,来一个可以移动的多边形吧)