您的位置:首页 > 运维架构

OpenGL: 圆柱面绘制贴图

2014-02-26 10:51 281 查看
最近看到dx中的sample中有用顶点数组实现的圆柱体贴图的程序。于是自己写了一个圆柱体的类,支持生成纹理坐标,法线,坐标。构造圆柱体的参数主要有:水平分段数(就是上下圆的分段数目),
高度上的分段数目,(至少有两段:上下两个圆面)
半径,
高度。
顶点生成的原理:将圆柱面展开就是一个矩形。而纹理也是一个矩形区域,需要注意的是圆柱面是一个首尾相接的封闭面。效果图如下:

代码:头文件
#ifndef CYLINDER_H
#define CYLINDER_H

struct Vertex3f
{
	float x; 
	float y;
	float z;

	float nx;
	float ny;
	float nz;

	float u;
	float v;

	void setValue(float x_, float y_, float z_)
	{
		x = x_;
		y = y_;
		z = z_;
	}

	void setNormal(float x_, float y_, float z_)
	{
		nx = x_;
		ny = y_;
		nz = z_;
	}

	void setTexture(float u_, float v_)
	{
		u = u_;
		v = v_;
	}
};

enum REND_MODE
{
	SOLID = 3000,
	WIRE = 3001
};

/*
 *	Cylinder created by RYF. [11/25/2009]
 */
class Cylinder
{
public:
	Cylinder(float r, float h, int l, int v);
	~Cylinder();

	void Render(REND_MODE mode);

	void PrintMatrices();
protected:
	Cylinder(){};
	

	void RenderSlice( const Vertex3f& v1,
   					  const Vertex3f& v2,
					  const Vertex3f& v3,
					  const Vertex3f& v4,
					  int i, int j,			
					  REND_MODE mode );

	void RenderSliceNormal( const Vertex3f& v1, 
					  const Vertex3f& v2, 
					  const Vertex3f& v3, 
					  const Vertex3f& v4 );

	void _getMatrices();
	void _setupVertexTexcoord();
	void _getVertex(float alpha, float hgh, Vertex3f& vertex);

	unsigned int	texId;		//纹理ID
	bool		isHasTex;	//是否加载纹理

	float		radius;		//半径
	float		height;		//高度
	int		lSlice;		//水平分段数
	int		vSlice;		//垂直分段数
	Vertex3f*	pVertexBuffer;	//顶点数据
	float*		pTexcoord;	//最后一列的纹理坐标
};
#endif
cpp文件:
#include "Cylinder.h"
#include <gl/glut.h>
#include <iostream>
#include <iomanip>
#include <cmath>

// ----------------------------------------------------------------
//	Description:	重载构造函数
//	Para info:		r为上下圆的半径
//				h为高度
//				l为上下圆的分段数
//				v为高度上圆柱的段数v>=2
// ----------------------------------------------------------------

Cylinder::Cylinder(float r, float h, int l, int v)
	: radius(r)
	, height(h)
	, lSlice(l)
	, vSlice(v)
	, texId(0)
	, isHasTex(false)
	, pVertexBuffer(0)
	, pTexcoord(0)
{
	pVertexBuffer = new Vertex3f[vSlice*lSlice];
	pTexcoord = new float[vSlice];
	
	_setupVertexTexcoord();
	_getMatrices();
	PrintMatrices();
}

Cylinder::~Cylinder()
{
	if (pVertexBuffer)
	{
		delete pVertexBuffer;
		pVertexBuffer = 0;
	}
}

// ----------------------------------------------------------------
//	Description:	圆柱体绘制函数
//	绘制按照逆时钟:
//		v4		v3
//	
//		v1		v2
// ----------------------------------------------------------------
void Cylinder::Render(REND_MODE mode)
{
	int i(0);
	int j(0);

	// 绘制圆柱体
	for (i=0; i<vSlice-1; i++)
	{
		for (j=0; j<lSlice-1; j++)
		{
			RenderSlice( pVertexBuffer[(i+1)*lSlice+j],
						 pVertexBuffer[(i+1)*lSlice+j+1],			
						 pVertexBuffer[i*lSlice+j+1],
						 pVertexBuffer[i*lSlice+j],	
						 i, j,
						 mode );
		}

		RenderSlice( pVertexBuffer[(i+1)*lSlice+j],		//第二行末端
					 pVertexBuffer[(i+1)*lSlice],		//第二行始端	
		 			 pVertexBuffer[i*lSlice],			//第一行始端
					 pVertexBuffer[i*lSlice+j],			//第一行末端
					 i, j+1,
					 mode );

	}
}

// ----------------------------------------------------------------
//	Description:	绘制四边形函数
//	函数参数顺序:	1 2 3 4
//	GL_TRIANGLE_STRIP的绘制顺序:1 2 4 3
//		四个v参数提供:位置和法线数据
//		i,j提供纹理坐标数据
//		1, 4为要特殊处理的点
// ----------------------------------------------------------------
void Cylinder::RenderSlice( const Vertex3f& v1, 
						    const Vertex3f& v2, 
							const Vertex3f& v3, 
							const Vertex3f& v4,
							int i, int j, 
							REND_MODE mode )
{
	glDisable(GL_LIGHTING);

	switch(mode)
	{
	case SOLID:
		glBegin(GL_TRIANGLE_STRIP);
		//glBegin(GL_POLYGON);
		break;
	case WIRE:
		glBegin(GL_LINE_LOOP);
		break;
	}
		glTexCoord2f( v1.u, v1.v );		
		glVertex3f(v1.x, v1.y, v1.z);	/*glNormal3f(v1.nx, v1.ny, v1.nz);*/	

		//特殊处理v2的配置
		if (j==lSlice)
		{
			glTexCoord2f( 1.0f, pTexcoord[i+1] );		
			glVertex3f(v2.x, v2.y, v2.z);	/*glNormal3f(v2.nx, v2.ny, v2.nz);*/	
		}
		else
		{
			glTexCoord2f( v2.u, v2.v );		
			glVertex3f(v2.x, v2.y, v2.z);	/*glNormal3f(v2.nx, v2.ny, v2.nz);*/	
		}

		glTexCoord2f( v4.u, v4.v );		
		glVertex3f(v4.x, v4.y, v4.z);	/*glNormal3f(v4.nx, v4.ny, v4.nz);*/
		
		//特殊处理v3的配置
		if (j==lSlice)
		{
			glTexCoord2f( 1.0f, pTexcoord[i] );		
			glVertex3f(v3.x, v3.y, v3.z);	/*glNormal3f(v3.nx, v3.ny, v3.nz);*/	
		}
		else
		{
			glTexCoord2f( v3.u, v3.v );		
			glVertex3f(v3.x, v3.y, v3.z);	/*glNormal3f(v3.nx, v3.ny, v3.nz);*/	
		}

	glEnd();

	// 显示法线
	// RenderSliceNormal( v1, v2, v3, v4 );

	glEnable(GL_LIGHTING);
}

void Cylinder::RenderSliceNormal( const Vertex3f& v1, const Vertex3f& v2, const Vertex3f& v3, const Vertex3f& v4 )
{
	glBegin(GL_LINES);
	glVertex3f(v1.x, v1.y, v1.z);	
	glVertex3f(v1.nx + v1.x, v1.ny+v1.y, v1.nz+v1.z);
	glEnd();

	glBegin(GL_LINES);
	glVertex3f(v2.x, v2.y, v2.z);	
	glVertex3f(v2.nx + v2.x, v2.ny+v2.y, v2.nz+v2.z);
	glEnd();

	glBegin(GL_LINES);
	glVertex3f(v3.x, v3.y, v3.z);	
	glVertex3f(v3.nx + v3.x, v3.ny+v3.y, v3.nz+v3.z);
	glEnd();

	glBegin(GL_LINES);
	glVertex3f(v4.x, v4.y, v4.z);	
	glVertex3f(v4.nx + v4.x, v4.ny+v4.y, v4.nz+v4.z);
	glEnd();
}

// ----------------------------------------------------------------
//	Description:	根据vSlice和lSlice生成纹理坐标
//					
// ----------------------------------------------------------------
void Cylinder::_setupVertexTexcoord()
{
	if (!pVertexBuffer || !pTexcoord)
		return;
	
	float ds = 1.0f / lSlice;			//x,u 方向
	float dt = 1.0f / (vSlice-1);		//y,v 方向

	for (int i=0; i<vSlice; i++)
	{
		for (int j=0; j<lSlice; j++)
		{
			pVertexBuffer[j + i*lSlice].u = j*ds;
			pVertexBuffer[j + i*lSlice].v = i*dt;
		}

		// 最后一列的纹理横坐标全部为:1.0
		// pTexcoord中只是纵坐标
		pTexcoord[i] = i * dt;
	}
}

// ----------------------------------------------------------------
//	Description:	根据角度和高度求取顶点的坐标
//	Para info:		theta为弧度数,圆中的角度
//					hgh为高度	
// ----------------------------------------------------------------
void Cylinder::_getVertex(float theta, float hgh, Vertex3f& vertex)
{
	float cosTheta = cos(theta);
	float sinTheta = sin(theta);

	// setup position coordinate
	vertex.x = radius * cosTheta;
	vertex.y = hgh;
	vertex.z = radius * sinTheta;

	// setup normal coordinate
	vertex.nx = cosTheta;
	vertex.ny = 0;
	vertex.nz = sinTheta;
}

// ----------------------------------------------------------------
//	Description:	求取圆柱的顶点阵列
// ----------------------------------------------------------------
void Cylinder::_getMatrices()
{
	const float pi = 3.1415926;

	float angle = 2.0f * pi / static_cast<float>(lSlice);
	// 注意分母为高度段数减1
	float span = height / static_cast<float>(vSlice-1);

	for (int v=0; v<vSlice; v++)
	{
		float y = span * v;
		for (int l=0; l<lSlice; l++)
		{
			float x = angle * static_cast<float>(l);
			_getVertex(x, y, pVertexBuffer[l + v*lSlice]);
		}
	}
}

// ----------------------------------------------------------------
//	Description:	打印matrices中的元素
// ----------------------------------------------------------------
void Cylinder::PrintMatrices()
{
	using namespace std;
	for (int i=0; i<vSlice*lSlice; i++)
	{
		cout << "//---------------------------------------------------------------------" << endl;
		cout << "row = " << i / lSlice << ".";
		cout << "coll = " << i % lSlice << endl;

		cout << "position(x, y, z) = " << setprecision (7) << pVertexBuffer[i].x << " "
									   << setprecision (7) << pVertexBuffer[i].y << " "
									   << setprecision (7) << pVertexBuffer[i].z << endl;

		cout << "texture(u, v) = " << setprecision (7) << pVertexBuffer[i].u << " "
								   << setprecision (7) << pVertexBuffer[i].v << endl;
		cout << "//---------------------------------------------------------------------" << endl;
	}
}
测试程序如下,要运行起来,还必须加一个bmpLoader的程序库,可以到这里下载一个简单的,里面有自带的bmp图片。http://users.ox.ac.uk/~orie1330/bmploader.html代码:
#include <GL/glut.h>
#include <cstdio>
#include <cstdlib>
#include "Cylinder.h"

#include "BMPLoader.h"

/*	Create checkerboard texture	*/
#define	checkImageWidth 64
#define	checkImageHeight 64
static GLubyte checkImage[checkImageHeight][checkImageWidth][4];

static GLuint texName;

Cylinder		g_cylinder(0.5f, 1.3f, 30, 5);
static float	angleX = 0.0f;
static float	angleY = 0.0f;
//////////////////////////////////////////////////////////////////////////
void makeCheckImage(void)
{
	int i, j, c;

	for (i = 0; i < checkImageHeight; i++) {
		for (j = 0; j < checkImageWidth; j++) {
			c = ((((i&0x8)==0)^((j&0x8))==0))*255;
			checkImage[i][j][0] = (GLubyte) c;
			checkImage[i][j][1] = (GLubyte) c;
			checkImage[i][j][2] = (GLubyte) c;
			checkImage[i][j][3] = (GLubyte) 255;
		}
	}
}

void init(void)
{    
	glClearColor (0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);

 	//makeCheckImage();
	BMPClass bmp;
	BMPLoad("bmp16.bmp", bmp);

 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
 	glGenTextures(1, &texName);
 	glBindTexture(GL_TEXTURE_2D, texName);
 
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
/*
 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 
 		0, GL_RGBA, GL_UNSIGNED_BYTE, / *checkImage* /bmp.bytes);
*/
	glTexImage2D(GL_TEXTURE_2D,0,3,bmp.width,bmp.height,0,GL_RGB,GL_UNSIGNED_BYTE,bmp.bytes);
}

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glEnable(GL_TEXTURE_2D);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glBindTexture(GL_TEXTURE_2D, texName);

	glPushMatrix();
	{
		glRotatef(angleX, 1.0f, 0.0f, 0.0f);
		glRotatef(angleY, 0.0f, 1.0f, 0.0f);
		g_cylinder.Render(SOLID);
	}glPopMatrix();

	glutSwapBuffers();	
	glDisable(GL_TEXTURE_2D);

	glutPostRedisplay();
}

void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -3.6f);
}

void keyboard (unsigned char key, int x, int y)
{
	switch (key) {
	  case 27:
		  exit(0);
		  break;

	  case 'x':
		  angleX += 5.0f;
		  break;
	  case 's':
		  angleX -= 5.0f;

	  case 'y':
		  angleY += 4.0f;
		  break;

	  case 'h':
		  angleY -= 4.0f;
		  break;

	  default:
		  break;
	}

	glutPostRedisplay();
}

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(250, 250);
	glutInitWindowPosition(100, 100);
	glutCreateWindow(argv[0]);
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutMainLoop();

	return 0; 
}
PS:OpenGL绘制什么都得DIY。/article/1342262.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: