注意:如果需要转载,请注明作者
作者:陈昱(CY)
最后一章,主要是说明一下面生成的分析,其实这里所有元素,除了0维时的第一个点外,生成都是拉伸产生的(有玩过3Dmax的朋友应该很了解那个Extrude建模,就是那样了)
之前在面结构定义里包含了4个点,这其实无法表达面的真正关系,面还是应该由线来表达。因为面是由线拉伸产生的,和点没有直接的联系。
面的产生中,在进入2维前,都是空的,进入2维的生成后,复制了一批面,新得到的每个面的每一条边分别对应原来每个面的第一条边,再偏移“上一维的线的数量”这样就完成了面的复制部分。拉伸产生的面部分,每个面的第一条边分别是上一维度中的线,第二条边则分别对应“从上一维度复制产生”的线,这两条边有复制和被复制的关系,因此,实际上这时面的4个点已经从这2条边得到了。但是为了下一维度的复制,肯定不能不管后面的2条边,后面的2条边的顶点已经知道了,2条边的第一个点都是上一维度的点,第二个点都是从上一维度复制产生的点,而这2条边则都是从上一维度到当前维度拉伸部分产生的边。于是找到第一条拉伸边,再根据当前面已知的第一条边的2个顶点分别对于第一个顶点的偏移量,就可以分别根据这个偏移量得到该面的第3、第4条边了。
于是到这里,每个维度的点、边、面都是按照这样的结构保存,非常有序,即使面结构中没有保存顶点,也可以根据保存的边直接确定openGL的绘画顺序。
另外,由于需要看到高维体的内部结构,面要弄成半透明的,但是当一个高维体旋转时,面之间会交叉重叠,因此对面的远近排序仍然无法保证每个像素被正确混合渲染。因此,对每一个面加上一个该面的索引数,另外还加上了雾效,都是为了方便眼睛上直觉看懂。
为了播放顺畅,把维度值设在3--8之间。
程序:
HyperCube.rar源文件:
1#pragma once
2#include "mainWindowStyle.h"
3#include "common/Render/CY_Camera.h"
4
5class CSuperCube:public CY_Screen
6{
7 //-----------------------------------------------------------
8 int MaxDim;//维度数量
9 int *PointsCount;
10 int *LinesCount;
11 int *FaceCount;
12 //-----------------------------------------------------------
13
14 float Length;//边长
15 //-----------------------------------------------------------------------------------------
16 bool isDone;//已经可以渲染的标志
17
18 float *Points;//n维空间中的点(以DimensionNum为一组为一个点坐标,PointNum为点数量,所以该float数组大小为DimensionNum*PointNum)
19 int DimensionNum;
20 int PointNum;
21
22 struct SLine
23 {
24 float *points1;
25 float *points2;
26 SLine()
27 {
28 points1=0;
29 points2=0;
30 }
31 };
32 SLine *Lines;//n维空间中的线(以2个点的x坐标索引为起始)
33 int LineNum;
34
35 struct SFace
36 {
37 SLine *line1;
38 SLine *line2;
39 SLine *line3;
40 SLine *line4;
41 SFace()
42 {
43 line1=0;
44 line2=0;
45 line3=0;
46 line4=0;
47 }
48 };
49 int FaceNum;
50 SFace *Faces;//n维空间中的面
51 //---------------------------------------------------------------------------------------------
52 //初始化各个维度的立方体中,点、线、面的数量
53 //输入:maxDim最大维数
54 void InitMaxPLF(int maxDim);
55
56
57 //计算Dim维度下的立方体的点、线、面
58 void CaculatePLF(int Dim);
59 void CaculatePHelp(int currentDim);
60 void CaculateLHelp(int currentDim);
61 void CaculateFHelp(int currentDim);
62
63 //----------------------------------------------------------------------------------------------
64
65 //吉文斯矩阵旋转,
66 //输入:dimNum空间维度(>=2,<=15)、point点指针、theta角度、dim1旋转面的第一个方向、dim2旋转面的第二个方向(值从1---15)
67 //输出:point点的坐标值
68 inline void GivensRotateMatrix(int dimNum,float *point,float theta,int dim1,int dim2);
69
70 void Rotate(float theta,int dim1,int dim2);
71
72 //--------------------------------------------------------------------------------------------
73 SFace **RenderFaces;
74 CGLText *FacesIndexTex;
75
76 void FaceSort();
77
78public:
79 CSuperCube();
80 ~CSuperCube();
81
82 //-----------------------------------
83 CY_TextBox *DimensionInput;
84 CY_Label *InputLabel;
85 CY_Button *CreateBtn;
86 CY_CheckBox *FaceLineRender;
87 CY_Label *Tips1,*Tips2,*Tips3;
88
89 CY_Camera theCamera;
90 //------------------------------------
91
92 unsigned long lastTime;
93 unsigned long currentTime;
94 short lastMousePos[2];
95 void UpDate();
96
97 void DrawScene();
98
99 void LineRender();
100 void FaceRender();
101
102
103 void OnKeyDown();
104 void OnCreateBtnDown(CY_Controller *);
105 void OnMouseWheel(const short &zDalta);
106};
1#include "Screens.h"
2#include <math.h>
3
4float MateriaColor[3][4]={0.9f,0.9f,0.5f,0.2f,
5 0.9f,0.5f,0.9f,0.2f,
6 0.5f,0.9f,0.9f,0.2f};
7CSuperCube::CSuperCube():CY_Screen()
8{
9 isDone=false;
10 Length=50.0f;
11 MaxDim=0;//维度数量
12
13 PointsCount=0;//点数
14 LinesCount=0;//线数
15 FaceCount=0;//面数
16
17 Points=0;//n维空间中的点(以DimensionNum为一组为一个点坐标,PointNum为点数量,所以该float数组大小为DimensionNum*PointNum)
18 DimensionNum=0;
19 PointNum=0;
20
21 Lines=0;//n维空间中的线(以2个点的x坐标索引为起始)
22 LineNum=0;
23
24 Faces=0;
25 FaceNum=0;
26
27 RenderFaces=0;
28 FacesIndexTex=0;
29
30 //------------------------------------------------
31 InputLabel=new CY_Label(L"请输入超立方体维度:",20,20);
32 this->addContent(InputLabel);
33 DimensionInput=new CY_TextBox(160,15,100);
34 DimensionInput->SetNumberic();
35 this->addContent(DimensionInput);
36 CreateBtn=new CY_Button(L"马上生成~~",windowWidth-150,20,100,30);
37 CreateBtn->OnMouseUpEvent.Bind(this,&CSuperCube::OnCreateBtnDown);
38 this->addContent(CreateBtn);
39 FaceLineRender=new CY_CheckBox(400,18,L"线框渲染",true);
40 this->addContent(FaceLineRender);
41 Tips1=new CY_Label(L"操作:主键盘上0控制坐标X,1控制坐标Y,3控制坐标Z,4控制坐标W于此类推。",10,windowHeight-60);
42 Tips2=new CY_Label(L"按住两个坐标键,即可以让物体在这2个坐标组成的平面上旋转,再按住shift键旋转方向相反",10,windowHeight-40);
43 Tips3=new CY_Label(L"按住鼠标键,移动鼠标可以从其它角度观察,鼠标滚轮控制镜头远近",10,windowHeight-20);
44 this->addContent(Tips1);
45 this->addContent(Tips2);
46 this->addContent(Tips3);
47
48 theCamera.SetTargetPosition(Vector3(0,0,0));
49 theCamera.SetPosition(Vector3(0,0,150));
50 theCamera.SetUpVector(Vector3(0,1,0));
51 theCamera.SetMinMaxDistance(100,300);
52 theCamera.SetTargetEnable(true);
53
54
55 currentTime=GetTickCount();
56 lastTime=currentTime;
57 lastMousePos[0]=MousePosition[0];
58 lastMousePos[1]=MousePosition[1];
59 //--------------------------------------------------
60
61 InitMaxPLF(15);
62}
63CSuperCube::~CSuperCube()
64{
65 if (PointsCount) delete []PointsCount;
66 if(LinesCount) delete[]LinesCount;
67 if(FaceCount)delete[]FaceCount;
68
69 if(Points)delete []Points;
70 if(Lines)delete []Lines;
71 if(Faces)delete []Faces;
72
73 if(RenderFaces) delete[]RenderFaces;
74 if(FacesIndexTex)delete []FacesIndexTex;
75}
76//----------------------------------------------------------------------------------------------------------------------------
77void CSuperCube::InitMaxPLF(int maxDim)
78{
79 if (MaxDim || maxDim<3 || maxDim>15)
80 return;
81
82 MaxDim=maxDim+1;
83
84 PointsCount=new int[MaxDim];
85 LinesCount=new int[MaxDim];
86 FaceCount=new int[MaxDim];
87
88 int i;
89
90 PointsCount[0]=1;
91 for (i=1;i<MaxDim;++i)
92 PointsCount[i]=PointsCount[i-1]*2;
93
94 LinesCount[0]=0;
95 LinesCount[1]=1;
96 for (i=2;i<MaxDim;++i)
97 LinesCount[i]=LinesCount[i-1]*2+PointsCount[i-1];
98
99 FaceCount[0]=0;
100 FaceCount[1]=0;
101 FaceCount[2]=1;
102 for(i=3;i<MaxDim;++i)
103 FaceCount[i]=FaceCount[i-1]*2+LinesCount[i-1];
104}
105//------------------------------------------------------------------------------------------------------------------------
106inline void CSuperCube::GivensRotateMatrix(int dimNum,float *point,float theta,int dim1,int dim2)
107{
108 if(dimNum<2 || dimNum>=16 || dim1<0 || dim1>dimNum || dim2<0 ||dim2>dimNum || dim1==dim2)return;
109
110 float temp1=cos(theta);
111 float temp2=sin(theta);
112 float temp=point[dim1]*temp1-point[dim2]*temp2;
113
114 point[dim2]=point[dim1]*temp2+point[dim2]*temp1;
115 point[dim1]=temp;
116}
117void CSuperCube::Rotate(float theta,int dim1,int dim2)
118{
119 for(int i=0;i<PointNum;++i)
120 GivensRotateMatrix(DimensionNum,&Points[i*DimensionNum],theta,dim1,dim2);
121}
122//-----------------------------------------------------------------------------------------------------------------------------
123void CSuperCube::CaculatePHelp(int currentDim)
124{
125 int i;
126 //----------------------点计算
127 if(currentDim==0)
128 return;
129 else
130 {
131 int targetStart=1<<(currentDim-1);//复制的起始点
132 int targetEnd=1<<currentDim;//复制的结束点下一点
133 for (i=targetStart;i<targetEnd;++i)
134 {
135 int index=DimensionNum*i;//目标点的x坐标索引
136 int source=DimensionNum*targetStart;//来源点的x坐标索引负偏移量
137 for (int j=0;j<currentDim-1;++j)
138 {
139 Points[index+j]=Points[index-source+j];//复制
140 }
141 Points[index+currentDim-1]=Length;//新加的维度设为边长
142 }
143 }
144}
145void CSuperCube::CaculateLHelp(int currentDim)
146{
147 //---------------------------边计算
148 if (currentDim==0)return;
149 if(currentDim==1)
150 {
151 Lines[0].points1=&Points[0];
152 Lines[0].points2=&Points[DimensionNum];
153 return;
154 }
155 else
156 {
157 //----------------------------------------------------------复制产生的边
158 int targetStar=LinesCount[currentDim-1];//复制的起始边
159 int targetEnd=LinesCount[currentDim-1]*2;//复制的结束边下一条边
160 for(int i=targetStar;i<targetEnd;++i)
161 {
162 Lines[i].points1=Lines[i-targetStar].points1+DimensionNum*(1<<(currentDim-1));//指针偏移
163 Lines[i].points2=Lines[i-targetStar].points2+DimensionNum*(1<<(currentDim-1));
164 }
165 //------------------------------------------复制部分完成,增加拉伸部分产生的边
166 targetStar=targetEnd;//拉伸边存储起始
167 targetEnd=targetStar+(1<<(currentDim-1));//拉伸边存储结束的下一条边
168 for(int i=targetStar;i<targetEnd;++i)
169 {
170 Lines[i].points1=&Points[(i-targetStar)*DimensionNum];
171 Lines[i].points2=&Points[(i-targetStar*2+targetEnd)*DimensionNum];
172 }
173 }
174}
175void CSuperCube::CaculateFHelp(int currentDim)
176{
177 if(currentDim<2)return;
178 if (currentDim==2)
179 {
180 Faces[0].line1=&Lines[0];
181 Faces[0].line2=&Lines[1];
182 Faces[0].line3=&Lines[2];
183 Faces[0].line4=&Lines[3];
184 }
185 else
186 {
187 int targetStar=FaceCount[currentDim-1];//复制的起始面
188 int targetEnd=FaceCount[currentDim-1]*2;//复制结束面的下一个面
189
190 for(int i=targetStar;i<targetEnd;++i)
191 {
192 Faces[i].line1=Faces[i-targetStar].line1+LinesCount[currentDim-1];//边指针偏移
193 Faces[i].line2=Faces[i-targetStar].line2+LinesCount[currentDim-1];
194 Faces[i].line3=Faces[i-targetStar].line3+LinesCount[currentDim-1];
195 Faces[i].line4=Faces[i-targetStar].line4+LinesCount[currentDim-1];
196 }
197 //-------------面复制完成,增加拉伸产生的面
198 targetStar=targetEnd;//拉伸面存储起始
199 targetEnd=targetStar+LinesCount[currentDim-1];//拉伸面存储结束的下一个面
200 for(int i=targetStar;i<targetEnd;++i)
201 {
202 Faces[i].line1=&Lines[i-targetStar];
203 Faces[i].line2=Faces[i].line1+LinesCount[currentDim-1];
204
205 //非复制边的起始索引:
206 int NoCopyindex=LinesCount[currentDim]-PointsCount[currentDim];
207 //该边的对于非复制边起始索引的偏移量:
208 int offset=(Faces[i].line1->points1-Points)/DimensionNum;
209 Faces[i].line3=&Lines[NoCopyindex+offset];
210 offset=(Faces[i].line1->points2-Points)/DimensionNum;
211 Faces[i].line4=&Lines[NoCopyindex+offset];
212 }
213 }
214}
215void CSuperCube::CaculatePLF(int Dim)
216{
217 if(!MaxDim || Dim<2 || Dim>=MaxDim)return;
218
219 if(isDone)
220 {
221 delete []Points;
222 delete []Lines;
223 delete []Faces;
224 }
225
226 //-------------------------------------分配好内存空间
227 DimensionNum=Dim;
228 PointNum=PointsCount[DimensionNum];
229 LineNum=LinesCount[DimensionNum];
230 FaceNum=FaceCount[DimensionNum];
231
232 Points=new float[PointNum*DimensionNum];
233 for (int i=0;i<PointNum*DimensionNum;++i)
234 {
235 Points[i]=0;
236 }
237
238 Lines=new SLine[LineNum];
239 Faces=new SFace[FaceNum];
240
241 //-------------------------------------计算值
242 int currentDim=0;
243 while (currentDim<=DimensionNum)
244 {
245 CaculatePHelp(currentDim);
246 CaculateLHelp(currentDim);
247 CaculateFHelp(currentDim);
248 ++currentDim;
249 }
250 //-----------------------------------把n维体中心移到原点
251 for(int i=0;i<DimensionNum*PointNum;++i)
252 {
253 Points[i]-=(Length/2);
254 }
255
256 //-----------------------------------
257 if(RenderFaces)
258 delete []RenderFaces;
259 RenderFaces=new SFace*[FaceNum];
260
261 if(FacesIndexTex)delete []FacesIndexTex;
262 FacesIndexTex=new CGLText[FaceNum];
263 for(int i=0;i<FaceNum;++i)
264 {
265 FacesIndexTex[i].SetFont(L"幼圆",60);
266 FacesIndexTex[i].SetColor(1,1,1,0.7f);
267 FacesIndexTex[i].SetReverColor();
268 FacesIndexTex[i].SetText(i);
269 }
270}
271//---------------------------------------------------------------------------------------------------------------------------
272void CSuperCube::UpDate()
273{
274 currentTime=GetTickCount();
275 unsigned long dalta=currentTime-lastTime;
276 lastTime=currentTime;
277
278 int i=-1,j=-1;
279 for (i=0;i<DimensionNum;++i)
280 {
281 if(CY_KeyBoard[48+i])
282 break;
283 }
284 for (j=i+1;j<DimensionNum;++j)
285 {
286 if(CY_KeyBoard[48+j])
287 break;
288 }
289 if(i>=0 && j<DimensionNum)//开始旋转
290 {
291 float theta=dalta*0.0016f;
292 if(CY_KeyBoard[16])//反方向
293 Rotate(-theta,i,j);
294 else
295 Rotate(theta,i,j);
296 }
297 if(CY_MouseKey[0])
298 {
299 theCamera.RotateLeftRight((MousePosition[0]-lastMousePos[0])*0.002f);
300 theCamera.RotateUpDown((MousePosition[1]-lastMousePos[1])*0.002f);
301 }
302 lastMousePos[0]=MousePosition[0];
303 lastMousePos[1]=MousePosition[1];
304}
305void CSuperCube::LineRender()
306{
307 if(!isDone)return;
308 glDisable(GL_LIGHTING);
309 //glDisable(GL_FOG);
310 glLineWidth(3.0f);
311 glColor4f(1,1,1,1.0f);
312 for (int i=0;i<LineNum;++i)
313 {
314 glBegin(GL_LINES);
315 glVertex3fv(Lines[i].points1);
316 glVertex3fv(Lines[i].points2);
317 //glVertex3f(30,30,-10);
318 //glVertex3f(-30,30,10);
319 //glVertex3f(30,-30,0);
320 glEnd();
321 }
322
323}
324void CSuperCube::FaceRender()
325{
326 if(!isDone)return;
327
328
329 for (int i=0;i<FaceNum;++i)
330 {
331 RenderFaces[i]=&Faces[i];
332 }
333 FaceSort();
334
335
336 GLfloat a[] = { 0.0f, 0.0f, 0.0f};
337 float length=VectorLength(theCamera.GetPosition());
338 glFogfv(GL_FOG_COLOR, a);
339 glFogi(GL_FOG_MODE, GL_LINEAR);
340 glFogf(GL_FOG_START,length);
341 glFogf(GL_FOG_END,length+28);
342 glEnable(GL_FOG);
343
344 /**//*GLfloat fLightPos[] = { 50, 50, 200,1.0f};
345 GLfloat light0_ambient[]= { 0.1f, 0.0f, 0.0f, 0.1f };
346 GLfloat light0_diffuse[]= { 0.7f, 0.5f, 0.1f, 0.1f };
347 GLfloat light0_specular[] = { 1, 1, 1, 0.8f };
348 glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
349 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
350 glLightfv(GL_LIGHT0, GL_SPECULAR,light0_specular);
351 glLightfv(GL_LIGHT0, GL_POSITION, fLightPos);
352 glEnable(GL_LIGHTING);
353 glEnable(GL_LIGHT0);*/
354 glDisable(GL_LIGHTING);
355
356 glEnable(GL_BLEND);
357 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
358 //glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR);
359 //glBlendFunc(GL_SRC_ALPHA, GL_ONE);
360 glDisable(GL_DEPTH_TEST);
361
362 //glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,32);
363 //glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,MateriaColor[0]);
364 //glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,MateriaColor[1]);
365 //glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,MateriaColor[2]);
366
367
368 /**//*glBegin(GL_QUADS);
369 glColor4f(0,0,0,1);
370 glVertex3f(-1000,-1000,-500);
371 glVertex3f(1000,-1000,-500);
372 glVertex3f(1000,1000,-500);
373 glVertex3f(-1000,1000,-500);
374 glEnd();*/
375
376 int temp=1;
377 for (int i=0;i<FaceNum;++i)
378 {
379 temp=RenderFaces[i]-Faces;
380 glBindTexture(GL_TEXTURE_2D,FacesIndexTex[temp].GetTextureID());
381 glBegin(GL_QUADS);
382 glColor4fv(MateriaColor[temp%3]);
383 glTexCoord2i(0,0);
384 glVertex3fv(RenderFaces[i]->line1->points1);
385 glTexCoord2i(0,1);
386 glVertex3fv(RenderFaces[i]->line1->points2);
387 glTexCoord2i(1,1);
388 glVertex3fv(RenderFaces[i]->line2->points2);
389 glTexCoord2i(1,0);
390 glVertex3fv(RenderFaces[i]->line2->points1);
391 glEnd();
392 }
393 glBindTexture(GL_TEXTURE_2D,0);
394}
395void CSuperCube::DrawScene()
396{
397 glLoadIdentity();
398 glDisable(GL_CULL_FACE);
399 theCamera.ApplyCamera();
400
401 if(FaceLineRender->GetIsCheck())
402 LineRender();
403 else
404 {
405 glEnable(GL_TEXTURE_2D);
406 FaceRender();
407 //glClear(GL_DEPTH_BUFFER_BIT);
408 glEnable(GL_DEPTH_TEST);
409 LineRender();
410 }
411}
412//--------------------------------------------------------------------------------------------------------------------------------
413void CSuperCube::FaceSort()//冒泡排序,以中点为准,但四边形嵌入的话.
414{
415 SFace *temp;
416 Vector3 frontV=theCamera.GetPosition()*-1;
417 Vector3 ii,jj;
418
419 float value1,value2;
420 for (int i=0;i<FaceNum-1;++i)
421 {
422 ii.x=RenderFaces[i]->line1->points1[0]+RenderFaces[i]->line1->points2[0]+RenderFaces[i]->line2->points1[0]+RenderFaces[i]->line2->points2[0];
423 ii.y=RenderFaces[i]->line1->points1[1]+RenderFaces[i]->line1->points2[1]+RenderFaces[i]->line2->points1[1]+RenderFaces[i]->line2->points2[1];
424 ii.z=RenderFaces[i]->line1->points1[2]+RenderFaces[i]->line1->points2[2]+RenderFaces[i]->line2->points1[2]+RenderFaces[i]->line2->points2[2];
425 ii=ii+frontV;
426 value1=ii*frontV;
427
428
429 for (int j=i+1;j<FaceNum-i;++j)
430 {
431 jj.x=RenderFaces[j]->line1->points1[0]+RenderFaces[j]->line1->points2[0]+RenderFaces[j]->line2->points1[0]+RenderFaces[j]->line2->points2[0];
432 jj.y=RenderFaces[j]->line1->points1[1]+RenderFaces[j]->line1->points2[1]+RenderFaces[j]->line2->points1[1]+RenderFaces[j]->line2->points2[1];
433 jj.z=RenderFaces[j]->line1->points1[2]+RenderFaces[j]->line1->points2[2]+RenderFaces[j]->line2->points1[2]+RenderFaces[j]->line2->points2[2];
434 jj=jj+frontV;
435 value2=jj*frontV;
436
437 if (value1<value2)
438 {
439 temp=RenderFaces[i];
440 RenderFaces[i]=RenderFaces[j];
441 RenderFaces[j]=temp;
442 }
443 }
444 }
445
446}
447//---------------------------------------------------------------------------------------------------------------------------------
448void CSuperCube::OnKeyDown()
449{
450 if(CY_KeyBoard[27])
451 PostMessage(hwnd,WM_CLOSE,0,0);
452}
453void CSuperCube::OnCreateBtnDown(CY_Controller *btn)
454{
455 const wchar_t *content=DimensionInput->GetText();
456 int Dim=_wtoi(content);
457 {
458 if (Dim>=3 && Dim<=8)
459 {
460 if (Dim<=6 || Dim>6 && my_OpenGL_Engine->myScreenManager->Show_CYMessageBox(L"大于6的维度可能会渲染较慢,真的要试试?",true)==true)
461 {
462 CaculatePLF(Dim);
463 isDone=true;
464 }
465 }
466 else
467 my_OpenGL_Engine->myScreenManager->Show_CYMessageBox(L"请输入3--8的维度值",false);
468 }
469
470}
471void CSuperCube::OnMouseWheel(const short &zDalta)
472{
473 theCamera.MoveFontBack(zDalta*0.0002f);
474}
截图:
posted on 2009-08-03 22:29
陈昱(CY) 阅读(2234)
评论(9) 编辑 收藏 引用 所属分类:
图形学 、
算法