添加斜面描述变量
为了指定斜面的倾斜角度,需要添加一些描述角度的变量,此处为了简化,只添加了俯仰角(及绕物体x轴旋转的角度)。代码如下:
double pitch = osg::PI * 30 / 180; // 仰角30度.
添加结点回调函数类MyRotateCallback
添加结点回调函数类MyRotateCallback,代码如下:
class MyRotateCallback: public osg::NodeCallback
{
public:
MyRotateCallback() {
m_rotate = 0; // 旋转角度(弧度)
}
~MyRotateCallback() {}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) {
ModelNode* mn = dynamic_cast<ModelNode*>(node);
if (mn) {
osg::Quat q1(pitch, osg::X_AXIS,
0, osg::Y_AXIS,
0, osg::Z_AXIS);
osg::Matrix m;
q1.get(m);
osg::Vec3d axis = m.preMult(osg::Vec3d(0, 0, 1));
osg::Quat q2(m_rotate, -axis);
mn->setLocalRotation(q1*q2);
m_rotate += 0.01; // 每次增加0.01弧度
if (m_rotate >= 2 * osg::PI)
m_rotate -= 2 * osg::PI;
}
}
protected:
double m_rotate; // 旋转角度(弧度)
};
重写圆括号运算符。两个四元数相乘,表示物体绕过原点的轴连续转动。axis是物体自身Z轴在空间坐标系中的投影。需要理解四元数的相关概念和性质。
添加参照倾斜面
为了显示效果,画一个倾斜的圆作为参照面,代码如下:
{ // 添加一个圆,用作倾斜的参照平面
Style circleStyle;
circleStyle.getOrCreate<PolygonSymbol>()->fill()->color() = Color(Color::Cyan, 0.5);
circleStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_ABSOLUTE;
circleStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_DRAPE;
CircleNode* circle = new CircleNode();
circle->set(
GeoPoint(geoSRS, 116.333, 39.9, 100000., ALTMODE_RELATIVE),
Distance(300, Units::KILOMETERS),
circleStyle,
Angle(0.0, Units::DEGREES),
Angle(0.0, Units::DEGREES),
true);
circle->setLocalRotation(osg::Quat(pitch, osg::X_AXIS,
0, osg::Y_AXIS,
0, osg::Z_AXIS));
annoGroup->addChild(circle);
editGroup->addChild(new CircleNodeEditor(circle));
}
创建圆锥体
创建圆锥的代码如下:
{// 添加圆锥体
double angle = 30; // 圆锥体顶角(度)
double length = 100; // 圆锥体高度
osg::Vec4 color(0.0, 1.0, 0.0, 0.5); // 颜色
double angleD = osg::DegreesToRadians(angle); // 圆锥体顶角转为弧度
double radius = std::tan(angleD * 0.5) * length; // 底面半径
int splitCount = 40; // 底面圆分割个数
double angleStep = osg::PI * 2.0 / splitCount; // 角度变化步长
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> vertex = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array;
osg::ref_ptr<osg::DrawElementsUInt> drawElemUInt = new osg::DrawElementsUInt(GL_TRIANGLE_FAN);
osg::ref_ptr<osg::DrawElementsUInt> drawElemUInt2 = new osg::DrawElementsUInt(GL_TRIANGLE_FAN);
geom->setVertexArray(vertex);
geom->setNormalArray(normal);
vertex->push_back(osg::Vec3(0, 0, 0));
drawElemUInt->push_back(0);
normal->push_back(osg::Vec3(0, -1, 0));
//侧面
for (int i = 0; i <= splitCount; i++) {
double tempAngle = i * angleStep;
osg::Vec3 pos(radius * cos(tempAngle), length, radius * sin(tempAngle) + 3);
vertex->push_back(osg::Vec3(pos));
pos.normalize();
normal->push_back(pos);
drawElemUInt->push_back(i + 1);
}
//底面
int indexBegin = vertex->size();
vertex->push_back(osg::Vec3(0, length, 0));
drawElemUInt2->push_back(indexBegin);
normal->push_back(osg::Vec3(0, 1, 0));
for (int i = 0; i <= splitCount; i++) {
double tempAngle = i * angleStep;
osg::Vec3 pos(radius * cos(tempAngle), length, radius * sin(tempAngle) + 3);
vertex->push_back(osg::Vec3(pos));
normal->push_back(osg::Vec3(0, 1, 0));
drawElemUInt2->push_back(indexBegin + i + 1);
}
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
geom->addPrimitiveSet(drawElemUInt);
geom->addPrimitiveSet(drawElemUInt2);
//创建材质对象
osg::ref_ptr<osg::Material> mat = new osg::Material;
//设置正面散射颜色
mat->setDiffuse(osg::Material::FRONT_AND_BACK, color);//1.0, 0.0, 0.0, 0.3
//设置正面镜面颜色
mat->setSpecular(osg::Material::FRONT_AND_BACK, color);//1.0, 0.0, 0.0, 0.3
//mat->setColorMode(osg::Material::ColorMode::AMBIENT_AND_DIFFUSE);
geom->getOrCreateStateSet()->setAttribute(mat.get());
geom->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);
//设置透明效果
geom->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
geom->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
// 创建ModelNode对象
Style modelStyle;
modelStyle.getOrCreateSymbol<ModelSymbol>()->setModel(geom);
osg::ref_ptr<ModelNode> modelNode = new ModelNode(mapNode, modelStyle);
// 放大以便于观察
modelNode->setScale(osg::Vec3f(10000.0, 10000.0, 10000.0));
// 指定经纬高
modelNode->setPosition(osgEarth::GeoPoint(geoSRS, 116.333, 39.9, 100000));
modelNode->addUpdateCallback(new MyRotateCallback());
annoGroup->addChild(modelNode);
}
创建圆锥体的代码参考了“OsgEarth添加圆锥体”( OsgEarth添加圆锥体_wb175208的专栏-CSDN博客 )WaveBeamCone::createWaveBeamCone的相关代码。
运行效果展示
使用免费软件GifCam( Download GifCam - free - latest version )录屏制作的gif文件如下:
上一篇: osgEarth显示绕端点旋转的线段