网站域名年费网站推广计划书范文500字
目录
- 本节内容
- 本节代码
- 思路
- 具体实现
- 注意
- 以下为全部代码
本节内容
经常的我们想看看模型的法线对不对,如本节下图所示:
我们就想把模型的法线绘制出来。本节就介绍这个小功能。
本节代码
本节资源在如下链接/文件中的附件/按章节编号目录中:
【击此打开网盘资源链接】
也可以在本文末获取
思路
遍历所有的Geode,然后将其里面所有的Geometry的,凡是有法线的,都给生成法线。法线的起点是该顶点,方向是法线的方向,长度可以根据包围盒的半径大小来。
具体实现
1、我们遍历模型的所有的Geode
class BuildNormal : public osg::NodeVisitor
{
public:BuildNormal() :osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}virtual void apply(osg::Geode& gnode){在这里做事情}
}
2、遍历gnode中所有的Geometry
virtual void apply(osg::Geode& gnode){//先看其里有多少个geometry,给每个geometry的每个顶点的法线生成一条实体线,再添加到gnode中//因为添加之后gnode的子结点就会增多,为了避免给法线的实体线再生成法线,因此这里先获取int geomNum = gnode.getNumDrawables();for (int i = 0; i < geomNum; i++){osg::Geometry* geom = gnode.getDrawable(i)->asGeometry();if (nullptr != geom){//在这里搞事情}}traverse(gnode);}
3、如果geom有逐顶点绑定的法线则申请几何体开始绘制:
if (nullptr != geom){//先判断有法线而且是逐顶点绑定osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(geom->getNormalArray());if ((nullptr != normal) && (geom->getNormalBinding() == osg::Array::BIND_PER_VERTEX)){//给法线生成Geometryosg::Geometry* geomNormalLine = new osg::Geometry();gnode.addDrawable(geomNormalLine);//关闭光照geomNormalLine->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);//申请顶点osg::Vec3Array* nVertex = new osg::Vec3Array;geomNormalLine->setVertexArray(nVertex);//申请颜色数组osg::Vec4Array* nColor = new osg::Vec4Array;geomNormalLine->setColorArray(nColor, osg::Array::BIND_PER_VERTEX);//为每个顶点生成一条线{osg::Vec3Array* vertex = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());if (nullptr != vertex){for (int j = 0; j < vertex->size(); j++){//压入当前顶点为第一个顶点nVertex->push_back(vertex->at(j));//压入颜色osg::Vec3 colorTemp = vertex->at(j);colorTemp.normalize();nColor->push_back(osg::Vec4(colorTemp.x(), colorTemp.y(), colorTemp.z(), 1.0));//得到法线osg::Vec3 normalTemp = normal->at(j);nColor->push_back(osg::Vec4(normalTemp.x(), normalTemp.y(), normalTemp.z(), 1.0));//得到顶点,为在法线方向上延长当前包围盒的半径的0.1倍float n = gnode.getBound().radius() * 0.1;nVertex->push_back(vertex->at(j) + normalTemp * n);}}}geomNormalLine->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, nVertex->size()));}}
注意
为什么要把绘制的geometry加到与法线所在的geometry同一个gnode当中,原因是这个gnode可能经过了平移旋转等操作,如果在根结点单独申请gnode,这样的操作复制起来就很麻烦。
以下为全部代码
// c.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/NodeVisitor>//为模型生成法线,法线放在同一个几何体当中
class BuildNormal : public osg::NodeVisitor
{
public:BuildNormal() :osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}virtual void apply(osg::Geode& gnode){//先看其里有多少个geometry,给每个geometry的每个顶点的法线生成一条实体线,再添加到gnode中//因为添加之后gnode的子结点就会增多,为了避免给法线的实体线再生成法线,因此这里先获取int geomNum = gnode.getNumDrawables();for (int i = 0; i < geomNum; i++){osg::Geometry* geom = gnode.getDrawable(i)->asGeometry();if (nullptr != geom){//先判断有法线而且是逐顶点绑定osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(geom->getNormalArray());if ((nullptr != normal) && (geom->getNormalBinding() == osg::Array::BIND_PER_VERTEX)){//给法线生成Geometryosg::Geometry* geomNormalLine = new osg::Geometry();gnode.addDrawable(geomNormalLine);//关闭光照geomNormalLine->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);//申请顶点osg::Vec3Array* nVertex = new osg::Vec3Array;geomNormalLine->setVertexArray(nVertex);//申请颜色数组osg::Vec4Array* nColor = new osg::Vec4Array;geomNormalLine->setColorArray(nColor, osg::Array::BIND_PER_VERTEX);//为每个顶点生成一条线{osg::Vec3Array* vertex = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());if (nullptr != vertex){for (int j = 0; j < vertex->size(); j++){//压入当前顶点为第一个顶点nVertex->push_back(vertex->at(j));//压入颜色osg::Vec3 colorTemp = vertex->at(j);colorTemp.normalize();nColor->push_back(osg::Vec4(colorTemp.x(), colorTemp.y(), colorTemp.z(), 1.0));//得到法线osg::Vec3 normalTemp = normal->at(j);nColor->push_back(osg::Vec4(normalTemp.x(), normalTemp.y(), normalTemp.z(), 1.0));//得到顶点,为在法线方向上延长当前包围盒的半径的0.1倍float n = gnode.getBound().radius() * 0.1;nVertex->push_back(vertex->at(j) + normalTemp * n);}}}geomNormalLine->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, nVertex->size()));}}}traverse(gnode);}
};int main()
{osgViewer::Viewer viewer;//读一个模型osg::Node* pNode = osgDB::readNodeFile("glider.osg");//为其生成法线BuildNormal bn;pNode->accept(bn);viewer.setSceneData(pNode);viewer.run();return 0;
}