计算机图形学(五)——opengl实现MFC界面下的三维球体的绘制

先上效果图

在这里插入图片描述
在这里插入图片描述

通过坐标的控件可以控制球体的移动,可以设置是否有光照及实体图,还可控制球的大小和球面级数

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 备注球体即可

  • 7
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值