美文网首页从0开始的视觉学习
[demo2].进阶啦,来一个可以移动的多边形吧

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

作者: NealDN | 来源:发表于2020-07-05 00:47 被阅读0次

    跳去目录


    首先,来绘制一个多边形

    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].进阶啦,来一个可以移动的多边形吧

        本文链接:https://www.haomeiwen.com/subject/bormqktx.html