首页 > 代码库 > 从头开始绘制一个圆锥体

从头开始绘制一个圆锥体

opengl帮助库glu里有一个对象叫做二次几何体,可以用来给球体圆锥体建模,然而在opengles中不能使用glu库,那么我们只能自己写方法替代它了,上次给球体建了模,这次应该给圆锥体建模了.

圆锥体是平面上的一个圆以及它的所有切线和平面外一点确定的平面围成的几何体,圆被称为底面,顶点被称为尖端,定义听上去有些复杂,那么看图:


嗯,懂了吧.其实它是一种特殊情况,如果尖端是一个圆面的话那么它就是一个截头圆锥体,顶面半径为0的截头圆锥体就是圆锥体了.

先来看下头文件是怎么定义的吧:

class Cone {
private:
	GLuint* vboId;
	GLuint vert,texcoord,norm;
	GLfloat* verts;
	GLfloat* texcoords;
	GLfloat* norms;
	int vertNum,topVertNum,sideVertNum;
	float radiusTop,radiusBottom,yHeight;//顶面半径,底面半径,高度
	void calculateSideNormal(float& x,float& y,float& z);//计算侧面法线
public:
	Cone(float rt,float rb,int m,float height);
	~Cone();
	void render();
};

侧面法线的计算方法,先取底面任意一点,求得圆心到该点的向量,然后沿着此向量把该截头圆锥体劈开,如图所示


然后把红色的向量沿着它的方向平移到圆周上的点,如图所示:


利用相似三角形即可求出紫色的法线N,具体代码如下:

void Cone::calculateSideNormal(float& x,float& y,float& z) {
	y=(radiusBottom-radiusTop)/yHeight*sqrtf(x*x+z*z);
	if(x==0.0&&z==0.0)
		y=1.0;
}
这边的(x,y,z)就是法向量了,x和z都是圆周上那点的坐标(x,z),y依靠相似三角形可以求出

接着是具体的建模代码:

Cone::Cone(float rt,float rb,int m,float height) {
	radiusTop=rt;
	radiusBottom=rb;
	yHeight=height;

	vertNum=m*3*2+m*4;
	topVertNum=m*3*2;
	sideVertNum=m*4;

	verts=new GLfloat[vertNum*3];
	norms=new GLfloat[vertNum*3];
	texcoords=new GLfloat[vertNum*2];

	float stepAngZ=PI2/m;
	float angZ=0.0;

	int index=0;
	int indexNorm=0;
	int indexTex=0;
	for(int i=0;i<m;i++) {
		//bottom
		float x1=cos(angZ)*rb;
		float y1=0.0;
		float z1=sin(angZ)*rb;
		verts[index]=x1; index++;
		verts[index]=y1; index++;
		verts[index]=z1; index++;
		float nx1=0.0;
		float ny1=-1.0;
		float nz1=0.0;
		norms[indexNorm]=nx1; indexNorm++;
		norms[indexNorm]=ny1; indexNorm++;
		norms[indexNorm]=nz1; indexNorm++;
		float u1=angZ/PI2;
		float v1=1.0;
		texcoords[indexTex]=u1; indexTex++;
		texcoords[indexTex]=v1; indexTex++;

		float x2=cos(angZ+stepAngZ)*rb;
		float y2=0.0;
		float z2=sin(angZ+stepAngZ)*rb;
		verts[index]=x2; index++;
		verts[index]=y2; index++;
		verts[index]=z2; index++;
		norms[indexNorm]=nx1; indexNorm++;
		norms[indexNorm]=ny1; indexNorm++;
		norms[indexNorm]=nz1; indexNorm++;
		float u2=(angZ+stepAngZ)/PI2;
		float v2=1.0;
		texcoords[indexTex]=u2; indexTex++;
		texcoords[indexTex]=v2; indexTex++;

		float x3=0.0;
		float y3=0.0;
		float z3=0.0;
		verts[index]=x3; index++;
		verts[index]=y3; index++;
		verts[index]=z3; index++;
		norms[indexNorm]=nx1; indexNorm++;
		norms[indexNorm]=ny1; indexNorm++;
		norms[indexNorm]=nz1; indexNorm++;
		float u3=0.0;
		float v3=0.0;
		texcoords[indexTex]=u3; indexTex++;
		texcoords[indexTex]=v3; indexTex++;

		//top
		float x4=cos(angZ+stepAngZ)*rt;
		float y4=height;
		float z4=sin(angZ+stepAngZ)*rt;
		verts[index]=x4; index++;
		verts[index]=y4; index++;
		verts[index]=z4; index++;
		float nx4=0.0;
		float ny4=1.0;
		float nz4=0.0;
		norms[indexNorm]=nx4; indexNorm++;
		norms[indexNorm]=ny4; indexNorm++;
		norms[indexNorm]=nz4; indexNorm++;
		float u4=(angZ+stepAngZ)/PI2;
		float v4=1.0;
		texcoords[indexTex]=u4; indexTex++;
		texcoords[indexTex]=v4; indexTex++;

		float x5=cos(angZ)*rt;
		float y5=height;
		float z5=sin(angZ)*rt;
		verts[index]=x5; index++;
		verts[index]=y5; index++;
		verts[index]=z5; index++;
		norms[indexNorm]=nx4; indexNorm++;
		norms[indexNorm]=ny4; indexNorm++;
		norms[indexNorm]=nz4; indexNorm++;
		float u5=angZ/PI2;
		float v5=1.0;
		texcoords[indexTex]=u5; indexTex++;
		texcoords[indexTex]=v5; indexTex++;

		float x6=0.0;
		float y6=height;
		float z6=0.0;
		verts[index]=x6; index++;
		verts[index]=y6; index++;
		verts[index]=z6; index++;
		norms[indexNorm]=nx4; indexNorm++;
		norms[indexNorm]=ny4; indexNorm++;
		norms[indexNorm]=nz4; indexNorm++;
		float u6=0.0;
		float v6=0.0;
		texcoords[indexTex]=u6; indexTex++;
		texcoords[indexTex]=v6; indexTex++;

		angZ+=stepAngZ;
	}

	angZ=0.0;
	for(int i=0;i<m;i++) {
		//side
		float x7=cos(angZ+stepAngZ)*rb;
		float y7=0.0;
		float z7=sin(angZ+stepAngZ)*rb;
		verts[index]=x7; index++;
		verts[index]=y7; index++;
		verts[index]=z7; index++;
		float nx7=x7;
		float ny7=0;
		float nz7=z7;
		calculateSideNormal(nx7,ny7,nz7);
		norms[indexNorm]=nx7; indexNorm++;
		norms[indexNorm]=ny7; indexNorm++;
		norms[indexNorm]=nz7; indexNorm++;
		float u7=(angZ+stepAngZ)/PI2;
		float v7=1.0;
		texcoords[indexTex]=u7; indexTex++;
		texcoords[indexTex]=v7; indexTex++;

		float x8=cos(angZ)*rb;
		float y8=0.0;
		float z8=sin(angZ)*rb;
		verts[index]=x8; index++;
		verts[index]=y8; index++;
		verts[index]=z8; index++;
		float nx8=x8;
		float ny8=0;
		float nz8=z8;
		calculateSideNormal(nx8,ny8,nz8);
		norms[indexNorm]=nx8; indexNorm++;
		norms[indexNorm]=ny8; indexNorm++;
		norms[indexNorm]=nz8; indexNorm++;
		float u8=angZ/PI2;
		float v8=1.0;
		texcoords[indexTex]=u8; indexTex++;
		texcoords[indexTex]=v8; indexTex++;

		float x10=cos(angZ)*rt;
		float y10=height;
		float z10=sin(angZ)*rt;
		verts[index]=x10; index++;
		verts[index]=y10; index++;
		verts[index]=z10; index++;
		float nx10=x10;
		float ny10=0;
		float nz10=z10;
		calculateSideNormal(nx10,ny10,nz10);
		norms[indexNorm]=nx10; indexNorm++;
		norms[indexNorm]=ny10; indexNorm++;
		norms[indexNorm]=nz10; indexNorm++;
		float u10=angZ/PI2*rt/rb;
		float v10=0.0;
		texcoords[indexTex]=u10; indexTex++;
		texcoords[indexTex]=v10; indexTex++;

		float x11=cos(angZ+stepAngZ)*rt;
		float y11=height;
		float z11=sin(angZ+stepAngZ)*rt;
		verts[index]=x11; index++;
		verts[index]=y11; index++;
		verts[index]=z11; index++;
		float nx11=x11;
		float ny11=0;
		float nz11=z11;
		calculateSideNormal(nx11,ny11,nz11);
		norms[indexNorm]=nx11; indexNorm++;
		norms[indexNorm]=ny11; indexNorm++;
		norms[indexNorm]=nz11; indexNorm++;
		float u11=(angZ+stepAngZ)/PI2*rt/rb;
		float v11=0.0;
		texcoords[indexTex]=u11; indexTex++;
		texcoords[indexTex]=v11; indexTex++;

		angZ+=stepAngZ;
	}

	vboId=new GLuint[3];
	vert=0;
	texcoord=1;
	norm=2;
	glGenBuffers(3,vboId);
	glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId[vert]);
	glBufferData(GL_ARRAY_BUFFER_ARB, vertNum*3*sizeof(GLfloat),
			verts, GL_STATIC_DRAW_ARB);
	glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId[texcoord]);
	glBufferData(GL_ARRAY_BUFFER_ARB, vertNum*2*sizeof(GLfloat),
			texcoords, GL_STATIC_DRAW_ARB);
	glBindBuffer(GL_ARRAY_BUFFER_ARB, vboId[norm]);
	glBufferData(GL_ARRAY_BUFFER_ARB, vertNum*3*sizeof(GLfloat),
			norms, GL_STATIC_DRAW_ARB);
	delete[] verts;
	delete[] texcoords;
	delete[] norms;
}

和上次球体的代码很像,纹理坐标底面与顶面的变化程度一致以防贴图分布不均匀.

这样模型就建立完成了,渲染效果如下所示:


从头开始绘制一个圆锥体