我应该如何在opengl中处理(变形)4D对象? [英] how should i handle (morphing) 4D objects in opengl?

查看:19
本文介绍了我应该如何在opengl中处理(变形)4D对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想尝试编写一个类似于此

因此,您可以通过这种方式渲染任何线框网格(即使 BR 渲染也应该采用这种方式).

如果您想升级到切割,那么您应该获取每条线框线并计算其与切割超平面的交点.如果我们选择通过点的超平面

O(0,0,0,u_cut)

正常

N(0,0,0,1)

然后任务会简化很多.有3个选项.让我们考虑端点 A,B 的边线:

  1. 没有交叉路口

    ((A.u > u_cut)&&(B.u > u_cut)) ||((A.u 

    忽略这样的边缘

  2. 1 个路口

    ((A.u >= u_cut)&&(B.u <= u_cut)) ||((A.u <= u_cut)&&(B.u >= u_cut))

    所以通过线性插值计算交点

    x = A.x + (B.x-A.x)*(u_cut-A.u)/(B.u-A.u)y = A.y + (B.y-A.y)*(u_cut-A.u)/(B.u-A.u)z = A.z + (B.z-A.z)*(u_cut-A.u)/(B.u-A.u)

    并记住它所属的点和边.

  3. 完全进入

    (A.u == u_cut)&&(B.u == u_cut)

    只需记住两个端点并渲染此边缘即可.

以这种方式处理所有边之后,您需要分析记住的交叉点并根据边之间的连接信息从它们创建新边.我还没有这样做,所以我对此无能为力.我会尝试连接共享相同邻居的记忆点,但不确定在 4D 中这是否足够.

有关更多信息,请查看我找到或回答的相关 QA:

  • [Edit2]实体网格和横截面

    所以我对架构进行了相当大的更改.我将 4D 5x5 同质变换矩阵 (reper4D) 移动到单独的文件中,并通过 4D 单纯形(4 点 4 边四面体)添加颜色和网格定义).切割只是计算单纯形和切割超平面的交点(如上所述),导致 3 个点(三角形)、4 个点(四面体)或 0 个点.可以轻松渲染(无需分析边缘之间的连接).有关更多信息,请参阅:

    • 最糟糕的部分是将超立方体定义为一组单纯形......

      i want to try writing a playground similar to this 4D toys, so i started learning opengl.
      from my current understanding, people use VBOs and uniform transformation matrix for mostly-static objects
      (like cubes, skeletal animations etc., which usually just involves transformations)

      i also heard that morphing between models also uses VBOs for caching both models, since both of them will be well defined and not so much intermediates.

      but in the 4D toys mentioned above, objects are morphing and clipped a lot.
      and it is likely that there is no defined models, and many transitions in between.
      (it might be a simple square now, and a spiky ball clipped in half later ).
      in this case, is updating-vertex-VBO-per-frame or Vertex Arrays(which i saw in another question) a suitable solution?

      解决方案

      For starters I would use 4D -> 3D projection instead of cut by hyperplane. The result is not the same but will get you closer to your goal (so you can latter upgrade this to cut). So similarly like in 3D -> 2D conversions used in graphics you got 2 choices one is using perspective projection and second is just ignoring the 4th dimension coordinate while rendering. I will use the latter as it is simpler.

      1. structures

        To make this as simple as I can I will use wire-frame instead of BR rendering. So you need to handle 4D mesh (wire-frame). I would use 2 tables:

        double pnt[];   // 4D point list (x,y,z,u)
        int  lin[];     // lines point indexes (i0,i1)
        

        first one stores all the vertexes of your mesh and the second hold index pairs of points connected by lines in wire-frame representation.

      2. transforms

        If I would only ignore the 4th coordinate then we would not get the desired functionality. So to make the 4th dimension work we need to add 4D transform to orient our mesh in 4D before rendering. So use homogenous transform matrix and lets call ir rep. In 4D it should be 5x5 orthonormal matrix with 4x4 rotation part rot.

        To make this even easier avoid smooth rotations for now (as in 4D that is not as easy) and compute random rotation 4x4 matrix instead. So just set all the cells randomly <-1,+1>. Handle each row as basis vector. To make them orthonormal just make them unit and exploit cross product. For more info see:

      3. render

        simply convert point table by your transform matrix

        (x',y',z',u',W) = rep * (x,y,z,u,1)
        

        then take the (x,y,z`) and render ...

      Here simple OpenGL/C++ example of 4D hyper cube:

      //---------------------------------------------------------------------------
      //--- Mesh 4D: ver 0.000 ----------------------------------------------------
      //---------------------------------------------------------------------------
      #ifndef _mesh4D_h
      #define _mesh4D_h
      //---------------------------------------------------------------------------
      #include <math.h>
      #include "nd_math.h"
      #include "list.h"
      //---------------------------------------------------------------------------
      const double pi   =    M_PI;
      const double pi2  =2.0*M_PI;
      const double pipol=0.5*M_PI;
      const double deg=M_PI/180.0;
      const double rad=180.0/M_PI;
      //---------------------------------------------------------------------------
      class mesh4D
          {
      public:
          matrix<5> rep;  // 4D uniform 5x5 transform matrix
      
          List<double> pnt;   // 4D point list (x,y,z,u)
          List<int>    lin;   // lines point indexes (i0,i1)
      
          mesh4D()    {}
          mesh4D(mesh4D& a)   { *this=a; }
          ~mesh4D()   {}
          mesh4D* operator = (const mesh4D *a) { *this=*a; return this; }
          //mesh4D* operator = (const mesh4D &a) { ...copy... return this; }
      
          void set_randomrep();               // random oriented uniform 4D transform matrix with origin (0,0,0,0)
          void set_hypercube(double a);
      
          void draw();
          };
      //---------------------------------------------------------------------------
      void mesh4D::set_randomrep()
          {
          int i,j;
          matrix<4> rot;
          rep.unit();
          rot.rnd();
          rot.orthonormal();
          for (i=0;i<4;i++)
           for (j=0;j<4;j++)
            rep[i][j]=rot[i][j];
          }     
      void mesh4D::set_hypercube(double a)
          {
          rep.unit(); // reset orientation
          pnt.num=0;  // clear point list
          lin.num=0;  // clear line list
      
          pnt.add(-a); pnt.add(-a); pnt.add(-a); pnt.add(-a);
          pnt.add(+a); pnt.add(-a); pnt.add(-a); pnt.add(-a);
          pnt.add(-a); pnt.add(+a); pnt.add(-a); pnt.add(-a);
          pnt.add(+a); pnt.add(+a); pnt.add(-a); pnt.add(-a);
          pnt.add(-a); pnt.add(-a); pnt.add(+a); pnt.add(-a);
          pnt.add(+a); pnt.add(-a); pnt.add(+a); pnt.add(-a);
          pnt.add(-a); pnt.add(+a); pnt.add(+a); pnt.add(-a);
          pnt.add(+a); pnt.add(+a); pnt.add(+a); pnt.add(-a);
      
          pnt.add(-a); pnt.add(-a); pnt.add(-a); pnt.add(+a);
          pnt.add(+a); pnt.add(-a); pnt.add(-a); pnt.add(+a);
          pnt.add(-a); pnt.add(+a); pnt.add(-a); pnt.add(+a);
          pnt.add(+a); pnt.add(+a); pnt.add(-a); pnt.add(+a);
          pnt.add(-a); pnt.add(-a); pnt.add(+a); pnt.add(+a);
          pnt.add(+a); pnt.add(-a); pnt.add(+a); pnt.add(+a);
          pnt.add(-a); pnt.add(+a); pnt.add(+a); pnt.add(+a);
          pnt.add(+a); pnt.add(+a); pnt.add(+a); pnt.add(+a);
      
          // A0
          lin.add( 0+0); lin.add( 0+1);
          lin.add( 0+1); lin.add( 0+3);
          lin.add( 0+3); lin.add( 0+2);
          lin.add( 0+2); lin.add( 0+0);
          // A1
          lin.add( 4+0); lin.add( 4+1);
          lin.add( 4+1); lin.add( 4+3);
          lin.add( 4+3); lin.add( 4+2);
          lin.add( 4+2); lin.add( 4+0);
          // A=A0+A1
          lin.add( 0+0); lin.add( 4+0);
          lin.add( 0+1); lin.add( 4+1);
          lin.add( 0+2); lin.add( 4+2);
          lin.add( 0+3); lin.add( 4+3);
      
          // B0
          lin.add( 8+0); lin.add( 8+1);
          lin.add( 8+1); lin.add( 8+3);
          lin.add( 8+3); lin.add( 8+2);
          lin.add( 8+2); lin.add( 8+0);
          // B1
          lin.add(12+0); lin.add(12+1);
          lin.add(12+1); lin.add(12+3);
          lin.add(12+3); lin.add(12+2);
          lin.add(12+2); lin.add(12+0);
          // B=B0+B1
          lin.add( 8+0); lin.add(12+0);
          lin.add( 8+1); lin.add(12+1);
          lin.add( 8+2); lin.add(12+2);
          lin.add( 8+3); lin.add(12+3);
      
          // hyper cube = A+B
          lin.add( 0+0); lin.add( 8+0);
          lin.add( 0+1); lin.add( 8+1);
          lin.add( 0+2); lin.add( 8+2);
          lin.add( 0+3); lin.add( 8+3);
          lin.add( 0+4); lin.add( 8+4);
          lin.add( 0+5); lin.add( 8+5);
          lin.add( 0+6); lin.add( 8+6);
          lin.add( 0+7); lin.add( 8+7);
          }
      //---------------------------------------------------------------------------
      void mesh4D::draw()
          {
          int i,j;
          double _zero=1e-3;
          vector<5> a,b;
          glBegin(GL_LINES);
          for (i=0;i<lin.num;)
              {
              // extrac first point
              j=lin[i]*4; i++;
              a.a[0]=pnt[j]; j++;
              a.a[1]=pnt[j]; j++;
              a.a[2]=pnt[j]; j++;
              a.a[3]=pnt[j]; j++;
              a.a[4]=1.0; // W=1
              // extrac second point
              j=lin[i]*4; i++;
              b.a[0]=pnt[j]; j++;
              b.a[1]=pnt[j]; j++;
              b.a[2]=pnt[j]; j++;
              b.a[3]=pnt[j]; j++;
              b.a[4]=1.0; // W=1
              // transform
              a=rep*a;
              b=rep*b;
              // render
              glVertex3dv(a.a);   // use just x,y,z
              glVertex3dv(b.a);   // use just x,y,z
              }
          glEnd();
          }
      //---------------------------------------------------------------------------
      #endif
      //---------------------------------------------------------------------------
      

      I used mine dynamic list.h template so:


      List<double> xxx; is the same as double xxx[];
      xxx.add(5); adds 5 to end of the list
      xxx[7] access array element (safe)
      xxx.dat[7] access array element (unsafe but fast direct access)
      xxx.num is the actual used size of the array
      xxx.reset() clears the array and set xxx.num=0
      xxx.allocate(100) preallocate space for 100 items

      the nd_math.h is mine lib for N-Dimensional computations. What you need is just 4D,5D vector and 4x4, 5x5 matrix math from linear algebra.

      Both libs are a bit big in size and also legal issues prevent me to share their code here.

      The usage is simple:

      // globals and init
      mesh4D mesh
      double animx=-50.0,danimx=0.0;
      double animy=  0.0,danimy=2.0;
      mesh.set_hypercube(0.5);
      
      // render
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluOrtho2D( -2.0, 2.0, -2.0, 2.0 );
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glRotated(animx,1.0,0.0,0.0);
      glRotated(animy,0.0,1.0,0.0);
      mesh.draw();
      glFlush();
      SwapBuffers(hdc);
      
      // some timer
      animx+=danimx; if (animx>=360.0) animx-=360.0;
      animy+=danimy; if (animy>=360.0) animy-=360.0;
      call_render_here();
      
      // on key press or mouse wheel or what ever
      mesh.set_randomrep();
      

      And here preview for some rep rotations ...

      so this way you can render any wire-frame mesh (even BR rendering should works this way).

      If you want to upgrade to the cut then you should take each Wire-frame line and compute its intersection with cutting hyperplane. If we chose hyperplane that goes through point

      O(0,0,0,u_cut)
      

      and has normal

      N(0,0,0,1)
      

      Then the task will simplify a lot. there are 3 options. Lets consider edge line with endpoints A,B:

      1. no intersection

        ((A.u > u_cut)&&(B.u > u_cut)) || ((A.u < u_cut)&&(B.u < u_cut))
        

        just ignore such edge

      2. 1 intersection

        ((A.u >= u_cut)&&(B.u <= u_cut)) || ((A.u <= u_cut)&&(B.u >= u_cut))
        

        so compute the intersection via linear interpolation

        x = A.x + (B.x-A.x)*(u_cut-A.u)/(B.u-A.u)
        y = A.y + (B.y-A.y)*(u_cut-A.u)/(B.u-A.u)
        z = A.z + (B.z-A.z)*(u_cut-A.u)/(B.u-A.u)
        

        and remember such point and also edge to which it belongs to.

      3. fully inside

        (A.u == u_cut)&&(B.u == u_cut)
        

        just remember both endpoints and also render this edge.

      After all edges are processed this way then you need to analyze the remembered intersection points and create new edges from them based on connectivity info between edges. I did not do this yet so I can not help with this. I would try to connect remembered points sharing the same neighbor but not sure if that is enough in 4D.

      For more info take a look at related QAs I found or answer:

      [Edit1] code with perspective

      //---------------------------------------------------------------------------
      //--- Mesh 4D: ver 0.001 ----------------------------------------------------
      //---------------------------------------------------------------------------
      #ifndef _mesh4D_h
      #define _mesh4D_h
      //---------------------------------------------------------------------------
      #include <math.h>
      #include "nd_math.h"
      #include "list.h"
      //---------------------------------------------------------------------------
      const double pi   =    M_PI;
      const double pi2  =2.0*M_PI;
      const double pipol=0.5*M_PI;
      const double deg=M_PI/180.0;
      const double rad=180.0/M_PI;
      //---------------------------------------------------------------------------
      class mesh4D
          {
      public:
          matrix<5> rep;  // 4D uniform 5x5 transform matrix
      
          List<double> pnt;   // 4D point list (x,y,z,u)
          List<int>    lin;   // lines point indexes (i0,i1)
      
          mesh4D()    {}
          mesh4D(mesh4D& a)   { *this=a; }
          ~mesh4D()   {}
          mesh4D* operator = (const mesh4D *a) { *this=*a; return this; }
          //mesh4D* operator = (const mesh4D &a) { ...copy... return this; }
      
          void set_randomrep();               // random oriented uniform 4D transform matrix with origin (0,0,0,0)
          void set_hypercube(double a);
      
          void draw();
          };
      //---------------------------------------------------------------------------
      void mesh4D::set_randomrep()
          {
          int i,j;
          matrix<4> rot;
          rot.rnd();
          rot.orthonormal();
          for (i=0;i<4;i++)
           for (j=0;j<4;j++)
            rep[i][j]=rot[i][j];
          }
      //---------------------------------------------------------------------------
      void mesh4D::set_hypercube(double a)
          {
          rep.unit();     // reset orientation
          rep[0][4]=0.0;  // set position
          rep[1][4]=0.0;
          rep[2][4]=0.0;
          rep[3][4]=3.0*a;
          pnt.num=0;  // clear point list
          lin.num=0;  // clear line list
      
          pnt.add(-a); pnt.add(-a); pnt.add(-a); pnt.add(-a);
          pnt.add(+a); pnt.add(-a); pnt.add(-a); pnt.add(-a);
          pnt.add(-a); pnt.add(+a); pnt.add(-a); pnt.add(-a);
          pnt.add(+a); pnt.add(+a); pnt.add(-a); pnt.add(-a);
          pnt.add(-a); pnt.add(-a); pnt.add(+a); pnt.add(-a);
          pnt.add(+a); pnt.add(-a); pnt.add(+a); pnt.add(-a);
          pnt.add(-a); pnt.add(+a); pnt.add(+a); pnt.add(-a);
          pnt.add(+a); pnt.add(+a); pnt.add(+a); pnt.add(-a);
      
          pnt.add(-a); pnt.add(-a); pnt.add(-a); pnt.add(+a);
          pnt.add(+a); pnt.add(-a); pnt.add(-a); pnt.add(+a);
          pnt.add(-a); pnt.add(+a); pnt.add(-a); pnt.add(+a);
          pnt.add(+a); pnt.add(+a); pnt.add(-a); pnt.add(+a);
          pnt.add(-a); pnt.add(-a); pnt.add(+a); pnt.add(+a);
          pnt.add(+a); pnt.add(-a); pnt.add(+a); pnt.add(+a);
          pnt.add(-a); pnt.add(+a); pnt.add(+a); pnt.add(+a);
          pnt.add(+a); pnt.add(+a); pnt.add(+a); pnt.add(+a);
      
          // A0
          lin.add( 0+0); lin.add( 0+1);
          lin.add( 0+1); lin.add( 0+3);
          lin.add( 0+3); lin.add( 0+2);
          lin.add( 0+2); lin.add( 0+0);
          // A1
          lin.add( 4+0); lin.add( 4+1);
          lin.add( 4+1); lin.add( 4+3);
          lin.add( 4+3); lin.add( 4+2);
          lin.add( 4+2); lin.add( 4+0);
          // A=A0+A1
          lin.add( 0+0); lin.add( 4+0);
          lin.add( 0+1); lin.add( 4+1);
          lin.add( 0+2); lin.add( 4+2);
          lin.add( 0+3); lin.add( 4+3);
      
          // B0
          lin.add( 8+0); lin.add( 8+1);
          lin.add( 8+1); lin.add( 8+3);
          lin.add( 8+3); lin.add( 8+2);
          lin.add( 8+2); lin.add( 8+0);
          // B1
          lin.add(12+0); lin.add(12+1);
          lin.add(12+1); lin.add(12+3);
          lin.add(12+3); lin.add(12+2);
          lin.add(12+2); lin.add(12+0);
          // B=B0+B1
          lin.add( 8+0); lin.add(12+0);
          lin.add( 8+1); lin.add(12+1);
          lin.add( 8+2); lin.add(12+2);
          lin.add( 8+3); lin.add(12+3);
      
          // hyper cube = A+B
          lin.add( 0+0); lin.add( 8+0);
          lin.add( 0+1); lin.add( 8+1);
          lin.add( 0+2); lin.add( 8+2);
          lin.add( 0+3); lin.add( 8+3);
          lin.add( 0+4); lin.add( 8+4);
          lin.add( 0+5); lin.add( 8+5);
          lin.add( 0+6); lin.add( 8+6);
          lin.add( 0+7); lin.add( 8+7);
          }
      //---------------------------------------------------------------------------
      void mesh4D::draw()
          {
          int i,j;
          const double _zero=1e-3;
          double focal_length=1.0;
      
          vector<5> a,b;
          glBegin(GL_LINES);
          for (i=0;i<lin.num;)
              {
              // extrac first point
              j=lin[i]*4; i++;
              a.a[0]=pnt[j]; j++;
              a.a[1]=pnt[j]; j++;
              a.a[2]=pnt[j]; j++;
              a.a[3]=pnt[j]; j++;
              a.a[4]=1.0; // W=1
              // extrac second point
              j=lin[i]*4; i++;
              b.a[0]=pnt[j]; j++;
              b.a[1]=pnt[j]; j++;
              b.a[2]=pnt[j]; j++;
              b.a[3]=pnt[j]; j++;
              b.a[4]=1.0; // W=1
              // transform
              a=rep*a;
              b=rep*b;
              // perspective: camera projection plane u=0, focus at (0,0,0,-focal_length)
              if (a[3]>=0.0) a*=divide(focal_length,a[3]+focal_length); else a.zero();
              if (b[3]>=0.0) b*=divide(focal_length,b[3]+focal_length); else b.zero();
              // render
              glVertex3dv(a.a);   // use just x,y,z
              glVertex3dv(b.a);   // use just x,y,z
              }
          glEnd();
          }
      //---------------------------------------------------------------------------
      #endif
      //---------------------------------------------------------------------------
      

      And preview:

      [Edit2] solid mesh and cross-section

      so I changed the architecture quite a bit. I moved the 4D 5x5 homogenuous transform matrix (reper4D) to separate file and added colors and mesh definition by 4D simplexes (4 point 4 side tetrahedrons). The cut is simply computing the intersection (as described above) of simplex and cutting hyperplane resulting in either 3 points (triangle) , 4 points (tetrahedron) or 0 points. Which can be rendered easily (no need to analyze the connections between edges). For more info see this:

      Btw. I think this is how Miegakure works. Here updated code:

      //---------------------------------------------------------------------------
      //--- Mesh 4D: ver 1.000 ----------------------------------------------------
      //---------------------------------------------------------------------------
      #ifndef _mesh4D_h
      #define _mesh4D_h
      //---------------------------------------------------------------------------
      #include "list.h"
      #include "reper4D.h"
      //---------------------------------------------------------------------------
      class mesh4D
          {
      public:
          reper4D rep;        // 4D uniform 5x5 transform matrix
      
          List<double> pnt;   // 4D point list (x,y,z,w)
          List<int>    lin;   // 4D wireframe (i0,i1)
          List<int>    fac;   // 4D simplexes (i0,i1,i2,i3)
          List<DWORD>  col;   // simplex colors (RGB)
      
          mesh4D()    {}
          mesh4D(mesh4D& a)   { *this=a; }
          ~mesh4D()   {}
          mesh4D* operator = (const mesh4D *a) { *this=*a; return this; }
          //mesh4D* operator = (const mesh4D &a) { ...copy... return this; }
      
          void set_hypercube(double a);
          void draw_cut(double w_cut);                                        // render cross section by w=w_cut hyperplane
          void draw          (double focal_length=-1.0,double w_near=-1.0);   // render mesh      (focal_length<0) -> no perspective, else perspective view in W+ direction
          void draw_wireframe(double focal_length=-1.0,double w_near=-1.0);   // render wireframe (focal_length<0) -> no perspective, else perspective view in W+ direction
          };
      //---------------------------------------------------------------------------
      void mesh4D::set_hypercube(double a)
          {
          const double tab_pnt[]=
              {
              -a, -a, -a, -a,
              +a, -a, -a, -a,
              -a, +a, -a, -a,
              +a, +a, -a, -a,
              -a, -a, +a, -a,
              +a, -a, +a, -a,
              -a, +a, +a, -a,
              +a, +a, +a, -a,
              -a, -a, -a, +a,
              +a, -a, -a, +a,
              -a, +a, -a, +a,
              +a, +a, -a, +a,
              -a, -a, +a, +a,
              +a, -a, +a, +a,
              -a, +a, +a, +a,
              +a, +a, +a, +a,
              };
          const int tab_lin[]=
              {
              // A0
               0+0,  0+1,
               0+1,  0+3,
               0+3,  0+2,
               0+2,  0+0,
              // A1
               4+0,  4+1,
               4+1,  4+3,
               4+3,  4+2,
               4+2,  4+0,
              // A=A0+A1
               0+0,  4+0,
               0+1,  4+1,
               0+2,  4+2,
               0+3,  4+3,
              // B0
               8+0,  8+1,
               8+1,  8+3,
               8+3,  8+2,
               8+2,  8+0,
              // B1
              12+0, 12+1,
              12+1, 12+3,
              12+3, 12+2,
              12+2, 12+0,
              // B=B0+B1
               8+0, 12+0,
               8+1, 12+1,
               8+2, 12+2,
               8+3, 12+3,
              // hyper cube = A+B
               0+0,  8+0,
               0+1,  8+1,
               0+2,  8+2,
               0+3,  8+3,
               0+4,  8+4,
               0+5,  8+5,
               0+6,  8+6,
               0+7,  8+7,
              };
          // 5x simplex per cube
          #define _cube(a0,a1,a2,a3,a4,a5,a6,a7) a1,a2,a4,a7, a0,a1,a2,a4, a2,a4,a6,a7, a1,a2,a3,a7, a1,a4,a5,a7
          // 4D hypercube = 8 cubes
          const int tab_fac[]=
              {
              _cube( 0, 1, 2, 3, 4, 5, 6, 7),
              _cube( 0, 1, 2, 3, 8, 9,10,11),
              _cube( 4, 5, 6, 7,12,13,14,15),
              _cube( 8, 9,10,11,12,13,14,15),
              _cube( 0, 1, 4, 5, 8, 9,12,13),
              _cube( 0, 2, 4, 6, 8,10,12,14),
              _cube( 1, 3, 5, 7, 9,11,13,15),
              _cube( 2, 3, 6, 7,10,11,14,15),
              };
          #undef _cube
          const DWORD tab_col[]=
              {
              //  BBGGRR,    BBGGRR,    BBGGRR,    BBGGRR,    BBGGRR,
              0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000,
              0x0000FF00,0x0000FF00,0x0000FF00,0x0000FF00,0x0000FF00,
              0x000000FF,0x000000FF,0x000000FF,0x000000FF,0x000000FF,
              0x0000FFFF,0x0000FFFF,0x0000FFFF,0x0000FFFF,0x0000FFFF,
              0x00FF00FF,0x00FF00FF,0x00FF00FF,0x00FF00FF,0x00FF00FF,
              0x00FFFF00,0x00FFFF00,0x00FFFF00,0x00FFFF00,0x00FFFF00,
              0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,0x00FFFFFF,
              0x004080FF,0x004080FF,0x004080FF,0x004080FF,0x004080FF,
              };
      
          int i,n;
          vector<4> p;
          rep.reset();
          pnt.num=0; for (i=0,n=sizeof(tab_pnt)/sizeof(tab_pnt[0]);i<n;i++) pnt.add(tab_pnt[i]);
          lin.num=0; for (i=0,n=sizeof(tab_lin)/sizeof(tab_lin[0]);i<n;i++) lin.add(tab_lin[i]);
          fac.num=0; for (i=0,n=sizeof(tab_fac)/sizeof(tab_fac[0]);i<n;i++) fac.add(tab_fac[i]);
          col.num=0; for (i=0,n=sizeof(tab_col)/sizeof(tab_col[0]);i<n;i++) col.add(tab_col[i]);
          }
      //---------------------------------------------------------------------------
      void mesh4D::draw_cut(double w_cut)
          {
          const double _zero=1e-6;
          const int edge2[]={0,1,0,2,0,3,1,2,2,3,3,1,-1}; // simplex wireframe i0,i1
          const int edge3[]={0,1,2,3,0,1,3,1,2,3,2,0,-1}; // simplex triangles i0,i1,i2
          int e,i,j,k,k0,k1,k2,inside[4];
          DWORD rgb;
          vector<4> p[4],q[4];
          vector<3> xyz[4],nor,a,b;
          for (i=0;i<fac.num;)
              {
              rgb=col[i>>2];
              // extrac points (x,y,z,w)
              for (k=0;k<4;k++)
                  {
                  j=fac[i]*4; i++;
                  p[k].a[0]=pnt[j]; j++;
                  p[k].a[1]=pnt[j]; j++;
                  p[k].a[2]=pnt[j]; j++;
                  p[k].a[3]=pnt[j]; j++;
                  // transform
                  rep.l2g(p[k],p[k]);
                  inside[k]=1;
                  }
              // process edge2 and compute cross section cut intersection points
              for (e=0,k=0;edge2[e]>=0;)
                  {
                  k0=edge2[e]; e++;
                  k1=edge2[e]; e++;
                  // fully inside
                  if (fabs(p[k0][3]-w_cut)+fabs(p[k1][3]-w_cut)<=_zero)
                      {
                      if ((k<4)&&(inside[k0])){ q[k]=p[k0]; k++; inside[k0]=0; }
                      if ((k<4)&&(inside[k1])){ q[k]=p[k1]; k++; inside[k1]=0; }
                      continue;
                      }
                  // no intersection
                  if (((p[k0][3]> w_cut)&&(p[k1][3]> w_cut))||((p[k0][3]< w_cut)&&(p[k1][3]< w_cut))) continue;
                  // 1 intersection
                  if (k<4)
                      {
                      q[k]=p[k1]-p[k0];
                      q[k]*=divide(w_cut-p[k0][3],p[k1][3]-p[k0][3]);
                      q[k]+=p[k0];
                      q[k][3]=w_cut;
                      k++;
                      continue;
                      }
                  }
              // 4D -> 3D vector
              for (k0=0;k0<k;k0++) for (k1=0;k1<3;k1++) xyz[k0][k1]=q[k0][k1];
              // render triangle
              if (k==3)
                  {
                  // normal
                  a=xyz[1]-xyz[0];
                  b=xyz[2]-xyz[1];
                  nor.cross(a,b);
                  nor.unit();
                  // render
                  glBegin(GL_TRIANGLES);
                  glNormal3dv(nor.a);
                  glColor4ubv((BYTE*)(&rgb));
                  glVertex3dv(xyz[0].a);
                  glVertex3dv(xyz[1].a);
                  glVertex3dv(xyz[2].a);
                  glEnd();
                  }
              // render simplex
              if (k==4)
               for (e=0;edge3[e]>=0;)
                  {
                  k0=edge3[e]; e++;
                  k1=edge3[e]; e++;
                  k2=edge3[e]; e++;
                  // normal
                  a=xyz[k1]-xyz[k0];
                  b=xyz[k2]-xyz[k1];
                  nor.cross(a,b);
                  nor.unit();
                  // render
                  glBegin(GL_TRIANGLES);
                  glNormal3dv(nor.a);
                  glColor4ubv((BYTE*)(&rgb));
                  glVertex3dv(xyz[k0].a);
                  glVertex3dv(xyz[k1].a);
                  glVertex3dv(xyz[k2].a);
                  glEnd();
                  }
              }
          }
      //---------------------------------------------------------------------------
      void mesh4D::draw(double focal_length,double w_near)
          {
          const int edge3[]={0,1,2,3,0,1,3,1,2,3,2,0,-1}; // simplex triangles i0,i1,i2
          int i,j,k,k0,k1,k2;
          DWORD rgb;
          vector<4> p;
          vector<3> xyz[4],nor,a,b;
      
          // 4D simplexes
          glColor3f(0.3,0.3,0.3);
          for (i=0;i<fac.num;)
              {
              rgb=col[i>>2];
              // extrac points (x,y,z,w)
              for (k=0;k<4;k++)
                  {
                  j=fac[i]*4; i++;
                  p[0]=pnt[j]; j++;
                  p[1]=pnt[j]; j++;
                  p[2]=pnt[j]; j++;
                  p[3]=pnt[j]; j++;
                  // transform
                  rep.l2g(p,p);
                  // perspective projection
                  if (focal_length>0.0)
                      {
                      p[3]-=w_near;
                      if (p[3]>=0.0) p*=divide(focal_length,p[3]+focal_length); else p.zero();
                      }
                  // 4D -> 3D vector
                  xyz[k].ld(p[0],p[1],p[2]);
                  }
              // render simplex
              for (k=0;edge3[k]>=0;)
                  {
                  k0=edge3[k]; k++;
                  k1=edge3[k]; k++;
                  k2=edge3[k]; k++;
                  // normal
                  a=xyz[k1]-xyz[k0];
                  b=xyz[k2]-xyz[k1];
                  nor.cross(a,b);
                  nor.unit();
                  // render
      //          glBegin(GL_LINE_LOOP);
                  glBegin(GL_TRIANGLES);
                  glNormal3dv(nor.a);
                  glColor4ubv((BYTE*)(&rgb));
                  glVertex3dv(xyz[k0].a);
                  glVertex3dv(xyz[k1].a);
                  glVertex3dv(xyz[k2].a);
                  glEnd();
                  }
              }
          }
      //---------------------------------------------------------------------------
      void mesh4D::draw_wireframe(double focal_length,double w_near)
          {
          int i,j,k;
          vector<4> p[4];
          // 4D wireframe
          glColor3f(1.0,1.0,1.0);
          glBegin(GL_LINES);
          for (i=0;i<lin.num;)
              {
              // extrac points (x,y,z,w)
              for (k=0;k<2;k++)
                  {
                  j=lin[i]*4; i++;
                  p[k].a[0]=pnt[j]; j++;
                  p[k].a[1]=pnt[j]; j++;
                  p[k].a[2]=pnt[j]; j++;
                  p[k].a[3]=pnt[j]; j++;
                  // transform
                  rep.l2g(p[k],p[k]);
                  // perspective projection
                  if (focal_length>0.0)
                      {
                      p[k][3]-=w_near;
                      if (p[k][3]>=0.0) p[k]*=divide(focal_length,p[k][3]+focal_length); else p[k].zero();
                      }
                  // render
                  glVertex3dv(p[k].a);    // use just x,y,z
                  }
              }
          glEnd();
          }
      //---------------------------------------------------------------------------
      #endif
      //---------------------------------------------------------------------------
      

      And the preview for cross section render:

      The worst part was to define the hypercube as set of simplexes ...

      这篇关于我应该如何在opengl中处理(变形)4D对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆