Vri*_*tra 3 opengl graphics geometry rendering 4d
我想尝试编写类似于4D玩具的游乐场,所以我开始学习opengl。
根据我目前的理解,人们将VBO和统一的转换矩阵用于大多数静态对象
(例如立方体,骨骼动画等,通常只涉及转换)。
我还听说,模型之间的变形也使用VBO来缓存两个模型,因为这两个模型都可以很好地定义并且不需要太多的中间步骤。
但是在上面提到的4D玩具中,物体会发生变形并被大量裁剪。
而且很可能没有定义的模型,并且两者之间有很多转换。
(现在可能是一个简单的正方形,一个尖刺的球在以后被切成两半)。
在这种情况下,每帧更新顶点VBO或顶点数组(我在另一个问题中看到)是合适的解决方案吗?
对于初学者,我将使用4D -> 3D投影而不是通过超平面切割。结果不尽相同,但会使您更接近目标(因此您可以稍后将其升级为削减目标)。因此,就像在3D -> 2D图形转换中一样,您有2种选择,一种是使用透视投影,第二种是在渲染时忽略第4维坐标。我将使用后者,因为它更简单。
结构
为了使这一点尽可能简单,我将使用线框而不是BR渲染。因此,您需要处理4D网格(线框)。我将使用2个表:
double pnt[]; // 4D point list (x,y,z,u)
int lin[]; // lines point indexes (i0,i1)
Run Code Online (Sandbox Code Playgroud)
第一个存储网格物体的所有顶点,第二个存储线对表示中由线连接的点的索引点对。
转换
如果我只忽略第四个坐标,那么我们将无法获得所需的功能。因此,要使第4维起作用,我们需要添加4D变换以在渲染之前将网格定向为4D。因此,请使用同质变换矩阵,并调用ir rep。在4D中,它应该是5x5带有4x4旋转部分的正交矩阵rot。
为了使这一点变得更加容易,现在就避免平滑旋转(就像在4D中那样不那么容易),4x4而是计算随机旋转矩阵。因此,只需随机设置所有单元格即可<-1,+1>。将每一行作为基础向量。要使它们正交,只需使其统一并利用叉积即可。有关更多信息,请参见:
渲染
只需通过转换矩阵转换点表
(x',y',z',u',W) = rep * (x,y,z,u,1)
Run Code Online (Sandbox Code Playgroud)
然后取[x ,y,z`)并渲染...
这里是4D超立方体的简单OpenGL / C ++示例:
double pnt[]; // 4D point list (x,y,z,u)
int lin[]; // lines point indexes (i0,i1)
Run Code Online (Sandbox Code Playgroud)
我使用了我的动态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是我的N维计算库。你需要的仅仅是4D,5D向量和4x4,5x5从线性代数矩阵数学。
这两个库的大小都很大,而且法律问题也阻止了我在这里共享它们的代码。
用法很简单:
(x',y',z',u',W) = rep * (x,y,z,u,1)
Run Code Online (Sandbox Code Playgroud)
在这里预览一些rep旋转...
这样您就可以渲染任何线框网格(即使BR渲染也可以这种方式工作)。
如果要升级到切割,则应采用每条线框线并计算其与切割超平面的交点。如果我们选择通过点的超平面
O(0,0,0,u_cut)
Run Code Online (Sandbox Code Playgroud)
并且正常
N(0,0,0,1)
Run Code Online (Sandbox Code Playgroud)
然后该任务将简化很多。有3个选项。让我们考虑与端点的边线A,B:
没有路口
((A.u > u_cut)&&(B.u > u_cut)) || ((A.u < u_cut)&&(B.u < u_cut))
Run Code Online (Sandbox Code Playgroud)
只是忽略这样的优势
1个路口
((A.u >= u_cut)&&(B.u <= u_cut)) || ((A.u <= u_cut)&&(B.u >= u_cut))
Run Code Online (Sandbox Code Playgroud)
所以通过线性插值计算交点
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)
Run Code Online (Sandbox Code Playgroud)
并记住这一点以及它所属的边缘。
完全在里面
(A.u == u_cut)&&(B.u == u_cut)
Run Code Online (Sandbox Code Playgroud)
只要记住两个端点并渲染该边缘即可。
以这种方式处理所有边缘之后,您需要分析记住的相交点,并根据边缘之间的连通性信息从它们创建新的边缘。我还没有这样做,所以我对此无能为力。我会尝试连接共享同一邻居的记忆点,但不确定4D是否足够。
有关更多信息,请查看我发现或回答的相关质量检查:
[Edit1]具有透视图的代码
//---------------------------------------------------------------------------
//--- 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
//---------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
并预览:
[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;