先上效果图
通过坐标的控件可以控制球体的移动,可以设置是否有光照及实体图,还可控制球的大小和球面级数
1.球体的绘制
void Cm03qiuView::DrawGeometry()
{
//在此处画球体
GLfloat r = (GLfloat)m_nRadius;
GLfloat vdata[6][3] = { //初始点坐标
{r,0.0,0.0},{-r,0.0,0.0},
{0.0,r,0.0},{0.0,-r,0.0},
{0.0,0.0,r},{0.0,0.0,-r}
};
GLuint tindices[8][3] = {//初始面的构造
{2,4,0},{2,0,5},{2,5,1},{2,1,4},
{3,0,4},{3,5,0},{3,1,5},{3,4,1}
};
/*以下坐标是参考书上的初值,为正20面体,效果会比自定义的要好些
const float X = (float)0.525731112119133606*m_nRadius;
const float Z = (float)0.850650808352039932*m_nRadius;
static GLfloat vdata[12][3] = {
{-X,0.0,Z},{X,0.0,Z},{-X,0.0,-Z},{X,0.0,-Z},
{0.0,Z,X},{0.0,Z,-X},{0.0,-Z,X},{0.0,-Z,-X},
{Z,X,0.0},{-Z,X,0.0},{Z,-X,0.0},{-Z,-X,0.0}
};
static GLuint tindices[20][3] = {
{0,4,1},{0,9,4},{9,5,4},{4,5,8},{4,8,1},
{8,10,1},{8,3,10},{5,3,8},{5,2,3},{2,7,3},
{7,10,3},{7,6,10},{7,11,6},{11,0,6},{0,1,6},
{6,1,10},{9,0,11},{9,11,2},{9,2,5},{7,2,11}
};*/
for(int i = 0; i < 8; i++){
SubDivide(&vdata[tindices[i][0]][0],
&vdata[tindices[i][1]][0],
&vdata[tindices[i][2]][0],m_nCount);
}
}
2.控制球面级数,级数越大,绘制出的图像越接近球体
void Cm03qiuView::SubDivide(float *v1, float *v2, float *v3, int count)
{
//把count为级数,对一个三角形面的子划分
if(0 >= count) //count=0,则画由三点构成的三角形
{
DrawTriangle(v1,v2,v3);
}
else
{
GLfloat v12[3],v23[3],v31[3];
GLint i;
for(i = 0; i < 3; i++){
v12[i] = (v1[i]+v2[i])/2;
v23[i] = (v2[i]+v3[i])/2;
v31[i] = (v3[i]+v1[i])/2;
}
Normalize(v12,(float)m_nRadius); //扩展模长
Normalize(v23,(float)m_nRadius);
Normalize(v31,(float)m_nRadius);
SubDivide(v1,v12,v31,count-1);
SubDivide(v2,v23,v12,count-1);
SubDivide(v3,v31,v23,count-1);
SubDivide(v12,v23,v31,count-1);
}
}
void Cm03qiuView::DrawTriangle(float *v1, float *v2, float *v3)
{
//以三点为顶点画三角形
GLfloat normal[3] = {0,0,0};
NormalTriangle(v1,v2,v3,normal);//求取面法向量
glBegin(m_nPattern);
glNormal3fv(normal);
glVertex3fv(v1);
glVertex3fv(v2);
glVertex3fv(v3);
glEnd();
}
void Cm03qiuView::Normalize(float *v, float radius)
{
//向量的标准化,以模长为radius进行标准化
GLfloat d = (GLfloat)sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
if(d == 0.0){
return ;
}
v[0] /= d; v[1] /= d; v[2] /= d;
v[0] *= radius; v[1] *= radius; v[2] *= radius;
}
void Cm03qiuView::NormalTriangle(float *v1, float *v2, float *v3, float *vout)
{
//求三点构成的三角形面的法向量
GLfloat v12[3],v23[3];
for(int i = 0; i < 3; i++){
v12[i] = v2[i] - v1[i];
v23[i] = v3[i] - v2[i];
}
vout[0] = v12[1]*v23[2] - v12[2]*v23[1];
vout[1] = -(v12[0]*v23[2] - v12[2]*v23[0]);
vout[2] = v12[0]*v23[1] - v12[1]*v23[0];
Normalize(vout,1);
}
3.球体的显示与平移旋转缩放控制
void Cm03qiuView::DrawScene()
{
//在屏幕上显出图形
if(m_hglrc) //设置当前绘图设备为OpenGL的设备情景对象
wglMakeCurrent(m_pDC->GetSafeHdc(),m_hglrc);
else
return;
glDrawBuffer(GL_BACK); //指定在后台缓存中绘制图形
glLoadIdentity(); //初始化变换矩阵
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glShadeModel(GL_SMOOTH);
//光照
GLfloat mat_ambient[]= { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat mat_diffuse[]= { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat mat_specular[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat mat_shininess[] = { 50.0f };
GLfloat light_diffuse[]= { 0.0, 1.0, 0.0, 1.0};
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
if(0 == m_nLighting)
glDisable(GL_LIGHTING);
else
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
//变换
glTranslated(m_fTranslateX,0.0,0.0);
glTranslated(0.0,m_fTranslateY,0.0);
glTranslated(0.0,0.0,m_fTranslateZ);
glRotated(m_fRotateX,1.0,0.0,0.0);
glRotated(m_fRotateY,0.0,1.0,0.0);
glRotated(m_fRotateZ,0.0,0.0,1.0);
//画图
DrawGeometry();
//画图结束
glPopMatrix();
glFinish(); //结束整个绘制
SwapBuffers(wglGetCurrentDC()); //交换前后缓存
glDrawBuffer(GL_FRONT); //绘制前景
}
4.调整窗口模块,防止图像变形
void Cm03qiuView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
//设置视口大小
glViewport(0,0,cx,cy);
glMatrixMode(GL_PROJECTION); //投影变换
glLoadIdentity();
if(cx <= cy) //根据窗口大小调整正射投影矩阵
glOrtho(-20.0,20.0,-20.0*(GLfloat)cy/(GLfloat)cx,
20.0*(GLfloat)cy/(GLfloat)cx,-50.0,50.0);
else
glOrtho(-20.0*(GLfloat)cx/(GLfloat)cy,
20.0*(GLfloat)cx/(GLfloat)cy,-20.0,20.0,-50.0,50.0);
glMatrixMode(GL_MODELVIEW); //这二句不能少,否则图形看不出效果
glLoadIdentity(); //设置变换模式为模型变换
}
5.初始化球体参数
Cm03qiuDoc::Cm03qiuDoc()
{
// TODO: add one-time construction code here
m_nRadius = 10;
m_nCount = 4;
m_nPattern = 0;
m_nLighting = 0;
m_fTranslateX = 0.1f;
m_fTranslateY = 0.1f;
m_fTranslateZ = 0.1f;
m_fRotateX = 1.0f;
m_fRotateY = 1.0f;
m_fRotateZ = 1.0f;
}
完整代码可添加QQ获取
1173953942 备注球体即可