博客
关于我
OSG学习:几何对象的绘制(二)——简易房屋
阅读量:804 次
发布时间:2023-02-26

本文共 7292 字,大约阅读时间需要 24 分钟。

OSG 三维渲染引擎编程实践:房屋建模示例

本文将介绍 OpenSceneGraph(OpenSceneGraph,简称 OSG)三维渲染引擎的使用方法,通过一个简易房屋建模的例子,详细讲解从项目配置到几何体绘制的整个流程。

1. 基本配置与环境搭建

在开始编程之前,需要完成以下步骤:

  • 安装 OSG 开发环境

    • 下载并安装 OSG 的开发包,通常包含必要的头文件和库文件。
    • 在项目中配置环境变量,确保编译器能够找到 OSG 的头文件和库文件。
  • 创建新项目

    • 使用合适的开发工具(如 Visual Studio)创建新项目。
    • 在项目中添加 OSG 的相关库,通常需要手动添加依赖项。
  • 配置项目

    • 通过项目配置文件(如 vcproj)添加必要的包含路径和库路径。
    • 确保所有 OSG 相关的头文件和库文件都被正确添加。
  • 2. 简易房屋建模

    在本节中,我们将通过代码示例详细讲解如何创建一个简单的房屋模型。房屋模型将由两个部分组成:房屋墙体和房屋顶部(屋顶)。

    2.1 房屋墙体建模

  • 顶点定义

    房屋墙体是一个人字顶,由 10 个顶点组成。顶点坐标如下:

    // 顶点坐标vertices->push_back(osg::Vec3(0.0, 0.0, 4.0));  // 顶部左前角vertices->push_back(osg::Vec3(0.0, 0.0, 0.0));  // 底部左前角vertices->push_back(osg::Vec3(6.0, 0.0, 4.0));  // 顶部右前角vertices->push_back(osg::Vec3(6.0, 0.0, 0.0));  // 底部右前角vertices->push_back(osg::Vec3(6.0, 4.0, 4.0));  // 顶部右后角vertices->push_back(osg::Vec3(6.0, 4.0, 0.0));  // 底部右后角vertices->push_back(osg::Vec3(0.0, 4.0, 4.0));  // 顶部左后角vertices->push_back(osg::Vec3(0.0, 4.0, 0.0));  // 底部左后角vertices->push_back(osg::Vec3(0.0, 0.0, 4.0));  // 顶部左前角
  • 法线定义

    每个顶点都需要对应的法线向量。以下是墙体各顶点的法线坐标:

    // 法线坐标(*normals)[0].set(-0.707, -0.707, 0.0);  // 顶部左前角(*normals)[1].set(-0.707, -0.707, 0.0);  // 底部左前角(*normals)[2].set(0.707, -0.707, 0.0);  // 顶部右前角(*normals)[3].set(0.707, -0.707, 0.0);  // 底部右前角(*normals)[4].set(0.707, 0.707, 0.0);  // 顶部右后角(*normals)[5].set(0.707, 0.707, 0.0);  // 底部右后角(*normals)[6].set(-0.707, 0.707, 0.0);  // 顶部左后角(*normals)[7].set(-0.707, 0.707, 0.0);  // 底部左后角(*normals)[8].set(-0.707, -0.707, 0.0);  // 顶部左前角
  • 纹理坐标

    每个顶点需要对应的纹理坐标。以下是墙体各顶点的纹理坐标:

    // 纹理坐标(*texcoords)[0].set(0.0, 1.0);        // 顶部左前角(*texcoords)[1].set(0.0, 0.0);        // 底部左前角(*texcoords)[2].set(0.3, 1.0);        // 顶部右前角(*texcoords)[3].set(0.3, 0.0);        // 底部右前角(*texcoords)[4].set(0.5, 1.0);        // 顶部右后角(*texcoords)[5].set(0.5, 0.0);        // 底部右后角(*texcoords)[6].set(0.8, 1.0);        // 顶部左后角(*texcoords)[7].set(0.8, 0.0);        // 底部左后角(*texcoords)[8].set(1.0, 1.0);        // 顶部左前角
  • 几何体创建

    将顶点、法线和纹理坐标设置到几何体对象中,并绘制为多段四边形条带图元:

    // 创建墙体几何体osg::Geometry *houseWall = new osg::Geometry;houseWall->setVertexArray(vertices.get());houseWall->setTexCoordArray(0, texcoords.get());houseWall->setNormalArray(normals.get());houseWall->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);houseWall->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::QUAD_STRIP, 0, 10));houseWall->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readImageFile("wall.bmp")));
  • 2.2 房屋顶部(屋顶)建模

  • 顶点定义

    屋顶由 6 个顶点组成。顶点坐标如下:

    // 顶点坐标vertices->push_back(osg::Vec3(-0.2, -0.5, 3.5));  // 左前下角vertices->push_back(osg::Vec3(6.2, -0.5, 3.5));  // 右前下角vertices->push_back(osg::Vec3(0.8, 2.0, 6.0));  // 左后上角vertices->push_back(osg::Vec3(5.2, 2.0, 6.0));  // 右后上角vertices->push_back(osg::Vec3(-0.2, 4.5, 3.5));  // 左后下角vertices->push_back(osg::Vec3(6.2, 4.5, 3.5));  // 右后下角
  • 顶点绘制方式

    屋顶的绘制方式为多段三角形条带图元。以下是具体实现:

    // 创建屋顶几何体osg::Geometry *houseRoof = new osg::Geometry;houseRoof->setVertexArray(vertices.get());houseRoof->addPrimitiveSet(roof.get());houseRoof->addPrimitiveSet(roofSide.get());
  • 颜色定义

    屋顶使用颜色数组代替纹理贴图,颜色分布如下:

    // 颜色定义colors->push_back(osg::Vec4(0.25, 0.0, 0.0, 1.0));
  • 快速法线生成

    使用 OSG 自带的 SmoothingVisitor 工具快速生成法线:

    osgUtil::SmoothingVisitor smv;smv.smooth(*houseRoof);
  • 最终几何体创建

    将墙体和屋顶合并到一个叶节点中进行渲染:

    // 创建叶节点osg::Geode *geode = new osg::Geode;geode->addDrawable(houseWall);geode->addDrawable(houseRoof);
  • 3. 代码优化与结构分析

    本例中的代码主要优化了以下几个方面:

  • 数组数据管理

    • 动态数组:通过 push_back 动态添加数据,适用于未知长度或需要灵活扩展的场景。
    • 静态数组:在定义时指定长度,适用于已知且固定不变的数据。
  • 几何体绘制流程

    • 墙体:使用多段四边形条带图元绘制,结合纹理贴图实现高效渲染。
    • 屋顶:采用多段三角形条带图元结合颜色数组,实现简易的屋顶效果。
  • 性能优化

    • 使用 SmoothingVisitor 自动生成法线,减少手动计算工作量。
    • 通过合理设置顶点数组和纹理坐标,提升渲染效率。
  • 4. 代码示例总结

    以下是完整的代码示例:

    #include "stdafx.h"#include 
    #include
    #include
    #include
    #include
    // 创建房屋墙体部分osg::Drawable *createHouseWall() { // 创建顶点数组 osg::ref_ptr
    vertices = new osg::Vec3Array; // 添加顶点坐标 vertices->push_back(osg::Vec3(0.0, 0.0, 4.0)); vertices->push_back(osg::Vec3(0.0, 0.0, 0.0)); vertices->push_back(osg::Vec3(6.0, 0.0, 4.0)); vertices->push_back(osg::Vec3(6.0, 0.0, 0.0)); vertices->push_back(osg::Vec3(6.0, 4.0, 4.0)); vertices->push_back(osg::Vec3(6.0, 4.0, 0.0)); vertices->push_back(osg::Vec3(0.0, 4.0, 4.0)); vertices->push_back(osg::Vec3(0.0, 4.0, 0.0)); vertices->push_back(osg::Vec3(0.0, 0.0, 4.0)); // 创建法线数组 osg::ref_ptr
    normals = new osg::Vec3Array(10); // 添加法线坐标 (*normals)[0].set(-0.707, -0.707, 0.0); (*normals)[1].set(-0.707, -0.707, 0.0); (*normals)[2].set(0.707, -0.707, 0.0); (*normals)[3].set(0.707, -0.707, 0.0); (*normals)[4].set(0.707, 0.707, 0.0); (*normals)[5].set(0.707, 0.707, 0.0); (*normals)[6].set(-0.707, 0.707, 0.0); (*normals)[7].set(-0.707, 0.707, 0.0); (*normals)[8].set(-0.707, -0.707, 0.0); (*normals)[9].set(-0.707, -0.707, 0.0); // 创建纹理坐标数组 osg::ref_ptr
    texcoords = new osg::Vec2Array(10); // 添加纹理坐标 (*texcoords)[0].set(0.0, 1.0); (*texcoords)[1].set(0.0, 0.0); (*texcoords)[2].set(0.3, 1.0); (*texcoords)[3].set(0.3, 0.0); (*texcoords)[4].set(0.5, 1.0); (*texcoords)[5].set(0.5, 0.0); (*texcoords)[6].set(0.8, 1.0); (*texcoords)[7].set(0.8, 0.0); (*texcoords)[8].set(1.0, 1.0); (*texcoords)[9].set(1.0, 0.0); // 创建几何体 osg::Geometry *houseWall = new osg::Geometry; houseWall->setVertexArray(vertices.get()); houseWall->setTexCoordArray(0, texcoords.get()); houseWall->setNormalArray(normals.get()); houseWall->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); houseWall->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::QUAD_STRIP, 0, 10)); houseWall->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readImageFile("../wall.bmp"))); return houseWall.release();}// 创建房顶部分osg::Drawable *createHouseRoof() { // 创建顶点数组 osg::ref_ptr
    vertices = new osg::Vec3Array; // 添加顶点坐标 vertices->push_back(osg::Vec3(-0.2, -0.5, 3.5)); vertices->push_back(osg::Vec3(6.2, -0.5, 3.5)); vertices->push_back(osg::Vec3(0.8, 2.0, 6.0)); vertices->push_back(osg::Vec3(5.2, 2.0, 6.0)); vertices->push_back(osg::Vec3(-0.2, 4.5, 3.5)); vertices->push_back(osg::Vec3(6.2, 4.5, 3.5)); // 创建三角形条带图元 osg::DrawArrays *roof = new osg::DrawArrays(osg::DrawArrays::TRIANGLES, 0, 6); osg::DrawElementsUInt *roofSide = new osg::DrawElementsUInt(osg::DrawElementsUInt::TRIANGLES, 6); (*roofSide)[0] = 0; (*roofSide)[1] = 2; (*roofSide)[2] = 4; (*roofSide)[3] = 5; (*roofSide)[4] = 3; (*roofSide)[5] = 1; // 创建颜色数组 osg::ref_ptr
    colors = new osg::Vec4Array; (*colors).push_back(osg::Vec4(0.25, 0.0, 0.0, 1.0)); // 创建几何体 osg::Geometry *houseRoof = new osg::Geometry; houseRoof->setVertexArray(vertices.get()); houseRoof->setColorArray(colors.get()); houseRoof->setColorBinding(osg::Geometry::BIND_OVERALL); houseRoof->addPrimitiveSet(roof.get()); houseRoof->addPrimitiveSet(roofSide.get()); osgUtil::SmoothingVisitor smv; smv.smooth(*houseRoof); return houseRoof.release();}int main(int argc, char **argv) { // 创建叶节点并添加几何体 osg::Geode *geode = new osg::Geode; geode->addDrawable(createHouseWall()); geode->addDrawable(createHouseRoof()); // 创建查看器并渲染场景 osgViewer::Viewer viewer; viewer.setSceneData(geode.get()); return viewer.run();}

    5. 代码优化总结

  • 数组管理

    • 动态数组适用于数据长度未知或需要频繁修改的场景。
    • 静态数组适用于数据长度固定且不会变更的场景。
  • 几何体绘制

    • 增加了法线生成工具 SmoothingVisitor,简化了手动计算。
    • 突出纹理贴图的使用,提升了渲染质量。
  • 结构优化

    • 将顶点、法线和纹理坐标分开管理,提升代码可读性。
    • 使用合适的图元类型(如 QUAD_STRIPTRIANGLES)优化渲染效率。
  • 通过以上优化,本文提供了一个完整的简易房屋建模示例,既详细解释了 OSG 的使用方法,又展示了代码优化的技巧。

    转载地址:http://qkvfk.baihongyu.com/

    你可能感兴趣的文章
    phpmailer发送邮件,可以带附件
    查看>>
    phpmailer的用法
    查看>>
    phpmyadmin 安装
    查看>>
    phpmyadmin导出数据库出现Fatal error: Cannot 'break' 2 levels in D:\phpstudy\WWW\phpMyAdmin
    查看>>
    phpmyadmin数据库建表及插入
    查看>>
    phpnow配置
    查看>>
    phprpc简单使用
    查看>>
    phpspider中当爬虫获取数据时如何去掉广告
    查看>>
    phpstorm 2016.3.3 激活
    查看>>
    phpstorm中Xdebug的使用
    查看>>
    phpstorm中使用svn版本控制器
    查看>>
    phpstorm配置php脚本执行
    查看>>
    PhpStorm配置远程xdebug
    查看>>
    phpstudy+iis搭建php项目
    查看>>
    phpStudy安装教程
    查看>>
    phpstudy搭建网站,通过快解析端口映射外网访问
    查看>>
    phpunit
    查看>>
    PHPUnit单元测试对桩件(stub)和仿件对象(Mock)的理解
    查看>>
    phpweb成品网站最新版(注入、上传、写shell)
    查看>>
    phpWhois 项目推荐
    查看>>