面向GPU基于Vertex Texture Fetch的细分曲面构想和初步实现 上

本文探讨了一种面向GPU的细分曲面实现方法,利用Vertex Shader和Pixel Shader在运行时通过细分矩阵纹理进行实时细分。通过化简原始网格,仅存储基本网格,减少了内存需求。然而,目前GPU的限制尚无法动态增删顶点,期望未来技术改进。
摘要由CSDN通过智能技术生成

面向GPU基于Vertex Texture Fetch的细分曲面构想和初步实现

 

作者:张嘉华、王建光、梁成(女)

华南理工大学计算机科学与工程学院(510460

指导教师:李桂清

华南理工大学计算机科学与工程学院(510460

newzjh@126.comAlceliang@163.net

 

 

介绍:

近几年来,面向GPU的图形技术发展非常迅速,可编程着色(Programming Shader)而融入到许多实际应用中了,而细分曲面也已经发展了很久的一段时间,有很多成熟的方法。本文结合作者在做的项目简单地介绍了作者在GPU上通过Vertex ShaderPixel Shader实现细分曲面的构想。该构想与其它方法网格建模渲染方法相比,只需要非常小的运行时存储空间,只存储模型最简单的能保持特征的三角形网格,在需要高分辨率时,在GPU上通过实时细分产生实际的网格。本构想仍没解决的问题是实时细分所产生的网格的渲染问题。

 

1、引子

 

细分曲面在计算机动画、多分辨率编辑分析等方面有广泛的应用。以往有很多计算机网格渲染方法,对于超大规模具有很多三角形面皮的模型,往往采用多分辨率LOD方法,也就是在读入模型的时候建立模型的多个分辨率,当模型接近的时候采用高的分辨率模型,远的时候采用低的分辨率模型,后来随着Huge Hoppe关于渐进网格的提出,微软的Direct 3DAPI层实现了渐进网格、增强网格,并能设置LOD层次值,但其往往需要在模型读入时建立模型的各级分辨率或者在运行时需要CPU对模型根据一定的LOD准则不断Refinement和合并,占用很大的存储空间,理论上要存储原模型的33%倍的顶点,对于一个很多三角形面的模型来说,难以实现运行时Out-of-core。而相比之下,基于细分曲面的方法,可以形式化地表示为“基本网格+细分的拓扑规则+细分的几何规则”,在模型读入建立时简化模型到最基本的网格,然后在运行时通过GPUVertex Shader Texture Fetch技术不断读入显示缓冲中的以纹理形式存放的细分矩阵,以实时迭代的形式不断Refinement,直至模型分辨率可以接收。我们这种方法与地形的中点位移法分形生成、L-System下植物生成以及过程纹理很类似,也是给定一非常简单的初始素材,根据给定的参数、通过一系列迭代和启发式规则生成满意的目标,其不同点在于本构想是针对模型的,期盼运行时实时实现。

 

优点:本构想能够运行时实时实现细分、只需很少存储空间存储初始网格、具有可控的实时细分规则、能够易于实现Out-of-Core,无需CPU

B样条曲面是一种常用的曲面表示方法,它可以通过控制点和节点向量定义。下面是一种基于OpenGL实现的B样条曲面的方法: 1. 定义控制点和节点向量 ```c++ // 控制点数 const int N = 4; const int M = 4; // 控制点 float ctrlPoints[N][M][3] = { {{-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0}, {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}}, {{-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0}, {0.5, -0.5, 0.0}, {1.5, -0.5, -1.0}}, {{-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0}, {0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}}, {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0}, {0.5, 1.5, 0.0}, {1.5, 1.5, -1.0}} }; // 节点向量 float knots[N+4] = {-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; ``` 2. 计算B样条基函数 ```c++ // 计算B样条基函数 float basisFunc(int i, int p, float u, float* knots) { if (p == 0) { if (knots[i] <= u && u < knots[i+1]) { return 1.0; } else { return 0.0; } } else { float a = (u - knots[i]) / (knots[i+p] - knots[i]); float b = (knots[i+p+1] - u) / (knots[i+p+1] - knots[i+1]); return a * basisFunc(i, p-1, u, knots) + b * basisFunc(i+1, p-1, u, knots); } } ``` 3. 计算曲面上每个点的坐标 ```c++ void drawSurface() { glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, M, 0.0, 1.0, 3*N, M, &ctrlPoints[0][0][0]); glEnable(GL_MAP2_VERTEX_3); glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); for (int i = 0; i < N-1; i++) { glBegin(GL_QUAD_STRIP); for (int j = 0; j <= M; j++) { for (int k = 0; k <= 1; k++) { float u = (i + k) * 1.0; float v = j * 1.0; for (int l = 0; l < 3; l++) { float sum = 0.0; for (int ii = 0; ii < N; ii++) { sum += ctrlPoints[ii][j][l] * basisFunc(ii, 3, u, knots); } vertices[k][l] = sum; } glVertex3fv(vertices[k]); } } glEnd(); } } ``` 这段代码通过调用OpenGL提供的函数来绘制B样条曲面,使用了GL_MAP2_VERTEX_3这个函数来指定控制点的坐标,然后通过计算每个点的坐标来绘制曲面。具体实现细节可以参考OpenGL的相关文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值