一、前言
实现思路:先绘制半个圆,再添加四个裁剪面,这么拼凑一下就感觉有那么点意思呢:)。
二、效果
三、关键代码
void EffectPhasedArrayRadar::RebuildEntityBody()
{
if (m_pGeode.valid()) {
mat->removeChild(m_pGeode.get());
m_pGeode = nullptr;
}
if (m_pGridCopy.valid()) {
mat->removeChild(m_pGridCopy.get());
m_pGridCopy = nullptr;
}
if (m_pPatch1.valid()) {
mat->removeChild(m_pPatch1.get());
m_pPatch1 = nullptr;
}
if (m_pPatch2.valid()) {
mat->removeChild(m_pPatch2.get());
m_pPatch2 = nullptr;
}
if (m_pPatch3.valid()) {
mat->removeChild(m_pPatch3.get());
m_pPatch3 = nullptr;
}
if (m_pPatch4.valid()) {
mat->removeChild(m_pPatch4.get());
m_pPatch4 = nullptr;
}
if (m_pClippedSubgraph.valid()) {
mat->removeChild(m_pClippedSubgraph.get());
m_pClippedSubgraph = nullptr;
}
if (m_pFanMT.valid()) {
mat->removeChild(m_pFanMT.get());
m_pFanMT = nullptr;
}
m_pGeode = new Geode();
//设置三维曲面采样步长
constexpr double dStep = 11.25;
//垂直方向循环
for (double vAngle = 0; vAngle <= 60; vAngle += dStep)
{
//三维曲面的半透明蒙皮,通过QUAD_STRIP图元合成
m_polySkin = new Geometry();
//计算蒙皮所需要的采样点数量
constexpr int numCoordsSkin = (360 / dStep + 1) * 2;//146
//申请蒙皮采样点
Vec3 myCoordsSkin[numCoordsSkin];// = new Vec3[numCoordsSkin];
osg::ref_ptr<Vec4Array> colorsSkin = new Vec4Array;
osg::ref_ptr<Vec3Array> normals = new Vec3Array;
normals->push_back(Vec3(0.0f, -1.0f, 0.0f));
int index = 0;
//水平方向循环
for (double hAngle = 0; hAngle <= 360; hAngle += dStep)
{
double vAngleR = DegreesToRadians(vAngle);
double hAngleR = DegreesToRadians(hAngle);
double vAngleNextStepR = DegreesToRadians(vAngle + dStep);
//计算蒙皮的采样点坐标,同时计算对应的显示颜色
//圈上的点
myCoordsSkin[index] = Vec3(
m_dRadius *sin(vAngleR)*cos(hAngleR),
m_dRadius *sin(vAngleR)* sin(hAngleR),
m_dRadius * cos(vAngleR));
//圈上方点
myCoordsSkin[index + 1] = Vec3(
m_dRadius *sin(vAngleNextStepR) * cos(hAngleR),
m_dRadius *sin(vAngleNextStepR) * sin(hAngleR),
m_dRadius * cos(vAngleNextStepR));
colorsSkin->push_back(Vec4(0.0,1.0,1.0, m_dColorAlpha));
colorsSkin->push_back(Vec4(0.0, 1.0, 1.0, m_dColorAlpha));
index += 2;
}
m_verticesSkin = new Vec3Array(numCoordsSkin, myCoordsSkin);
m_polySkin->setVertexArray(m_verticesSkin);
//设置曲面的颜色为逐点设置
m_polySkin->setColorArray(colorsSkin.get(), Array::BIND_PER_VERTEX);
//m_polySkin->setNormalArray(normals, Array::BIND_OVERALL);
//设置曲面的图元类型为QUAD_STRIP
m_polySkin->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUAD_STRIP, 0, numCoordsSkin));//QUAD_STRIP为四边形,三角面数相同
//设置曲面半透明效果的一条关键语句,少了该句会导致半透明显示错误,暂未搞清楚该句的原理
m_polySkin->getOrCreateStateSet()->setAttribute(new Depth(Depth::LESS, 0.0, 1.0, false));
//开启曲面的半透明效果
m_polySkin->getOrCreateStateSet()->setMode(GL_BLEND, StateAttribute::ON);
m_polySkin->getOrCreateStateSet()->setRenderingHint(StateSet::TRANSPARENT_BIN);
m_polySkin->getOrCreateStateSet()->setMode(GL_LIGHTING, StateAttribute::OFF);
//背面剔除
m_polySkin->getOrCreateStateSet()->setMode(GL_CULL_FACE, StateAttribute::OFF);
//smooth geoset by creating per vertex normals.
osgUtil::SmoothingVisitor::smooth(*m_polySkin.get());
m_pGeode->addDrawable(m_polySkin);
}
//绘制网格线
m_pGridCopy = dynamic_cast<Geode *>(m_pGeode->clone(CopyOp::DEEP_COPY_ALL));
ref_ptr<StateSet> spStateSet = m_pGridCopy->getOrCreateStateSet();
ref_ptr<PolygonMode> polyMode = new PolygonMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
spStateSet->setAttribute(polyMode);
// 设置线框颜色
osg::ref_ptr<osg::Material> material = new osg::Material();
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 1, 1, 1));
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 1, 1, 1));
spStateSet->setAttributeAndModes(material, osg::StateAttribute::ON);
// 启用多边形偏移解决Z-fighting
ref_ptr<PolygonOffset> polyOffset = new PolygonOffset;
polyOffset->setFactor(-1.0f);
polyOffset->setUnits(-1.0f);
spStateSet->setAttributeAndModes(polyOffset, StateAttribute::ON);
// 关闭透明混合
spStateSet->setMode(GL_BLEND, StateAttribute::OFF);
spStateSet->setRenderingHint(StateSet::OPAQUE_BIN);
// 确保深度测试正确
spStateSet->setMode(GL_DEPTH_TEST, StateAttribute::ON);
spStateSet->setMode(GL_LIGHTING, StateAttribute::OFF);
ref_ptr<LineWidth> lineWidth = new LineWidth(1.0f);
spStateSet->setAttribute(lineWidth);
// 创建裁剪节点和裁剪平面
osg::ref_ptr<osg::ClipPlane> clipPlane1 = new osg::ClipPlane(0, osg::Vec4d(0, 0.707, 0.707, 0.0));
osg::ref_ptr<osg::ClipPlane> clipPlane2 = new osg::ClipPlane(1, osg::Vec4d(0, -0.707, 0.707, 0.0));
osg::ref_ptr<osg::ClipPlane> clipPlane3 = new osg::ClipPlane(2, osg::Vec4d(0.707, 0, 0.707, 0.0));
osg::ref_ptr<osg::ClipPlane> clipPlane4 = new osg::ClipPlane(3, osg::Vec4d(-0.707, 0, 0.707, 0.0));
m_pClippedSubgraph = new osg::Group;
osg::ref_ptr<osg::StateSet> stateset = m_pClippedSubgraph->getOrCreateStateSet();
//添加裁剪面
stateset->setAttributeAndModes(clipPlane1, osg::StateAttribute::ON);
stateset->setAttributeAndModes(clipPlane2, osg::StateAttribute::ON);
stateset->setAttributeAndModes(clipPlane3, osg::StateAttribute::ON);
stateset->setAttributeAndModes(clipPlane4, osg::StateAttribute::ON);
//stateset->setMode(GL_CLIP_PLANE0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
//stateset->setMode(GL_CLIP_PLANE1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
//stateset->setMode(GL_CLIP_PLANE2, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
//stateset->setMode(GL_CLIP_PLANE3, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
// 被裁剪的部分(原半球)
m_pClippedSubgraph->addChild(m_pGeode.get());
m_pClippedSubgraph->addChild(m_pGridCopy.get());
/*
创建补全的四个面,y朝下x朝右
如果将四个补面和扇子添加到m_pClippedSubgraph里面就更完美,但不知道为什么,添加进去就会闪烁
有时间了再演技。
*/
//+x轴方向的补面
m_pPatch1 = CreatePatch(-45.0, osg::Vec3d(0, 1, 0), 45.0, -45.0);
mat->addChild(m_pPatch1.get());
//-y轴方向的补面
m_pPatch2 = CreatePatch(45.0, osg::Vec3d(1, 0, 0), 135.0, 45.0);
mat->addChild(m_pPatch2.get());
//-x轴方向补面
m_pPatch3 = CreatePatch(45.0, osg::Vec3d(0, 1, 0), 225.0, 135.0);
mat->addChild(m_pPatch3.get());
//+y轴方向补面
m_pPatch4 = CreatePatch(-45.0, osg::Vec3d(1, 0, 0), 315.0, 225.0);
mat->addChild(m_pPatch4.get());
//中间的扇子
m_pFanMT = new osg::MatrixTransform();
m_pFanMT->addChild(CreateSector(135, 45, 0.5).get());
mat->addChild(m_pFanMT.get());
mat->addChild(m_pClippedSubgraph.get());
}
原创不易,记得点赞加关注哦,我会持续分享实用的功能(:-