本文阐述一种简单的绘制3D花瓶的方法,对于刚接触图形学的小伙伴而言是一个很好的练习题目。

先附上我的结果:

     

下面阐述原理及我的实现:

1.定义一个正弦函数f(y)

f(y) =  r*sin(y)+R

r和R用于控制花瓶半径

2.让这个函数绕着y轴旋转,则我们可以得到一个曲面函数:

x^2+z^2 = (r*sin(y)+R)^2

3.根据函数我们可以开始建立网格,如下:

我们先定义一些变量:

QVector<QVector3D> m_vertex;//保存顶点坐标QVector<QVector2D> m_texcood;GLdouble *vertex;GLdouble *texcood;GLuint *tex0;//纹理

说一下网格建立的思路,我们可以想象一下我们把上面那个曲面函数在竖直方向分成v_levels层,以及把每一层的圆分成h_levels块,其目的是离散化我们的曲线曲面,这样我们能够轻易的构造面片(下面的代码构造四角面片)。具体的思路是我们取一层的相邻两个点和相邻层的对应的两个点组成一个四角面片。对每一层进行四角面片的构造之后我们完成了网格建立。

以下函数完成了网格的建立

void Widget::BuildVase( int v_levels,int h_levels)
//v_levels 和 h_levels 分别是竖直和水平方向划分层数,如一个把圆切片分成h_levels块
{m_vertex.clear();int horiz_levels = h_levels;   int vertical_levels = v_levels;int mincal = 50,maxcal = 100;//最小口径和最大口径double height = 380;//定义花瓶高度int step = height/vertical_levels;for( int i = -50; i< 330;i+=step){double r1 = mincal*sin(i/180.0*PI)+maxcal;double r2 = mincal*sin((i+step)/180.0*PI)+maxcal;for(int j = 0; j<horiz_levels;j++){ //每一层的划分double angle1 =  360.0/horiz_levels*j;double angle2 =  360.0/horiz_levels*(j+1);//生成顶点v1,v2在切片i上 v3,v4在切片i+step上,四个点构成一个四角面QVector3D v1(r1*cos(angle1/180.0*PI),i,r1*sin(angle1/180.0*PI));QVector3D v2(r1*cos(angle2/180.0*PI),i,r1*sin(angle2/180.0*PI));QVector3D v3(r2*cos(angle2/180.0*PI),i+step,r2*sin(angle2/180.0*PI));QVector3D v4(r2*cos(angle1/180.0*PI),i+step,r2*sin(angle1/180.0*PI));//生成对应的纹理坐标QVector2D t1((double)j/horiz_levels,(i+50)/height);QVector2D t2((double)(j+1)/horiz_levels,(i+50)/height);QVector2D t3((double)(j+1)/horiz_levels,(i+step+50)/height);QVector2D t4((double)j/horiz_levels,(i+step+50)/height);m_vertex.push_back(v1);m_vertex.push_back(v2);m_vertex.push_back(v3);m_vertex.push_back(v4);m_texcood.push_back(t1);m_texcood.push_back(t2);m_texcood.push_back(t3);m_texcood.push_back(t4);}}free(vertex);//把纹理坐标和顶点坐标转换为数组,即为顶点数组的使用方式vertex = new double [m_vertex.size()*3];texcood = new double [m_texcood.size()*2];for(int i= 0; i< m_vertex.size();i++){vertex[i*3+0] = m_vertex[i].x();vertex[i*3+1] = m_vertex[i].y();vertex[i*3+2] = m_vertex[i].z();}for(int i= 0; i< m_texcood.size();i++){texcood[i*2+0] = m_texcood[i].x();texcood[i*2+1] = m_texcood[i].y();}}

注:这个函数只在初始化函数中执行一次即可。

4.使用纹理

我们已经把网格建立好了,如果我们直接绘制,即使加上光照也只能得到一个很普通的花瓶样子,并不好看,所以我们要加上纹理,下面是纹理的使用方法:


void loadTexture(QString filepath, GLuint *texture){QImage tex, buf;if(!buf.load(filepath)){qDebug()<<"Error: failed to load image!";exit(1);}tex = convertToGLFormat(buf);glGenTextures(1, texture);glBindTexture(GL_TEXTURE_2D, *texture);gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex.width(), tex.height(), GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,3);}

在初始化函数中使用以上函数绑定纹理


tex0 = new GLuint;
loadTexture(filepath,tex0);//filepath为纹理图片的路径

5.使用顶点数组绘制花瓶

使用顶点数组可以很大的提高绘制效率。当然这是一个很简单的程序也可以不适用顶点数组,根据以上获得的顶点和纹理坐标,我们遍历一遍使用glBegin(GL_QUADS);绘制也是可以的。

但是,我强烈推荐使用顶点数组。

顶点数组使用的方式如下:


void Widget::drawVase()
{glBindTexture(GL_TEXTURE_2D,*tex0);  //绑定纹理glEnableClientState(GL_VERTEX_ARRAY); //启动顶点数组glEnableClientState(GL_TEXTURE_COORD_ARRAY);//启动纹理数组glPushMatrix();glTexCoordPointer(2,GL_DOUBLE,0,texcood); //绑定纹理数据glVertexPointer(3,GL_DOUBLE,0,vertex); //绑定顶点数据glDrawArrays(GL_QUADS,0,m_vertex.size());//绘制glPopMatrix();glFlush();}

在绘制函数中调用drawVase();即可完成绘制。

6. 给花瓶添加阴影

可以看一下我的另一个文章:基于平面方程的阴影计算

程序演示链接:https://download.csdn.net/download/qq_31804159/10383046

opengl绘制花瓶相关推荐

  1. 如何用 OpenGL 绘制雪花?

    作者 | 许向武 责编 | 张红月 出品 | CSDN博客 看冬奥才知道,阿勒泰不但是中国的"雪都",还是"人类滑雪起源地".这个说法是否成立,姑且不论,阿勒泰 ...

  2. 使用OpenGL绘制圆环体(Torus)

    本篇介绍一下使用OpenGL绘制圆环体的方法.程序是在C#和OpenTK环境下编译的. 代码: /// <summary> /// 绘制圆环体 /// </summary> / ...

  3. 【OpenGL】十三、OpenGL 绘制三角形 ( 绘制单个三角形 | 三角形绘制顺序 | 绘制多个三角形 )

    文章目录 一.绘制三角形 二.三角形绘制顺序 1.绘制正面 2.三个点逆时针方向排列 3.三个点顺时针方向排列 4.设置点的正面方向 三.绘制多个三角形 四.相关资源 一.绘制三角形 三角形绘制即绘制 ...

  4. 【OpenGL】十一、OpenGL 绘制多个点 ( 绘制单个点 | 绘制多个点 )

    文章目录 一.绘制单个点 二.绘制多个点 三.相关资源 在上一篇博客 [OpenGL]十.OpenGL 绘制点 ( 初始化 OpenGL 矩阵 | 设置投影矩阵 | 设置模型视图矩阵 | 绘制点 | ...

  5. 【OpenGL】十、OpenGL 绘制点 ( 初始化 OpenGL 矩阵 | 设置投影矩阵 | 设置模型视图矩阵 | 绘制点 | 清除缓冲区 | 设置当前颜色值 | 设置点大小 | 绘制点 )

    文章目录 一.初始化 OpenGL 矩阵 1.设置投影矩阵 2.设置模型视图矩阵 二.绘制点 1.清除缓冲区 2.设置当前颜色值 3.设置绘制点的大小 4.绘制点 5.将缓冲区绘制到前台 三.部分代码 ...

  6. 【OpenGL】九、OpenGL 绘制基础 ( OpenGL 状态机概念 | OpenGL 矩阵概念 )

    文章目录 一.OpenGL 状态机概念 二.OpenGL 矩阵概念 上一篇博客 [OpenGL]八.初始化 OpenGL 渲染环境 ( 导入 OpenGL 头文件 | 链接 OpenGL 库 | 将窗 ...

  7. OpenGL绘制二个不同颜色的三角形的实例

    OpenGL绘制二个不同颜色的三角形 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include & ...

  8. OpenGL绘制带有索引的矩形的实例

    OpenGL绘制带有索引的矩形 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include < ...

  9. OpenGL绘制一个三角形的实例

    OpenGL绘制一个橘黄色的三角形 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <glad/glad.h> #include &l ...

最新文章

  1. 不再为Apache进程淤积、耗尽内存而困扰[转载]
  2. 打开一个解决方案时弹出“项目所需的应用程序未安装,确保已安装项目类型(.csproj)的应用程序”问题的解决方案
  3. ★Kali信息收集~★6.Dmitry:汇总收集
  4. 一些关于Silverlight 3的消息
  5. 「Apollo」protobuf报错No module named ‘google‘
  6. 《数据库原理与应用》(第三版)第2章 数据模型与数据库结构 习题参考答案
  7. java long bigdecimal,通过Java中的long创建BigDecimal值
  8. BZOJ 4810 [Ynoi2017]由乃的玉米田(莫队+bitset)
  9. 关于MongoDB的几个问题
  10. python 环境管理工具_python3环境管理器
  11. 元月元日是哪一天_2020年下元节是哪一天 几月几号
  12. HDU 2068 RPG 的错排(错排问题,组合数)
  13. BT 与 Magnet 的下载方式及原理
  14. 给予Java初学者的学习路线建议
  15. nagios监控数据库错误
  16. 腾讯守护者 向网络黑产说不!
  17. 稳压二极管和TVS二极管的区别
  18. 想用Charles抓包,某些app不让抓怎么办
  19. 【独行秀才】macOS Monterey 12.2.1正式版(21D62)原版镜像
  20. c/c++: 如何区分c和c++

热门文章

  1. 游戏设计模式杂谈(一)
  2. 瑞云科技奥斯卡原班渲染团队助力《龙之谷:破晓奇兵》3D渲染
  3. 程序员写的春联你见过吗
  4. 20162329张旭升 2016-2017-2 《程序设计与数据结构》第八周学习总结
  5. 为什么都说UX / UI设计师是最佳工作?
  6. Android Camera HAL3 hdr
  7. alexa排名的快速提升方法
  8. iOS简单好看的动画
  9. android百度地图 模糊查询,百度地图,自动获取定位,拖拽获取地点,模糊查询获取当前位置...
  10. Linux useradd 命令详解