#include "effects/ConeWave.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class WaveSurfaceCallback : public osg::NodeCallback { public: WaveSurfaceCallback() : timeElapsed(0.0f) {} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { timeElapsed += (nv->getFrameStamp()->getSimulationTime() - SimulationTime); // 获取并更新geometry的顶点 osg::Geode* geode = dynamic_cast(node); if (geode) { osg::Geometry* geometry = dynamic_cast(geode->getDrawable(0)); if (geometry) { osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); if (vertices) { // 更新顶点位置来模拟波动 float amplitude = 2.0f; float frequency = 1.0f; for (unsigned int i = 0; i < vertices->size(); ++i) { osg::Vec3f& vertex = (*vertices)[i]; vertex.z() = amplitude * sin(frequency * (vertex.x() + timeElapsed)); } geometry->setVertexArray(vertices); geometry->dirtyBound(); // 更新几何体边界 } } } // 继续遍历场景图 traverse(node, nv); SimulationTime = nv->getFrameStamp()->getSimulationTime(); } private: float timeElapsed; double SimulationTime; }; // 雷达扫描波时间更新回调 class RadarWaveTimeCallback : public osg::NodeCallback { public: RadarWaveTimeCallback(osg::ref_ptr waveTimeUniform) : waveTimeUniform_(waveTimeUniform), startTime_(0.0) {} virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (nv->getFrameStamp()) { double currentTime = nv->getFrameStamp()->getSimulationTime(); if (startTime_ == 0.0) { startTime_ = currentTime; } // 计算经过的时间 float elapsedTime = static_cast(currentTime - startTime_); // 更新waveTime uniform if (waveTimeUniform_.valid()) { waveTimeUniform_->set(elapsedTime); } } // 继续遍历场景图 traverse(node, nv); } private: osg::ref_ptr waveTimeUniform_; double startTime_; }; ConeWave::ConeWave() { osgEarth::Registry::shaderGenerator().run(this); currentTime_ = 0.0; // 确保成员变量有合理的默认值 height_ = 1000.0f; radius_ = 50.0f; waveRadius_ = 100.0f; waveSpeed_ = 20.0f; waveCount_ = 3; baseColor_ = osg::Vec4(0.0f, 0.8f, 1.0f, 1.0f); waveColor_ = osg::Vec4(1.0f, 0.5f, 1.0f, 0.8f); // 初始化透明度值 ringBrightAlpha_ = 0.8f; ringDarkAlpha_ = 0.3f; coneAlpha_ = 0.7f; } ConeWave::~ConeWave(void) { } void ConeWave::Render(double dt) { // 时间更新现在由RadarWaveTimeCallback回调处理 // 这里可以处理其他需要更新的属性 } void ConeWave::InitGeode() { Rebuild(); getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); setCullingActive(true); } void ConeWave::Destory() { OnDestroy(); } void ConeWave::SetHeight(float height) { height_ = height; Rebuild(); } void ConeWave::SetBaseColor(const osg::Vec4& color) { baseColor_ = color; if (baseColorUniform_.valid()) { baseColorUniform_->set(baseColor_); } } void ConeWave::SetWaveCount(int count) { waveCount_ = count; Rebuild(); } void ConeWave::SetWaveSpeed(float speed) { waveSpeed_ = speed; if (waveSpeedUniform_.valid()) { waveSpeedUniform_->set(waveSpeed_); } } // 雷达扫描波效果相关方法实现 void ConeWave::SetWaveRadius(float radius) { waveRadius_ = radius; radius_ = radius; // 同时更新锥形的半径 Rebuild(); } void ConeWave::SetWaveColor(const osg::Vec4& color) { waveColor_ = color; if (waveColorUniform_.valid()) { waveColorUniform_->set(waveColor_); } } // 透明度控制方法实现 void ConeWave::SetRingBrightAlpha(float alpha) { ringBrightAlpha_ = alpha; if (ringBrightAlphaUniform_.valid()) { ringBrightAlphaUniform_->set(alpha); } } void ConeWave::SetRingDarkAlpha(float alpha) { ringDarkAlpha_ = alpha; if (ringDarkAlphaUniform_.valid()) { ringDarkAlphaUniform_->set(alpha); } } void ConeWave::SetConeAlpha(float alpha) { coneAlpha_ = alpha; // 更新锥形的基础颜色透明度 if (coneGeometry_.valid()) { // 通过着色器uniform来控制透明度,而不是直接设置颜色 // 这里可以在CreateRadarShader中添加coneAlpha uniform来控制 // 或者通过StateSet的材质属性来控制 osg::StateSet* ss = coneGeometry_->getOrCreateStateSet(); osg::ref_ptr material = new osg::Material(); material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 0.8f, 1.0f, alpha)); material->setTransparency(osg::Material::FRONT_AND_BACK, 1.0f - alpha); ss->setAttributeAndModes(material, osg::StateAttribute::ON); } } void ConeWave::Clear() { // 清除锥形几何体和相关uniform if (coneCallback_.valid()) { setUpdateCallback(nullptr); // 移除时间更新回调 coneCallback_ = nullptr; } if (coneGeometry_.valid()) { removeDrawable(coneGeometry_); coneGeometry_ = nullptr; coneDrawable_ = nullptr; } waveTimeUniform_ = nullptr; baseColorUniform_ = nullptr; waveColorUniform_ = nullptr; levelHeightUniform_ = nullptr; waveSpeedUniform_ = nullptr; ringBrightAlphaUniform_ = nullptr; ringDarkAlphaUniform_ = nullptr; } void ConeWave::Rebuild() { // 清除当前几何体和uniform Clear(); CreateRadarScanWave(); } void ConeWave::CreateConeGeometry() { // 创建锥形几何体 osg::ref_ptr coneGeometry = new osg::Geometry(); // 锥形参数 const int segments = 64; // 圆周细分数 const float angleStep = 2.0f * osg::PI / segments; // 创建顶点数组 osg::ref_ptr vertices = new osg::Vec3Array(); osg::ref_ptr normals = new osg::Vec3Array(); osg::ref_ptr texCoords = new osg::Vec2Array(); // 锥顶(位于原点) vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f)); normals->push_back(osg::Vec3(0.0f, 0.0f, -1.0f)); texCoords->push_back(osg::Vec2(0.5f, 0.5f)); // 底面圆周顶点(位于height_高度处) for (int i = 0; i <= segments; ++i) { float angle = i * angleStep; float x = radius_ * cos(angle); float y = radius_ * sin(angle); float z = height_; vertices->push_back(osg::Vec3(x, y, z)); // 计算法线(从锥顶指向圆周的单位向量) osg::Vec3 normal(x, y, radius_); normal.normalize(); normals->push_back(normal); // 纹理坐标 texCoords->push_back(osg::Vec2((x/radius_ + 1.0f) * 0.5f, (y/radius_ + 1.0f) * 0.5f)); } coneGeometry->setVertexArray(vertices); coneGeometry->setNormalArray(normals); coneGeometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); coneGeometry->setTexCoordArray(0, texCoords); // 创建三角形索引 osg::ref_ptr indices = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES); // 生成锥面三角形 for (int i = 0; i < segments; ++i) { // 每个三角形:锥顶 -> 底面点i -> 底面点i+1 indices->push_back(0); // 锥顶 indices->push_back(i + 1); // 底面点i indices->push_back(i + 2); // 底面点i+1 } coneGeometry->addPrimitiveSet(indices); if (coneGeometry_.valid() && coneGeometry_->getNumParents() > 0) { removeDrawable(coneGeometry_); coneGeometry_ = coneGeometry; coneDrawable_ = coneGeometry_.get(); waveTimeUniform_ = nullptr; levelHeightUniform_ = nullptr; addDrawable(coneDrawable_); } else { coneGeometry_ = coneGeometry; coneDrawable_ = coneGeometry_.get(); } } void ConeWave::CreateRadarScanWave() { // 手动创建锥形几何体 CreateConeGeometry(); // 添加到几何节点 addDrawable(coneDrawable_); // 设置渲染状态 osg::StateSet* ss = coneDrawable_->getOrCreateStateSet(); ss->setRenderBinDetails(120, "RenderBin"); ss->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); // 关闭面剔除以确保可见 ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // 设置混合模式 osg::ref_ptr bf = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA); ss->setAttributeAndModes(bf, osg::StateAttribute::ON); ss->setMode(GL_BLEND, osg::StateAttribute::ON); ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); ss->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); // 创建雷达扫描波着色器 CreateRadarShader(); // 添加时间更新回调 osg::ref_ptr waveTimeCallback = new RadarWaveTimeCallback(waveTimeUniform_); coneCallback_ = waveTimeCallback; setUpdateCallback(coneCallback_); } void ConeWave::CreateRadarShader() { // 防止重复创建着色器 if (waveTimeUniform_.valid()) { return; } // 顶点着色器 - 使用简单的基于高度的条纹效果 static const char* vertexShaderSource = "varying vec3 pos;\n" "void main()\n" "{\n" " pos.x = gl_Vertex.x;\n" " pos.y = gl_Vertex.y;\n" " pos.z = gl_Vertex.z;\n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" "}\n"; // 片段着色器 - 可控透明度的同心圆波纹效果 static const char* fragmentShaderSource = "uniform float height;\n" "uniform vec4 baseColor;\n" "uniform vec4 waveColor;\n" "uniform float waveTime;\n" "uniform float ringBrightAlpha;\n" "uniform float ringDarkAlpha;\n" "uniform float waveSpeed;\n" "varying vec3 pos;\n" "void main()\n" "{\n" " float h = abs(pos.z) / max(height, 1.0);\n" " float radialDist = sqrt(pos.x * pos.x + pos.y * pos.y);\n" " float wavePhase = radialDist * 3.2 - waveTime * waveSpeed;\n" " float ripple = sin(wavePhase);\n" " if (ripple > 0.3)\n" " {\n" " gl_FragColor = vec4(waveColor.rgb, ringBrightAlpha);\n" " }\n" " else\n" " {\n" " gl_FragColor = vec4(baseColor.rgb, ringDarkAlpha);\n" " }\n" "}\n"; // 创建着色器 osg::ref_ptr vertexShader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource); osg::ref_ptr fragmentShader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource); osg::ref_ptr program = new osg::Program; program->addShader(vertexShader); program->addShader(fragmentShader); // 获取drawable的状态集并设置着色器程序 osg::StateSet* stateSet = coneDrawable_->getOrCreateStateSet(); stateSet->setAttributeAndModes(program, osg::StateAttribute::ON); // 创建uniform变量 waveTimeUniform_ = new osg::Uniform("waveTime", 0.0f); baseColorUniform_ = new osg::Uniform("baseColor", baseColor_); // 绿色雷达色调 waveColorUniform_ = new osg::Uniform("waveColor", waveColor_); levelHeightUniform_ = new osg::Uniform("height", height_ > 0 ? height_ : 100.0f); // 确保高度不为0 waveSpeedUniform_ = new osg::Uniform("waveSpeed", waveSpeed_ > 0 ? waveSpeed_ : 1.0f); // 创建透明度控制uniform变量 ringBrightAlphaUniform_ = new osg::Uniform("ringBrightAlpha", ringBrightAlpha_); ringDarkAlphaUniform_ = new osg::Uniform("ringDarkAlpha", ringDarkAlpha_); stateSet->addUniform(waveTimeUniform_); stateSet->addUniform(baseColorUniform_); stateSet->addUniform(waveColorUniform_); stateSet->addUniform(levelHeightUniform_); stateSet->addUniform(waveSpeedUniform_); stateSet->addUniform(ringBrightAlphaUniform_); stateSet->addUniform(ringDarkAlphaUniform_); }