Mesh Data Structure in OpenCascade
Mesh Data Structure in OpenCascade
摘要Abstract:本文对网格数据结构作简要介绍,并结合使用OpenCascade中的数据结构,将网格数据在OpenSceneGraph中可视化。
关键字KeyWords:OpenCascade、OpenSceneGraph、Triangulation、Mesh Data Structure
一、引言 Introduction
三角网格就是全部由三角形组成的多边形网格。多边形和三角网格在图形学和建模中广泛使用,用来模拟复杂物体的表面,如建筑、车辆、人体,当然,还有茶壶等自由曲面。任意多边形网格都能转换成三角网格。三角网格以其简单性而吸引人,相对于一般多边形网格许多操作对三角网格列容易。
常用的网格数据文件有:
1.Wavefront OBJ(*.obj)
2.3D Max(*.max, *.3ds)
3.VRML(*.vrl)
4.Inventor(*.iv)
5.PLY(*.ply, *.ply2)
6.STL(*.stl)
7.Off(*.off) in CGAL library
有些文件以文本方式保存,有些可以以二进制方式保存。如下图所示为OBJ文件的格式:
![]()
Figure 1.1 Wavefront OBJ File Format
l Vertices
n 以‘V’开始;
n 其后为坐标值(x,y,z);
l Faces
n 以‘F’开始;
n 其后为面的顶点索引值;
l Other properties
n Normal, texture coordinates, material, etc.
二、三角网格的表示 Mesh Data Structure
三角网格为一个三角形列表,所以最直接的表示方法是用三角形数组:
struct Triangle
{
Vector3 p[];
}; struct TriangleMesh
{
int triCount;
Triangle* triList;
};
对于某些应用程序,这种表示方法已经足够。然而,术语“网格”隐含的相邻三角形的连通性未在这种简单表示中有任何体现。实际应用中出现的三角网格,每个三角形都和其他三角形共享边。于是三角网格需要存储三类信息:
l 顶点。每个三角形有三个顶点,各顶点都有可能和其他三角形共享;
l 边。连接两个顶点的边,每个三角形有三条边;
l 面。每个三角形对应一个面。我们可以用顶点或边列表表示面;
根据应用程序的不同,有多种有效的网格表示方法。常用的一种标准的存储格式为索引三角网格。
在索引三角网格中,我们维护了两个列表:顶点表与三角形表。每个顶点包含一个3D位置,也可能有表面法向量、纹理映射坐标、光照值附加数据。每个三角形由顶点列表的三个索引值组成。通常顶点列出的顺序是非常重要的,因为我们必须考虑面的“正面”和“反面”。从前面看时,我们将用顺时针方向列出顶点。
在OpenCascade中,分别用类TColgp_Array1OfPnt和Poly_Array1OfTriangle表存储顶点表和三角形表。注意到索引三角形列表中的邻接信息是隐含的,即边信息没有存储,但我们可以通过搜索三角形表找出公共边。和前面“三角形数组”方式相比,这种方式确实能节省不少空间。原因是信息存于顶点级别,它的整数索引比之三角形数组里存储的顶点重复率要小得多。实践中,三角网里确实有大量的连接性问题。
简单索引三角网格对于基本应用已经足够了。但为更加高效地实现某些操作还可以进一步改进。主要的问题是邻接信息没有显式表达,所以必须从三角形列表中搜索。另一种表达方法可以常数时间内取得这种信息。方法是显式维护一个边列表,每边由两个端点定义,同时维护一个共享该边的三角形列表。这样三角形可视为三条边而非三个点的列表,也就是说它是边列表的索引。该思想的一个扩展称作“Winged Edge”模型(翼边模型),对每一顶点,存储使用该点的边的索引。这样三角形和边都可以通过定位点列表快速查找。
大多数显卡并不直接支持索引三角网。渲染三角形时,一般是将三个顶点同时提交。这样,共享顶点会多次提交,三角形用到一次就提交一次。因为内存和图形硬件间的数据传输是瓶颈,所以许多API和硬件支持特殊三角网格式以减少传输量。基本思想是排序点和面,使得显存中已有的三角形不需要再次传输。
从最高灵活性到最低灵活性,我们讨论三种方案:
n 顶点缓存;
n 三角带Triangle Strip;
n 三角扇Triangle Fan;
三、程序示例 Code Example
在安装好的CGAL库中发现其例子中有很多off文件,其格式同常见的网格文件格式基本相同,结合OpenCascade和OpenSceneGraph,读取off文件,将其表示的网格模型显示出来。程序代码如下所示:
/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2013-08-10 18:02
* Version : V1.0
*
* Description : Mesh Viewer for the general mesh file format.
* Poly_Triangulation data structure can save vertices and triangle index.
*
*/ // OpenSceneGraph library.
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/StateSetManipulator>
#include <osgViewer/ViewerEventHandlers> #pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib") // OpenCascade library.
#include <TColgp_Array1OfPnt.hxx>
#include <Poly_Array1OfTriangle.hxx>
#include <Poly_Triangulation.hxx> #pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib") /**
* @breif Build the mesh from *.off file.
*/
osg::Node* buildMesh(const std::string& fileName)
{
std::ifstream offFile(fileName.c_str());
std::string strBuffer; osg::ref_ptr<osg::Geode> geode = new osg::Geode();
osg::ref_ptr<osg::Geometry> triGeom = new osg::Geometry();
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array();
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array(); Standard_Integer nbNodes = ;
Standard_Integer nbTriangles = ; // Ignore "OFF"
offFile>>strBuffer;
offFile>>nbNodes>>nbTriangles>>strBuffer; TColgp_Array1OfPnt nodes(, nbNodes);
Poly_Array1OfTriangle triangles(, nbTriangles); // Read node coordinate and store them.
Standard_Real dx = 0.0;
Standard_Real dy = 0.0;
Standard_Real dz = 0.0; for (Standard_Integer i = ; i < nbNodes; i++)
{
offFile>>dx>>dy>>dz; nodes(i).SetCoord(dx, dy, dz);
} // Read the triangles
Standard_Integer ni = ;
Standard_Integer n1 = ;
Standard_Integer n2 = ;
Standard_Integer n3 = ; for (Standard_Integer i = ; i < nbTriangles; i++)
{
offFile>>ni>>n1>>n2>>n3; triangles(i).Set(n1, n2, n3);
} // Construct the mesh data by Poly_Triangulation.
gp_Pnt node1;
gp_Pnt node2;
gp_Pnt node3;
Poly_Triangle triangle;
Handle_Poly_Triangulation T = new Poly_Triangulation(nodes, triangles); for (Standard_Integer i = ; i < nbTriangles; i++)
{
triangle = triangles.Value(i); triangle.Get(n1, n2, n3); node1 = nodes.Value(n1);
node2 = nodes.Value(n2);
node3 = nodes.Value(n3); gp_XYZ vector12(node2.XYZ() - node1.XYZ());
gp_XYZ vector13(node3.XYZ() - node1.XYZ());
gp_XYZ normal = vector12.Crossed(vector13);
Standard_Real rModulus = normal.Modulus(); if (rModulus > gp::Resolution())
{
normal.Normalize();
}
else
{
normal.SetCoord(., ., .);
} vertices->push_back(osg::Vec3(node1.X(), node1.Y(), node1.Z()));
vertices->push_back(osg::Vec3(node2.X(), node2.Y(), node2.Z()));
vertices->push_back(osg::Vec3(node3.X(), node3.Y(), node3.Z())); normals->push_back(osg::Vec3(normal.X(), normal.Y(),normal.Z()));
} triGeom->setVertexArray(vertices.get());
triGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, , vertices->size()));
triGeom->setNormalArray(normals);
triGeom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); geode->addDrawable(triGeom); return geode.release();
} int main(int argc, char* argv[])
{
osgViewer::Viewer myViewer; std::string strFile; (argc > ) ? strFile = argv[] : strFile = "ChineseDragon-10kv.off"; myViewer.setSceneData(buildMesh(strFile)); myViewer.addEventHandler(new osgGA::StateSetManipulator(myViewer.getCamera()->getOrCreateStateSet()));
myViewer.addEventHandler(new osgViewer::StatsHandler);
myViewer.addEventHandler(new osgViewer::WindowSizeHandler); return myViewer.run();
}
程序效果图如下所示:
![]()
Figure 3.1 ChineseDragon-10kv.off
![]()
Figure 3.2 Camel.off
![]()
Figure 3.3 cow.off
![]()
Figure 3.4 elephant.off
![]()
Figure 3.5 man.off
![]()
Figure 3.6 pinion.off
![]()
Figure 3.7 spool.off
![]()
Figure 3.8 bones.off
![]()
Figure 3.9 couplingdown.off
![]()
Figure 3.10 rotor.off
![]()
Figure 3.11 joint.off
![]()
Figure 3.12 knot1.off
![]()
Figure 3.13 anchor.off
![]()
Figure 3.14 mushroom.off
![]()
Figure 3.15 sphere.off
![]()
Figure 3.16 star.off
看到这些三维模型,很有感觉!在有关计算机图形学的期刊上有可能也会看到上面的模型。
四、结论 Conclusion
三角网格在计算中用来近似表示三维模型。存储三角网格的标准方式是使用索引三角网格方式。结合OpenCascade中的数据结构,将CGAL示例中的off文件在OpenSceneGraph中显示出来,感觉很棒!
如果加上osgUtil::SmoothingVisitor,效果应该会更好。
PDF Version: Mesh Data Structure in OpenCascade
Mesh Data Structure in OpenCascade的更多相关文章
- [LeetCode] All O`one Data Structure 全O(1)的数据结构
Implement a data structure supporting the following operations: Inc(Key) - Inserts a new key with va ...
- [LeetCode] Add and Search Word - Data structure design 添加和查找单词-数据结构设计
Design a data structure that supports the following two operations: void addWord(word) bool search(w ...
- [LeetCode] Two Sum III - Data structure design 两数之和之三 - 数据结构设计
Design and implement a TwoSum class. It should support the following operations:add and find. add - ...
- Finger Trees: A Simple General-purpose Data Structure
http://staff.city.ac.uk/~ross/papers/FingerTree.html Summary We present 2-3 finger trees, a function ...
- ✡ leetcode 170. Two Sum III - Data structure design 设计two sum模式 --------- java
Design and implement a TwoSum class. It should support the following operations: add and find. add - ...
- leetcode Add and Search Word - Data structure design
我要在这里装个逼啦 class WordDictionary(object): def __init__(self): """ initialize your data ...
- Java for LeetCode 211 Add and Search Word - Data structure design
Design a data structure that supports the following two operations: void addWord(word)bool search(wo ...
- HDU5739 Fantasia(点双连通分量 + Block Forest Data Structure)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5739 Description Professor Zhang has an undirect ...
- LeetCode Two Sum III - Data structure design
原题链接在这里:https://leetcode.com/problems/two-sum-iii-data-structure-design/ 题目: Design and implement a ...
随机推荐
- 双向链表、双向循环链表的JS实现
关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法: 单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...
- 做 Web 开发少不了这些的
抱歉,似乎有些标题党了.最近做服务器的热备,整理了些李纳斯工具的适用方法.看看还有不错的. 基本命令 sleep 500 暂停 ctrl + z 暂停 progress & 后台运行 jobs ...
- Windows7-USB-DVD-tool提示不能拷贝文件的处理
打开 Windows7-USB-DVD-tool所在目录的log/日志 01/28/2016 02:21:02: Drive selected, H:\; Ready01/28/2016 02:21 ...
- myEclipse Could not create the view: An unexpected exception was thrown.
myEclipse 非正常关闭,打开后 service Explorer or Package Explorer 视图显示不出来.报“Could not create the view: An une ...
- mysql安装流程
一.配置MySQL数据库 1.解压绿色版mysql,如下图 二.安装服务 1.运行cmd(管理员版本,否则没有权限),如下图 2.运行命令mysqld –install安装服务,如下图: 如果不需要m ...
- oracle导出一条二进制数据(二进制,long只能通过dmp导出)
exp jxfoc/JXFOC@ORCL file=d:\dd.dmp tables=(jxfoc.FLIGHT_PLAN_MAKE_LOG,jxfoc.METAR_CONTENT_FOR_MAIL) ...
- JavaIO 将数据写入到文件中去
package com.Practice_FileWriter; import java.io.FileWriter; import java.io.IOException; public class ...
- java学习中的一些疑惑解答
一.java中的枚举类型: 在实际编程中,往往存在着这样的"数据集",它们的数值在程序中是稳定的,而且"数据集"中的元素是有限的.例如星期一到星期日七个数据元素 ...
- PHP如何使用GeoIP数据库
1.首先下载GeoIP的IP库.参考<利用GeoIP数据库及API进行地理定位查询>.下载后解压,得到一个GeoIP.dat文件 2.新建一个文件geoip.inc.内容为 <?ph ...
- ArcGIS10的附件功能
转自 积思园 http://blog.csdn.net/linghe301/article/details/6386176 老是忘记怎么使用这个ArcGIS10的附件功能,这次就做个记录吧. 在项目应 ...