Mesh Data Structure in OpenCascade

eryar@163.com

摘要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,效果应该会更好。

Mesh Data Structure in OpenCascade的更多相关文章

  1. [LeetCode] All O`one Data Structure 全O(1)的数据结构

    Implement a data structure supporting the following operations: Inc(Key) - Inserts a new key with va ...

  2. [LeetCode] Add and Search Word - Data structure design 添加和查找单词-数据结构设计

    Design a data structure that supports the following two operations: void addWord(word) bool search(w ...

  3. [LeetCode] Two Sum III - Data structure design 两数之和之三 - 数据结构设计

    Design and implement a TwoSum class. It should support the following operations:add and find. add - ...

  4. 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 ...

  5. ✡ 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 - ...

  6. leetcode Add and Search Word - Data structure design

    我要在这里装个逼啦 class WordDictionary(object): def __init__(self): """ initialize your data ...

  7. 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 ...

  8. HDU5739 Fantasia(点双连通分量 + Block Forest Data Structure)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5739 Description Professor Zhang has an undirect ...

  9. LeetCode Two Sum III - Data structure design

    原题链接在这里:https://leetcode.com/problems/two-sum-iii-data-structure-design/ 题目: Design and implement a ...

随机推荐

  1. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

  2. 做 Web 开发少不了这些的

    抱歉,似乎有些标题党了.最近做服务器的热备,整理了些李纳斯工具的适用方法.看看还有不错的. 基本命令 sleep 500 暂停 ctrl + z 暂停 progress & 后台运行 jobs ...

  3. Windows7-USB-DVD-tool提示不能拷贝文件的处理

    打开  Windows7-USB-DVD-tool所在目录的log/日志 01/28/2016 02:21:02: Drive selected, H:\; Ready01/28/2016 02:21 ...

  4. myEclipse Could not create the view: An unexpected exception was thrown.

    myEclipse 非正常关闭,打开后 service Explorer or Package Explorer 视图显示不出来.报“Could not create the view: An une ...

  5. mysql安装流程

    一.配置MySQL数据库 1.解压绿色版mysql,如下图 二.安装服务 1.运行cmd(管理员版本,否则没有权限),如下图 2.运行命令mysqld –install安装服务,如下图: 如果不需要m ...

  6. oracle导出一条二进制数据(二进制,long只能通过dmp导出)

    exp jxfoc/JXFOC@ORCL file=d:\dd.dmp tables=(jxfoc.FLIGHT_PLAN_MAKE_LOG,jxfoc.METAR_CONTENT_FOR_MAIL) ...

  7. JavaIO 将数据写入到文件中去

    package com.Practice_FileWriter; import java.io.FileWriter; import java.io.IOException; public class ...

  8. java学习中的一些疑惑解答

    一.java中的枚举类型: 在实际编程中,往往存在着这样的"数据集",它们的数值在程序中是稳定的,而且"数据集"中的元素是有限的.例如星期一到星期日七个数据元素 ...

  9. PHP如何使用GeoIP数据库

    1.首先下载GeoIP的IP库.参考<利用GeoIP数据库及API进行地理定位查询>.下载后解压,得到一个GeoIP.dat文件 2.新建一个文件geoip.inc.内容为 <?ph ...

  10. ArcGIS10的附件功能

    转自 积思园 http://blog.csdn.net/linghe301/article/details/6386176 老是忘记怎么使用这个ArcGIS10的附件功能,这次就做个记录吧. 在项目应 ...