osg::NodeVisitor中计算一个节点对应的世界变换矩阵、法向量、顶点坐标
class MyNodeVisitor:public osg::NodeVisitor
{
pulic:
MyNodeVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{}
void apply(osg::Geode& geode)
{
//计算当前geode节点对应的世界变换矩阵,用来计算geode中顶点对应的世界坐标
osg::Matrix geodeMatrix=osg::computeLocalToWorld(getNodePath());
unsigned int count=geode.getNumDrawables();
for(unsigned int geomIdx=0; geomIdx<count; geomIdx++)
{
osg::Geometery *geometry = geode.getDrawable(geomIdx)->asGeometry();
if(!geometry) continue;
//顶点数据
osg::Vec3Array* vertices=dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
//法向量
osg::Vec3Array* normals=dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
//索引数组
for(unsigned int primitiveIdx=0; primitiveIdx<geometry->getNumPrimitiveSets(); ++primitiveIdx)
{
osg::PrimitiveSet* ps=geometry->getPrimitiveSet(primitiveIdx);
if(!ps) continue;
switch(ps->getType())
{
case osg::PrimitiveSet::DrawElementsUShortPrimitiveType:
{
osg::DrawElementsUShort* deus=dynamic_cast<osg::DrawElementsUShort*>(ps);
const unsigned int indexNum=deus->getNumIndices();
switch(deus->getMode)
{
case osg::PrimitiveSet::TRIANGLES:
//假设geometry->getNormalBinding()==osg::Geometry::BIND_PER_VERTEX)
//即每一个顶点对应一个法向量
for(unsigned int i=0; i<indexNum; i++)
{
//顶点索引
unsigned int idx=deus->at(i);
//法向量。需要转换成世界坐标,需要乘以geodeMatrix的逆矩阵的转置,具体原因可以参考计算法向量那篇随笔
Vec3 normalWorld=normals->at(idx)*(geodeMatrix的逆矩阵的转置);
//顶点坐标
Vec3 vertexWorld=vertices->at(idx)*geodeMatrix;
}
break;
}
}
}
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决