osg 几何体绘制

发布于:2022-11-27 ⋅ 阅读:(493) ⋅ 点赞:(0)

目录

1、场景基本绘图类

1.1、Geometry 绘制几何体

1.1.1、顶点属性

1.1.2、图元

1.1.3、图元组

2、使用 OSG 预定义的几何体

2.1、osg::Shape 类

2.2、osg::ShapeDrawable 类

2.3、网格化类

3、实战示例

3.1、画五角星 (DrawArrays 方式)

3.2、画实心五角星(DrawElements 方式)

3.3、画圆锥


1、场景基本绘图类

OSG 通常由三种处理几何体的手段:

  1. 使用松散封装的 OpenGL 绘图基元
  2. 使用 OSG 中的基本几何体
  3. 从文件中导入场景模型

1.1、Geometry 绘制几何体

使用 Geometry 绘制几何体时,需要了解以下概念:

1.1.1、顶点属性

几何体时由顶点组成的,当顶点为空时,无法绘制几何体;

顶点属性定义每一顶点的信息,包括:

  • 顶点坐标(描述顶点位置信息) ----- 必要的
  • 顶点颜色(描述顶点的默认颜色值)
  • 顶点法线(用于计算光照)
  • 纹理坐标(描述顶点使用的纹理位置信息)
  • 等等。。。

其中,对于颜色、法线等属性,提供了绑定方式,包括:

  • 绑定每个顶点(BING_PER_VERTEX)

该模式下,颜色或法线的数量需要和顶点数量一致,每一顶点对应一个属性值;

  • 绑定图元组(BING_PER_PRIMITIVE_SET)

该模式下,颜色或法线的数量需要和图元组数量一致,每一图元组使用一个属性值;

  • 绑定所有(BIND_OVERALL)

该模式下,整个绘制体使用一个属性值。

1.1.2、图元

        osg::PrimitiveSet 类, 该类主要松散封装了 OpenGL 的绘图基元,通过指定绘图基元来指定几何体顶点将采用哪一种或几种基元绘制。

图元类型:

  • POINGS        // 绘制点                               
  • LINES           // 绘制线
  • LINE_STRIP          // 绘制多段线
  • LINE_LOOP          // 绘制封闭线
  • TRIANGLES         // 绘制三角形
  • TRIANGLE_STRIP       // 绘制多个三角形

TRIANGLE_FAN          // 绘制多个三角扇

  • QUADS                   // 绘制四边形
  • QUAD_STRIP        // 绘制多个四边形
  • POLYGON             // 绘制多边形

1.1.3、图元组

        图元组告诉 OSG, 在绘制图形时,使用哪些顶点、使用哪个图元对顶点进行结合。

图元由两种:

  • DrawArrays
    • DrawArrays 直接告诉 OSG 使用的顶点在顶点数组中的起点、终点和使用的图元
    • 复杂的莫模型需要传入较多的点且比较麻烦
    • 效率高
  • DrawElements
    • DrawElements 告诉 OSG 使用顶点的索引值数组和图元
    • 该方式不需要传入重复的点数据,使用简单
    • 由于内部需要复制数据,因此效率较低

2、使用 OSG 预定义的几何体

再 OSG 中,为了简化场景的绘制,它本身预定义了一些常用的几何体。

2.1、osg::Shape 类

  • osg::Shape 类直接继承自 osg::Object 基类。
  • osg::Shape 类是各种内嵌几何体的基类,它不但可用于碰撞检测,还可用于生成预定义的几何体对象。

常用的内嵌几何体包括以下几种:

  • osg::Box                        // 正方体
  • osg::Capsule                // 太空舱
  • osg::Cone                    // 锥体
  • osg::Cylinder                // 柱体
  • osg::HeightField           // 高度图
  • osg::InfinitePlane          // 无线平面
  • osg::Sphere                  // 球体
  • osg::TriangleMesh        // 三角片

2.2、osg::ShapeDrawable 类

        如果渲染内嵌的几何体,就必须将其与 osg::Drawable 相关联。实际应用中,可以使用 osg::Drawable 的派生类 osg::ShapeDrawable 来完成这个功能。 

在 osg::ShapeDrawable 类的构造方法中提供了关联 osg::Shape 的方法:

// 第一个参数为 shape, 第二个参数默认不细化
ShapeDrawable(Shape* shape, TessellationHints = 0);

同时,由于它继承 osg::Drawable 类,所以 它的实例需要被添加到叶节点中才能被实例绘制。

2.3、网格化类

        osg::TessellationHints 类的主要作用是设置预定义几何体对象的精细程度,精细程度越高,表示其细分越详细,但对于不同的预定义几何体对象,它的作用是不一样的。例如:

  • Box ( 四棱柱 ):网格化类对四棱柱没有意义
  • Capsule ( 太空舱 ):太空舱分为上下半球部分和圆柱侧面部分,默认细化侧面部分
  • Cone ( 圆锥 ):直接细分
  • Cylinder ( 柱体 ):直接细分
  • Sphere ( 球 ):直接细分 

3、实战示例

3.1、画五角星 (DrawArrays 方式)

1、先创建五角星的顶点

// 创建五角星的顶点 (五角星需要十个顶点)
osg::ref_ptr<osg::Vec3Array> createFiveStarVertecs()
{
    osg::ref_ptr<osg::Vec3Array> vertexs = new osg::Vec3Array();
    int n = 10;
    double step = 360 / n;
    
    for(int i = 0; i < n; i++)
    {
        double x = sin(osg::DegressToRadiaus(i * step));
        double y = cos(osg::DegressToRadiaus(i * step));
        double z = 0.0;

        // 五角星内环的五个点
        if(i % != 0)
        {
            x = x * 0.35;
            y = y * 0.35;
        }
        vertex->push_back(osg::Vec3(x, y, z));
    }

    return vertex.release();
}

2、画五角星

// 画五角星
osg::ref_ptr<osg::MatrixTransform> drawFiveStar()
{
    osg::ref_ptr<osg::MatrixTransform> trans = new osg::MatrixTransform;
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;

    // 顶点
    osg::ref_ptr<osg::Vec3Array> vertexs = createFiveStarVertexs();
    
    // 添加顶点
    geometry->setVertexArray(veretexs);
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimiteveSet::LINE_LOOP, 0, 10));

    geode->addDrawable(geometry);
    trans->addChild(geode);
    return trans;
}

3.2、画实心五角星(DrawElements 方式)

画实心五角星与画五角星完全不同,

因为五角星只是画一条封闭的线 LINE_LOOP,

而实心五角星需要以多边形的形式画出来,而多边形只能画凸多边形,不能直接画,

所以,要把实心五角星分为多个凸多边形拼凑起来。

依然使用上述五角星的顶点

// 画实心五角星
osg::ref_ptr<osg::MatrixTransform> drawSolidFiveStar()
{
    osg::ref_ptr<osg::MatrixTransform> trans = new osg::MatrixTransform;
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;

    // 顶点
    osg::ref_ptr<osg::Vec3Array> vertexs = createFiveStarVertexs();
    
    // 添加顶点
    geometry->setVertexArray(veretexs);

    // 先画五角星中间的五边形 
    osg::ref_ptr<osg::DrawElementsUInt> polygonElement = new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON, 0, 5);
    // DrawElements 方式里面加的是 顶点集合的索引值, 可以重复使用
    polygonElement->addElement(1);
    polygonElement->addElement(3);
    polygonElement->addElement(5);
    polygonElement->addElement(7);
    polygonElement->addElement(9);
    geometry->addPrimitiveSet(polyginElement);

    // 后绘制五角星外围的五个小五角形
    for(int i = 1; i < 10; i +=2)
    {
        osg::ref_ptr<osg::DrawElementsUInt> triangleElement = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0, 3);
        triangleElement->addElement(i);
        // 如果超出顶点索引的最大范围,使用索引减去顶点的总数
        i + 1 > 9 ? triangleElement->addElement(i + 1 - 10) : triangleElement->addElement(i + 1);
        i + 2 > 9 ? triangleElement->addElement(i + 2 - 10) : triangleElement->addElement(i + 2);

        geometry->addPeimitiveSet(triangleElement);
    }
    geometry->addDrawable(geometry);
    trans->addChild(geometry);
    return trans;
}

3.3、画圆锥

画圆锥需要画一个底部的圆, 和一个圆锥侧面的面

1、创建圆锥的顶点

// 创建圆锥的顶点
osg::ref_ptr<osg::Vec3Array> createConeVertexs()
{
    osg::ref_ptr<osg::Vec3Array> vertexs = new osg::Vec3Array;
    // 添加圆锥的顶点
    vertexs->push_back(osg::Vec3(0, 0, 2));

    // 圆锥底部由20个点组成
    int n = 20;
    double step = 360 / n;
    
    for(int i = 0; i < n; i++)
    {
        double x = sin(osg::DegressToRadiaus(i * step));
        double y = cos(osg::DegressToRadiaus(i * step));
        double z = 0.0;

        vertexs->push_back(osg::Vec3(x, y, z));
    }
    return vertexs;
}

 2、画圆锥

// 画圆锥
osg::ref_ptr<osg::MatrixTransform> drawCone()
{
    osg::ref_ptr<osg::MatrixTransform> trans = new osg::MatrixTransform;
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;

    // 获取圆锥的顶点
    osg::ref_ptr<osg::Vec3Array> vertexs = createConeVertexs();
    // 设置顶点
    geometry->setVertexArray(vertexs);
    // 先画圆锥侧面的面
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN, 0, 21));
    // 后画圆锥底部的圆
    geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 1, 20));

    geode->addDrawable(geometry);
    trans->addChild(geode);
    return trans;
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到