注意:如果需要转载,请注明作者
作者:陈昱(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
5
class 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
78
public:
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
4
float 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};
7
CSuperCube::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
}
63
CSuperCube::~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
//----------------------------------------------------------------------------------------------------------------------------
77
void 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
//------------------------------------------------------------------------------------------------------------------------
106
inline 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
}
117
void 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
//-----------------------------------------------------------------------------------------------------------------------------
123
void 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
}
145
void 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
}
175
void 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
}
215
void 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
//---------------------------------------------------------------------------------------------------------------------------
272
void 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
}
305
void 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
}
324
void 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
}
395
void 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
//--------------------------------------------------------------------------------------------------------------------------------
413
void 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
//---------------------------------------------------------------------------------------------------------------------------------
448
void CSuperCube::OnKeyDown()
449

{
450
if(CY_KeyBoard[27])
451
PostMessage(hwnd,WM_CLOSE,0,0);
452
}
453
void 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
}
471
void CSuperCube::OnMouseWheel(const short &zDalta)
472

{
473
theCamera.MoveFontBack(zDalta*0.0002f);
474
}
截图:

posted on 2009-08-03 22:29
陈昱(CY) 阅读(2244)
评论(9) 编辑 收藏 引用 所属分类:
图形学 、
算法