OpenGL圆柱面绘制贴图

最近看到dx中的sample中有用顶点数组实现的圆柱体贴图的程序。于是自己写了一个圆柱体的类,支持生成纹理坐标,法线,坐标。

构造圆柱体的参数主要有:

  • 水平分段数(就是上下圆的分段数目),
  • 高度上的分段数目,(至少有两段:上下两个圆面)
  • 半径,
  • 高度。

顶点生成的原理:将圆柱面展开就是一个矩形。而纹理也是一个矩形区域,需要注意的是圆柱面是一个首尾相接的封闭面。

效果图如下:

代码:

头文件

  1. #ifndef CYLINDER_H   
  2. #define CYLINDER_H   
  3.   
  4. struct Vertex3f  
  5. {  
  6.     float x;   
  7.     float y;  
  8.     float z;  
  9.   
  10.     float nx;  
  11.     float ny;  
  12.     float nz;  
  13.   
  14.     float u;  
  15.     float v;  
  16.   
  17.     void setValue(float x_, float y_, float z_)  
  18.     {  
  19.         x = x_;  
  20.         y = y_;  
  21.         z = z_;  
  22.     }  
  23.   
  24.     void setNormal(float x_, float y_, float z_)  
  25.     {  
  26.         nx = x_;  
  27.         ny = y_;  
  28.         nz = z_;  
  29.     }  
  30.   
  31.     void setTexture(float u_, float v_)  
  32.     {  
  33.         u = u_;  
  34.         v = v_;  
  35.     }  
  36. };  
  37.   
  38.   
  39. enum REND_MODE  
  40. {  
  41.     SOLID = 3000,  
  42.     WIRE = 3001  
  43. };  
  44.   
  45. /* 
  46.  *  Cylinder created by RYF. [11/25/2009] 
  47.  */  
  48. class Cylinder  
  49. {  
  50. public:  
  51.     Cylinder(float r, float h, int l, int v);  
  52.     ~Cylinder();  
  53.   
  54.     void Render(REND_MODE mode);  
  55.   
  56.     void PrintMatrices();  
  57. protected:  
  58.     Cylinder(){};  
  59.       
  60.   
  61.     void RenderSlice( const Vertex3f& v1,  
  62.                       const Vertex3f& v2,  
  63.                       const Vertex3f& v3,  
  64.                       const Vertex3f& v4,  
  65.                       int i, int j,           
  66.                       REND_MODE mode );  
  67.   
  68.     void RenderSliceNormal( const Vertex3f& v1,   
  69.                       const Vertex3f& v2,   
  70.                       const Vertex3f& v3,   
  71.                       const Vertex3f& v4 );  
  72.   
  73.     void _getMatrices();  
  74.     void _setupVertexTexcoord();  
  75.     void _getVertex(float alpha, float hgh, Vertex3f& vertex);  
  76.   
  77.     unsigned int    texId;      //纹理ID   
  78.     bool            isHasTex;   //是否加载纹理   
  79.   
  80.     float       radius;             //半径   
  81.     float       height;             //高度   
  82.     int         lSlice;             //水平分段数   
  83.     int         vSlice;             //垂直分段数   
  84.     Vertex3f*   pVertexBuffer;      //顶点数据   
  85.     float*      pTexcoord;          //最后一列的纹理坐标   
  86. };  
  87. #endif  

cpp文件:

  1. #include "Cylinder.h"   
  2. #include <gl/glut.h>   
  3. #include <iostream>   
  4. #include <iomanip>   
  5. #include <cmath>   
  6.   
  7. // ----------------------------------------------------------------   
  8. //  Description:    重载构造函数   
  9. //  Para info:      r为上下圆的半径   
  10. //                  h为高度   
  11. //                  l为上下圆的分段数   
  12. //                  v为高度上圆柱的段数v>=2   
  13. // ----------------------------------------------------------------   
  14.   
  15. Cylinder::Cylinder(float r, float h, int l, int v)  
  16.     : radius(r)  
  17.     , height(h)  
  18.     , lSlice(l)  
  19.     , vSlice(v)  
  20.     , texId(0)  
  21.     , isHasTex(false)  
  22.     , pVertexBuffer(0)  
  23.     , pTexcoord(0)  
  24. {  
  25.     pVertexBuffer = new Vertex3f[vSlice*lSlice];  
  26.     pTexcoord = new float[vSlice];  
  27.       
  28.     _setupVertexTexcoord();  
  29.     _getMatrices();  
  30.     PrintMatrices();  
  31. }  
  32.   
  33. Cylinder::~Cylinder()  
  34. {  
  35.     if (pVertexBuffer)  
  36.     {  
  37.         delete pVertexBuffer;  
  38.         pVertexBuffer = 0;  
  39.     }  
  40. }  
  41.   
  42. // ----------------------------------------------------------------   
  43. //  Description:    圆柱体绘制函数   
  44. //  绘制按照逆时钟:   
  45. //      v4      v3   
  46. //     
  47. //      v1      v2   
  48. // ----------------------------------------------------------------   
  49. void Cylinder::Render(REND_MODE mode)  
  50. {  
  51.     int i(0);  
  52.     int j(0);  
  53.   
  54.     // 绘制圆柱体   
  55.     for (i=0; i<vSlice-1; i++)  
  56.     {  
  57.         for (j=0; j<lSlice-1; j++)  
  58.         {  
  59.             RenderSlice( pVertexBuffer[(i+1)*lSlice+j],  
  60.                          pVertexBuffer[(i+1)*lSlice+j+1],             
  61.                          pVertexBuffer[i*lSlice+j+1],  
  62.                          pVertexBuffer[i*lSlice+j],   
  63.                          i, j,  
  64.                          mode );  
  65.         }  
  66.   
  67.         RenderSlice( pVertexBuffer[(i+1)*lSlice+j],     //第二行末端   
  68.                      pVertexBuffer[(i+1)*lSlice],       //第二行始端    
  69.                      pVertexBuffer[i*lSlice],           //第一行始端   
  70.                      pVertexBuffer[i*lSlice+j],         //第一行末端   
  71.                      i, j+1,  
  72.                      mode );  
  73.   
  74.     }  
  75. }  
  76.   
  77. // ----------------------------------------------------------------   
  78. //  Description:    绘制四边形函数   
  79. //  函数参数顺序: 1 2 3 4   
  80. //  GL_TRIANGLE_STRIP的绘制顺序:1 2 4 3   
  81. //      四个v参数提供:位置和法线数据   
  82. //      i,j提供纹理坐标数据   
  83. //      1, 4为要特殊处理的点   
  84. // ----------------------------------------------------------------   
  85. void Cylinder::RenderSlice( const Vertex3f& v1,   
  86.                             const Vertex3f& v2,   
  87.                             const Vertex3f& v3,   
  88.                             const Vertex3f& v4,  
  89.                             int i, int j,   
  90.                             REND_MODE mode )  
  91. {  
  92.     glDisable(GL_LIGHTING);  
  93.   
  94.     switch(mode)  
  95.     {  
  96.     case SOLID:  
  97.         glBegin(GL_TRIANGLE_STRIP);  
  98.         //glBegin(GL_POLYGON);   
  99.         break;  
  100.     case WIRE:  
  101.         glBegin(GL_LINE_LOOP);  
  102.         break;  
  103.     }  
  104.         glTexCoord2f( v1.u, v1.v );       
  105.         glVertex3f(v1.x, v1.y, v1.z);   /*glNormal3f(v1.nx, v1.ny, v1.nz);*/      
  106.   
  107.         //特殊处理v2的配置   
  108.         if (j==lSlice)  
  109.         {  
  110.             glTexCoord2f( 1.0f, pTexcoord[i+1] );         
  111.             glVertex3f(v2.x, v2.y, v2.z);   /*glNormal3f(v2.nx, v2.ny, v2.nz);*/      
  112.         }  
  113.         else  
  114.         {  
  115.             glTexCoord2f( v2.u, v2.v );       
  116.             glVertex3f(v2.x, v2.y, v2.z);   /*glNormal3f(v2.nx, v2.ny, v2.nz);*/      
  117.         }  
  118.   
  119.         glTexCoord2f( v4.u, v4.v );       
  120.         glVertex3f(v4.x, v4.y, v4.z);   /*glNormal3f(v4.nx, v4.ny, v4.nz);*/  
  121.           
  122.         //特殊处理v3的配置   
  123.         if (j==lSlice)  
  124.         {  
  125.             glTexCoord2f( 1.0f, pTexcoord[i] );       
  126.             glVertex3f(v3.x, v3.y, v3.z);   /*glNormal3f(v3.nx, v3.ny, v3.nz);*/      
  127.         }  
  128.         else  
  129.         {  
  130.             glTexCoord2f( v3.u, v3.v );       
  131.             glVertex3f(v3.x, v3.y, v3.z);   /*glNormal3f(v3.nx, v3.ny, v3.nz);*/      
  132.         }  
  133.   
  134.     glEnd();  
  135.   
  136.     // 显示法线   
  137.     // RenderSliceNormal( v1, v2, v3, v4 );   
  138.   
  139.     glEnable(GL_LIGHTING);  
  140. }  
  141.   
  142. void Cylinder::RenderSliceNormal( const Vertex3f& v1, const Vertex3f& v2, const Vertex3f& v3, const Vertex3f& v4 )  
  143. {  
  144.     glBegin(GL_LINES);  
  145.     glVertex3f(v1.x, v1.y, v1.z);     
  146.     glVertex3f(v1.nx + v1.x, v1.ny+v1.y, v1.nz+v1.z);  
  147.     glEnd();  
  148.   
  149.     glBegin(GL_LINES);  
  150.     glVertex3f(v2.x, v2.y, v2.z);     
  151.     glVertex3f(v2.nx + v2.x, v2.ny+v2.y, v2.nz+v2.z);  
  152.     glEnd();  
  153.   
  154.     glBegin(GL_LINES);  
  155.     glVertex3f(v3.x, v3.y, v3.z);     
  156.     glVertex3f(v3.nx + v3.x, v3.ny+v3.y, v3.nz+v3.z);  
  157.     glEnd();  
  158.   
  159.     glBegin(GL_LINES);  
  160.     glVertex3f(v4.x, v4.y, v4.z);     
  161.     glVertex3f(v4.nx + v4.x, v4.ny+v4.y, v4.nz+v4.z);  
  162.     glEnd();  
  163. }  
  164.   
  165. // ----------------------------------------------------------------   
  166. //  Description:    根据vSlice和lSlice生成纹理坐标   
  167. //                     
  168. // ----------------------------------------------------------------   
  169. void Cylinder::_setupVertexTexcoord()  
  170. {  
  171.     if (!pVertexBuffer || !pTexcoord)  
  172.         return;  
  173.       
  174.     float ds = 1.0f / lSlice;           //x,u 方向   
  175.     float dt = 1.0f / (vSlice-1);       //y,v 方向   
  176.   
  177.     for (int i=0; i<vSlice; i++)  
  178.     {  
  179.         for (int j=0; j<lSlice; j++)  
  180.         {  
  181.             pVertexBuffer[j + i*lSlice].u = j*ds;  
  182.             pVertexBuffer[j + i*lSlice].v = i*dt;  
  183.         }  
  184.   
  185.         // 最后一列的纹理横坐标全部为:1.0   
  186.         // pTexcoord中只是纵坐标   
  187.         pTexcoord[i] = i * dt;  
  188.     }  
  189. }  
  190.   
  191.   
  192. // ----------------------------------------------------------------   
  193. //  Description:    根据角度和高度求取顶点的坐标   
  194. //  Para info:      theta为弧度数,圆中的角度   
  195. //                  hgh为高度     
  196. // ----------------------------------------------------------------   
  197. void Cylinder::_getVertex(float theta, float hgh, Vertex3f& vertex)  
  198. {  
  199.     float cosTheta = cos(theta);  
  200.     float sinTheta = sin(theta);  
  201.   
  202.     // setup position coordinate   
  203.     vertex.x = radius * cosTheta;  
  204.     vertex.y = hgh;  
  205.     vertex.z = radius * sinTheta;  
  206.   
  207.     // setup normal coordinate   
  208.     vertex.nx = cosTheta;  
  209.     vertex.ny = 0;  
  210.     vertex.nz = sinTheta;  
  211. }  
  212.   
  213. // ----------------------------------------------------------------   
  214. //  Description:    求取圆柱的顶点阵列   
  215. // ----------------------------------------------------------------   
  216. void Cylinder::_getMatrices()  
  217. {  
  218.     const float pi = 3.1415926;  
  219.   
  220.     float angle = 2.0f * pi / static_cast<float>(lSlice);  
  221.     // 注意分母为高度段数减1   
  222.     float span = height / static_cast<float>(vSlice-1);  
  223.   
  224.     for (int v=0; v<vSlice; v++)  
  225.     {  
  226.         float y = span * v;  
  227.         for (int l=0; l<lSlice; l++)  
  228.         {  
  229.             float x = angle * static_cast<float>(l);  
  230.             _getVertex(x, y, pVertexBuffer[l + v*lSlice]);  
  231.         }  
  232.     }  
  233. }  
  234.   
  235. // ----------------------------------------------------------------   
  236. //  Description:    打印matrices中的元素   
  237. // ----------------------------------------------------------------   
  238. void Cylinder::PrintMatrices()  
  239. {  
  240.     using namespace std;  
  241.     for (int i=0; i<vSlice*lSlice; i++)  
  242.     {  
  243.         cout << "//---------------------------------------------------------------------" << endl;  
  244.         cout << "row = " << i / lSlice << ".";  
  245.         cout << "coll = " << i % lSlice << endl;  
  246.   
  247.         cout << "position(x, y, z) = " << setprecision (7) << pVertexBuffer[i].x << " "  
  248.                                        << setprecision (7) << pVertexBuffer[i].y << " "  
  249.                                        << setprecision (7) << pVertexBuffer[i].z << endl;  
  250.   
  251.         cout << "texture(u, v) = " << setprecision (7) << pVertexBuffer[i].u << " "  
  252.                                    << setprecision (7) << pVertexBuffer[i].v << endl;  
  253.         cout << "//---------------------------------------------------------------------" << endl;  
  254.     }  
  255. }  

 

测试程序如下,要运行起来,还必须加一个bmpLoader的程序库,可以到这里下载一个简单的,里面有自带的bmp图片。

http://users.ox.ac.uk/~orie1330/bmploader.html

代码:

  1. #include <GL/glut.h>   
  2. #include <cstdio>   
  3. #include <cstdlib>   
  4. #include "Cylinder.h"   
  5.   
  6. #include "BMPLoader.h"   
  7.   
  8. /*  Create checkerboard texture */  
  9. #define checkImageWidth 64   
  10. #define checkImageHeight 64   
  11. static GLubyte checkImage[checkImageHeight][checkImageWidth][4];  
  12.   
  13. static GLuint texName;  
  14.   
  15. Cylinder        g_cylinder(0.5f, 1.3f, 30, 5);  
  16. static float    angleX = 0.0f;  
  17. static float    angleY = 0.0f;  
  18. //   
  19. void makeCheckImage(void)  
  20. {  
  21.     int i, j, c;  
  22.   
  23.     for (i = 0; i < checkImageHeight; i++) {  
  24.         for (j = 0; j < checkImageWidth; j++) {  
  25.             c = ((((i&0x8)==0)^((j&0x8))==0))*255;  
  26.             checkImage[i][j][0] = (GLubyte) c;  
  27.             checkImage[i][j][1] = (GLubyte) c;  
  28.             checkImage[i][j][2] = (GLubyte) c;  
  29.             checkImage[i][j][3] = (GLubyte) 255;  
  30.         }  
  31.     }  
  32. }  
  33.   
  34. void init(void)  
  35. {      
  36.     glClearColor (0.0, 0.0, 0.0, 0.0);  
  37.     glShadeModel(GL_SMOOTH);  
  38.     glEnable(GL_DEPTH_TEST);  
  39.   
  40.     //makeCheckImage();   
  41.     BMPClass bmp;  
  42.     BMPLoad("bmp16.bmp", bmp);  
  43.   
  44.     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);  
  45.    
  46.     glGenTextures(1, &texName);  
  47.     glBindTexture(GL_TEXTURE_2D, texName);  
  48.    
  49.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
  50.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);  
  51.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  
  52.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
  53.    
  54. /* 
  55.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight,  
  56.         0, GL_RGBA, GL_UNSIGNED_BYTE, / *checkImage* /bmp.bytes); 
  57. */  
  58.     glTexImage2D(GL_TEXTURE_2D,0,3,bmp.width,bmp.height,0,GL_RGB,GL_UNSIGNED_BYTE,bmp.bytes);  
  59. }  
  60.   
  61. void display(void)  
  62. {  
  63.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  64.   
  65.     glEnable(GL_TEXTURE_2D);  
  66.     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);  
  67.     glBindTexture(GL_TEXTURE_2D, texName);  
  68.   
  69.     glPushMatrix();  
  70.     {  
  71.         glRotatef(angleX, 1.0f, 0.0f, 0.0f);  
  72.         glRotatef(angleY, 0.0f, 1.0f, 0.0f);  
  73.         g_cylinder.Render(SOLID);  
  74.     }glPopMatrix();  
  75.   
  76.     glutSwapBuffers();    
  77.     glDisable(GL_TEXTURE_2D);  
  78.   
  79.     glutPostRedisplay();  
  80. }  
  81.   
  82. void reshape(int w, int h)  
  83. {  
  84.     glViewport(0, 0, (GLsizei) w, (GLsizei) h);  
  85.     glMatrixMode(GL_PROJECTION);  
  86.     glLoadIdentity();  
  87.     gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);  
  88.     glMatrixMode(GL_MODELVIEW);  
  89.     glLoadIdentity();  
  90.     glTranslatef(0.0f, 0.0f, -3.6f);  
  91. }  
  92.   
  93. void keyboard (unsigned char key, int x, int y)  
  94. {  
  95.     switch (key) {  
  96.       case 27:  
  97.           exit(0);  
  98.           break;  
  99.   
  100.       case 'x':  
  101.           angleX += 5.0f;  
  102.           break;  
  103.       case 's':  
  104.           angleX -= 5.0f;  
  105.   
  106.       case 'y':  
  107.           angleY += 4.0f;  
  108.           break;  
  109.   
  110.       case 'h':  
  111.           angleY -= 4.0f;  
  112.           break;  
  113.   
  114.       default:  
  115.           break;  
  116.     }  
  117.   
  118.     glutPostRedisplay();  
  119. }  
  120.   
  121. int main(int argc, char** argv)  
  122. {  
  123.     glutInit(&argc, argv);  
  124.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);  
  125.     glutInitWindowSize(250, 250);  
  126.     glutInitWindowPosition(100, 100);  
  127.     glutCreateWindow(argv[0]);  
  128.     init();  
  129.     glutDisplayFunc(display);  
  130.     glutReshapeFunc(reshape);  
  131.     glutKeyboardFunc(keyboard);  
  132.     glutMainLoop();  
  133.   
  134.   
  135.     return 0;   
  136. }  

 

PS:OpenGL绘制什么都得DIY。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值