计算机图形学·6 OpenGL编程3 谢尔宾斯基垫与三维编程

本文是记录专业课"计算机图形学"的部分笔记,参考教材为Angel的第八版交互式计算机图形学------基于WebGL 2.0的自顶向下方法。

1、在OpenGL中,二维是三维的一个特例,而三维其实变化不大,使用 glVertex3*( )即可。需要考虑的是多边形的绘制顺序、使用隐藏面消除技术以及简单性、凸性和平面性。

2、让我们先考虑二维的The Sierpinski Gasket(谢尔宾斯基垫):

算法如下图,核心是利用随机过程和迭代函数系统。具体流程是①在三角形内部任意选择一个初始点 p0​;②从三角形的三个顶点中随机选择一个;③找到当前点 p与上一步选中的顶点之间的中点q并绘制;④将当前点 p的位置更新为刚刚计算出的中点 q的位置(即 pn+1​=qn​),为下一次迭代做准备;⑤跳回第二步。

上述算法是A1 gasket 2D Sierpinski Gasket Using Randomly Selected Vertices,而对于A2 Sierpinski Gasket 2D ,先从一个三角形开始,连接三边的中点并去掉中间的三角形,再重复上述过程。对于A2的分形效果,我们考虑填充区域(黑色)和周长(围绕填充三角形的所有线的长度):随着我们继续细分,面积变为零但周长趋于无穷大,这不是一个普通的几何对象(既不是二维也不是三维)、而是一个分形(分形维数)对象(例如英格兰海岸线为1.02维)。

A2 Sierpinski Gasket 2D 示例程序:

复制代码
#include <GL/glut.h>

/* initial triangle */
GLfloat v[3][2]={{-1.0, -0.58}, {1.0, -0.58}, {0.0, 1.15}};
 
/* number of recursive steps递归次数*/
int n; // 全局变量 递归层次

//绘制三角形:
void triangle( GLfloat *a, GLfloat *b, GLfloat *c)
/* display one triangle */
{
 glVertex2fv(a); 
 glVertex2fv(b); 
 glVertex2fv(c);
}

//三角形细分:
void divide_triangle(GLfloat *a, GLfloat *b, GLfloat *c, int m)
{
/* triangle subdivision using vertex numbers */
 point2 v0, v1, v2;
 int j;
 if(m>0) {
 for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
 for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
 for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
 divide_triangle(a, v0, v1, m-1);
 divide_triangle(c, v1, v2, m-1);
 divide_triangle(b, v2, v0, m-1);
 }
 else
 triangle(a,b,c);
/* draw triangle at end of recursion */
}

//显示与初始化函数:
void display()
{
 glClear(GL_COLOR_BUFFER_BIT);
 glBegin(GL_TRIANGLES);
 divide_triangle(v[0], v[1], v[2], n); // 全局参变量 n
 glEnd();
 glFlush();
}

void myinit()
{
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
 glMatrixMode(GL_MODELVIEW);
 glClearColor (1.0, 1.0, 1.0,1.0); //背景白色,屏幕
 glColor3f(0.0,0.0,0.0); //前景黑色,三角形
}

//主函数:
int main(int argc, char **argv)
{
 n=4; //程序指定,还可以用户输入,交互界面 或者 命令行
 
 glutInit(&argc, argv); // 初始化GLUT 
 glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
 glutInitWindowSize(500, 500);
 glutCreateWindow("2D Gasket");
 glutDisplayFunc(display);
 myinit();
 glutMainLoop();
}

通过将glBegin和glEnd放在显示回调中而不是在triangle函数中,并在glBegin中使用GL_TRIANGLES而不是GL_POLYGON,我们只需为整个垫片调用一次glBegin和glEnd,而不是为所有三角形都调用一次。不过也可以用glDrawArrays(GL_TRIANGLES, 0, Nvertices);

3、而对于三维垫,可以使用三维点(GLfloat v33、glVertex3f、glOrtho)的方式,但不好。因此我们采用四面体(tetrahedron)方法。

复制代码
//三角形代码:
void triangle( GLfloat *a, GLfloat *b, 
GLfloat *c)
{
 glVertex3fv(a);
 glVertex3fv(b);
 glVertex3fv(c);
}

void divide_triangle(GLfloat *a, GLfloat *b, GLfloat *c, int m)
{
 GLfloat v1[3], v2[3], v3[3];
 int j;
 if(m>0)
 {
 for(j=0; j<3; j++) v1[j]=(a[j]+b[j])/2;
 for(j=0; j<3; j++) v2[j]=(a[j]+c[j])/2;
 for(j=0; j<3; j++) v3[j]=(b[j]+c[j])/2;
 divide_triangle(a, v1, v2, m-1);
 divide_triangle(c, v2, v3, m-1);
 divide_triangle(b, v3, v1, m-1);
 }
 else(triangle(a,b,c));
}

//生成四面体:
void tetrahedron(int m)
{
 glColor3f(1.0,0.0,0.0);
 divide_triangle(v[0], v[1], v[2], m);
 glColor3f(0.0,1.0,0.0);
 divide_triangle(v[3], v[2], v[1], m);
 glColor3f(0.0,0.0,1.0);
 divide_triangle(v[0], v[3], v[1], m);
 glColor3f(0.0,0.0,0.0);
 divide_triangle(v[0], v[2], v[3], m);
}

4、不过在三维中,由于三角形是按照程序中的定义顺序绘制的,因此前面的三角形并不总是渲染在它们后面的三角形前面,这涉及了遮挡/消隐问题:

我们只想看到位于其他表面之前的那些表面,OpenGL采用z缓冲算法,使用了一个硬件支持的额外缓冲区,在渲染对象时保存深度信息,以便图像中只显示前面的对象。使用时需要①在main.c中给绘制模式加上z缓冲区 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);②在init.c中启动深度测试状态 glEnable(GL_DEPTH_TEST);③清屏时候同时清理深度缓存glClear(GL_COLOR_BUFFER_BIT | //当前可写的颜色缓存 GL_DEPTH_BUFFER_BIT)//将所有像素的深度值设置为最大可能距离(一般是远剪裁面)。

5、另外,在上述示例中,我们对每个物体进行了面分解,实际上体分解也是可以的:

相关推荐
YLCHUP10 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
思麟呀11 小时前
背包DP(01背包+完全背包)
c++·算法
发现你走远了11 小时前
05-权限不是开关:工具调用如何在放行、拦截与追问之间做决定
人工智能·agent·claude
AllData公司负责人11 小时前
AI大模型数据开发底座系列说明书:AllData集成DB-GPT开源项目建设 AI 多模态分析底座,涵盖模态解析/智能大屏/MCP 扩展!
大数据·数据库·人工智能·gpt·数据采集·数据接入·模态解析
笑容掩饰我的失落12 小时前
区块链从小白到精通(七):Solidity 语法精讲——数据类型、函数、修饰器与事件
算法·区块链·php·智能合约·哈希算法
syyjhchou13 小时前
自己搭企业内部中转站,怎么让请求更容易命中缓存
人工智能·后端·语言模型·aigc
Pniubi13 小时前
力扣24. 两两交换链表中的节点(递归)
算法·leetcode·链表
张然Adolf13 小时前
人工智能电力系统应用新手实战指南
人工智能
高洁0113 小时前
数据同化与动态状态估计:让孪生持续贴合现实
人工智能·python·深度学习·transformer·迁移学习
feasibility.13 小时前
一物降一物?AI逆向没有终局:REA拆App,BLA设套,LASIK清场
人工智能·爬虫·github·逆向·skill·rea