我想尝试写一个类似于4D toys的游乐场, 所以我开始学习opengl 根据我目前的理解,人们使用VBO和均匀变换矩阵来处理大多数静态对象 (像立方体,骨骼动画等,通常只涉及转换)
我还听说模型之间的变形也使用VBO来缓存两个模型,因为它们都将被很好地定义而不是中间体。
但是在上面提到的4D玩具中,物体变形和剪裁很多 并且很可能没有定义的模型,并且之间存在许多转换 (现在可能是一个简单的方形,后面夹着一个尖刺的球) 在这种情况下,更新顶点-VPO-每帧或顶点阵列(我在另一个问题中看到)是一个合适的解决方案?
答案 0 :(得分:4)
对于初学者,我会使用4D -> 3D
投影而不是超平面切割。结果不尽相同,但会让你更接近你的目标(所以你可以将后者升级为切入)。所以类似于在图形中使用的3D -> 2D
转换,您有2个选择,一个是使用透视投影,第二个是在渲染时忽略第四个维度坐标。我将使用后者,因为它更简单。
<强>结构强>
为了尽可能简单,我将使用线框而不是 BR 渲染。所以你需要处理4D网格(线框)。我会用2个表:
double pnt[]; // 4D point list (x,y,z,u)
int lin[]; // lines point indexes (i0,i1)
第一个存储网格的所有顶点,第二个存储索引线对以线框表示的线连接。
<强>变换强>
如果我只忽略第4个坐标,那么我们就无法获得所需的功能。因此,为了使第4维工作,我们需要添加 4D 变换以在渲染之前将网格定向在 4D 中。因此,请使用homogenous transform matrix并调用ir rep
。在 4D 中,它应为5x5
正交矩阵,4x4
旋转部分rot
。
为了使这更容易避免现在的平滑旋转(如在4D中那样不那么容易)并且计算随机旋转4x4
矩阵。因此,只需随机设置所有单元格<-1,+1>
。将每一行作为基础向量处理。为了使它们正交,只需使它们成为单位并利用交叉产品。有关详细信息,请参阅:
<强>呈现强>
只需通过变换矩阵转换点表
(x',y',z',u',W) = rep * (x,y,z,u,1)
然后取(x ,y
,z`)并渲染......
这里是4D超立方体的简单OpenGL / C ++示例:
//---------------------------------------------------------------------------
//--- 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
//---------------------------------------------------------------------------
我使用了我的动态list.h
模板:
List<double> xxx;
与double xxx[];
相同
xxx.add(5);
将5
添加到列表的末尾
xxx[7]
访问数组元素(安全)
xxx.dat[7]
访问数组元素(不安全但快速直接访问)
xxx.num
是数组的实际使用大小
xxx.reset()
清除数组并设置xxx.num=0
xxx.allocate(100)
为100
项目预分配空间
nd_math.h
是我的lib用于N维计算。你需要的只是来自线性代数的 4D,5D 向量和4x4
,5x5
矩阵数学。
两个库的大小都有点大,而法律问题也阻止我在这里分享他们的代码。
用法很简单:
// 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();
此处预览了一些rep
轮换......
所以这样你可以渲染任何线框网格(甚至 BR 渲染都应该这样工作)。
如果您想升级到剪切,那么您应该拍摄每个线框线并计算其与切割超平面的交点。如果我们选择经过点的超平面
O(0,0,0,u_cut)
并且正常
N(0,0,0,1)
然后任务将简化很多。有3个选项。让我们考虑带有端点A,B
的边线:
没有交集
((A.u > u_cut)&&(B.u > u_cut)) || ((A.u < u_cut)&&(B.u < u_cut))
忽略这样的边缘
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)
并记住这一点以及它所属的边缘。
完全在
内(A.u == u_cut)&&(B.u == u_cut)
只需记住两个端点,并渲染此边缘。
在以这种方式处理完所有边之后,您需要分析记住的交叉点并根据边之间的连接信息从它们创建新边。我还没有这样做,所以我无法帮助解决这个问题。我会尝试连接共享相同邻居的记忆点,但不确定 4D 中是否足够。
有关详细信息,请查看我刚刚找到的相关 QA :
[Edit1]带透视的代码
//---------------------------------------------------------------------------
//--- 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
//---------------------------------------------------------------------------
预览:
[Edit2]实体网格和横截面
所以我改变了架构。我将 4D 5x5
同质变换矩阵(reper4D
)移动到单独的文件中,并通过4D单面(4点4边四面体)添加颜色和网格定义。切割简单地计算单面和切割超平面的交点(如上所述),得到3个点(三角形),4个点(四面体)或0个点。哪个可以轻松渲染(无需分析边缘之间的连接)。有关详细信息,请参阅:
顺便说一下。我认为这就是Miegakure的工作原理。这里更新了代码:
//---------------------------------------------------------------------------
//--- 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
//---------------------------------------------------------------------------
横截面预览呈现:
最糟糕的是将超立方体定义为单形集...