osg系列文章目录
前言
osg3.6.5 osgEarth3.2中,鼠标操作地球放大、缩小、旋转发生屏闪,如下图所示,感觉晃眼睛,这谁能忍?
一、分析原因
1.垂直同步(VSync)未启用:
如果垂直同步未启用,图形的刷新速率可能和显示器的刷新速率不同步,导致屏幕撕裂和闪烁。
解决方法:无效
typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC)(int interval);
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
if (wglSwapIntervalEXT)
{
wglSwapIntervalEXT(1); // Enable VSync
}
2.双缓冲(Double Buffering)未启用:
双缓冲可以避免在渲染过程中直接绘制到屏幕上,从而减少屏幕闪烁。
解决方法:无效
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->doubleBuffer = true;
3.绘制循环中的重复绘制:
如果绘制循环中存在不必要的重复绘制操作,可能会导致性能问题和屏幕闪烁。
解决方法:无效
void COSGObject::Render(void* ptr)
{
COSGObject* osg = static_cast<COSGObject*>(ptr);
if (!osg)
{
std::cerr << "Error: osg is nullptr!" << std::endl;
return;
}
osgViewer::Viewer* viewer = osg->GetViewer();
if (!viewer)
{
std::cerr << "Error:viewer is nullptr!" << std::endl;
return;
}
while (!viewer->done())
{
osg->PreFrameUpdate();
viewer->frame();
osg->PostFrameUpdate();
}
_endthread();
}
4.图形驱动程序或硬件问题:
图形驱动程序或硬件问题也可能导致屏幕闪烁。
更新过显卡驱动:无效
5.透明度和混合设置问题:
透明度和混合设置不当可能会影响渲染性能,导致屏幕闪烁。
解决方法:无效
osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc;
blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_CONSTANT_ALPHA);
stateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
6.窗口重绘频率过高:
窗口重绘频率过高可能导致屏幕闪烁。
解决方法:无效
m_viewer->setUpThreadingModel(osgViewer::Viewer::SingleThreaded);
二、最终解决方法
透明对象需要特别的处理来保证它们以正确的顺序进行渲染(通常是从远到近),以避免混合错误。这行代码将该节点及其子节点放入一个专门的渲染通道(Render Bin)中,以确保正确处理透明度。
显式地设置了渲染通道的详细信息。
//启动混合
osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc;
blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_CONSTANT_ALPHA);
stateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
//启动透明度写入
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setRenderBinDetails(0, "RenderBin");
三、完整代码
1.头文件
#pragma once
#include <osg/Group>
#include <osg/CullFace>
#include <osg/BlendFunc>
#include <osgviewer/Viewer>
#include <osgDB/ReadFile>
#include <osgviewer/api/Win32/GraphicsWindowWin32>
#include <osgGA/TrackballManipulator>
#include <osgEarth/MapNode>
#include <osgEarth/Utils>
#include <osgEarth/EarthManipulator>
#include <osgEarth/SkyView>
#include <osgEarth/Units>
//#include <osgEarth/Util/SkyNode> // 确保包含 SkyNode 的定义
#include <osgEarth/Sky>
#include <osgEarth/Ephemeris>
#include <osgEarth/ImageLayer>
#include <osgEarth/AnnotationUtils>
#include <osgText/Text>
#include <osgEarth/GeoTransform>
#include <osgEarth/AnnotationNode>
#include <osgEarth/MapInfo>
#include <osgEarth/Symbol>
#include <osgEarth/GeoMath>
#include <osgEarth/SpatialReference>
#include <osgEarth/TextSymbol>
#include <osgEarth/Feature>
#include <osgEarth/PlaceNode>
#include <osgEarth/Style>
#include <osgEarth/OGRFeatureSource>
#include <osgEarth/FeatureModelLayer>
#include <osgEarth/FeatureImageLayer>
#include <mutex>
#include <memory>
#include <tuple>
#include "CLabelTools.h"
using namespace osgEarth;
using namespace osgEarth::Util;
class COSGObject
{
public:
COSGObject(HWND hWnd);
~COSGObject();
void InitOSG();
void InitSceneGraph();
void InitCameraConfig();
void PreFrameUpdate();
void PostFrameUpdate();
static void Render(void* ptr);
void InitOsgEarth();
osgViewer::Viewer* GetViewer();
void setChinaBoundariesOpacity(double opt);
double getChinaBoundariesOpacity();
void rmvChinaBoundaryes();
void addChinaBoundaryes();
//新增地标
void addLabel();
void loadSharp();
std::wstring MultiByteToWideChar(const std::string& str);
std::string WideChar2MultiByte(const std::wstring& wstr);
std::string MultiByteToUTF8(const std::string& str);
//1:ptr COSGObject
//2:ptr 文件名
//3:ptr 地标数量
static void ReadLabelThread(void* ptr);
//static void CreateLabelThread(void* ptr);
//void CreateLabelThread(std::shared_ptr<std::vector<void*>> params);
static void CreateLabelThread(void* ptr);
//static COSGObject* m_osg;
unsigned int m_processI;
osg::ref_ptr<osg::Image> m_province;
osg::ref_ptr<osg::Image> m_cityCenter;
osg::ref_ptr<osg::Image> m_city;
osg::ref_ptr<osg::Image> m_countyCity;
osg::ref_ptr<osg::Image> m_county;
osg::ref_ptr<osg::Image> m_town;
osg::ref_ptr<osg::Image> m_vi;
//osgEarth::Style m_style;
std::shared_ptr<std::tuple<COSGObject*, std::shared_ptr<std::string>, unsigned int>> m_shaanXiParam;
std::shared_ptr<std::string> m_shaanXiTxt;
std::shared_ptr<std::tuple<COSGObject*, std::shared_ptr<std::string>, unsigned int>> m_shanXiParam;
std::shared_ptr<std::string> m_shanXiTxt;
/*unsigned int shaanXiParam[3];
std::string shaanXiTxt;
std::string shanXiTxt;*/
public:
HWND m_hWnd;
osg::ref_ptr<osgViewer::Viewer> m_viewer;
osg::ref_ptr<osg::Group> m_root;
static osg::ref_ptr<osgEarth::MapNode> m_mapNode;
osg::ref_ptr<osgEarth::EarthManipulator> m_em;
osg::ref_ptr<osgEarth::SkyNode> m_skyNode;
static osgEarth::Style *m_style;
static std::mutex m_mutex;
time_t m_nowTime;
tm* m_tm;
//国界线图层
//osg::ref_ptr<osgEarth::Layer> m_chinaBoundaries;
osg::ref_ptr<osgEarth::ImageLayer> m_chinaBoundaries;
osg::ref_ptr<osg::Node> m_world;
//地标
osg::ref_ptr<osg::Group> m_earthLabel;
};
2.实现文件
#include "pch.h"
#include "COSGObject.h"
#include "DigitalEarth.h"
osg::ref_ptr<osgEarth::MapNode> COSGObject::m_mapNode;
osgEarth::Style* COSGObject::m_style = new osgEarth::Style;
std::mutex COSGObject::m_mutex;
//COSGObject* COSGObject::m_osg = nullptr;
COSGObject::COSGObject(HWND hWnd)
{
m_hWnd = hWnd;
//m_osg = nullptr;
m_viewer = nullptr;
m_root = nullptr;
m_processI = 0;
}
COSGObject::~COSGObject() {
}
void COSGObject::InitOSG()
{
InitSceneGraph();
InitCameraConfig();
InitOsgEarth();
}
void COSGObject::InitSceneGraph()
{
// osg::ref_ptr<osg::Group> rr = new osg::Group;
try
{
osgEarth::initialize();
m_root = new osg::Group;
// m_root->addChild(osgDB::readNodeFile("../../vs2022_64bit_3rdParty_osg365_oe32/runtime/test/earthFile/china-simple.earth"));
//启动背面剔除
osg::ref_ptr<osg::CullFace> cullFace = new osg::CullFace(osg::CullFace::BACK);
osg::ref_ptr<osg::StateSet> stateSet = m_root->getOrCreateStateSet();
stateSet->setAttributeAndModes(cullFace, osg::StateAttribute::ON);
// osg::ref_ptr<osg::Node> mp = osgDB::readNodeFile("../../vs2022_64bit_3rdParty_osg365_oe32/runtime/test/earth/TestCommon10/output.ive");
osg::ref_ptr<osg::Node> mp = osgDB::readNodeFile("../../vs2022_64bit_3rdParty_osg365_oe32/runtime/test/earthFile/china-simple.earth");
m_root->addChild(mp);
// 注意:osgEarth::MapNode只能加载earth文件,加载ive会失败
m_mapNode = dynamic_cast<osgEarth::MapNode*>(mp.get());
//设置透明度、材质
osg::ref_ptr<osg::Material> material = dynamic_cast<osg::Material*>(stateSet->getAttribute(osg::StateAttribute::MATERIAL));
if (!material){
material = new osg::Material;
stateSet->setAttribute(material);
}
//设置透明度0.2
material->setAlpha(osg::Material::FRONT_AND_BACK, 0.2f);
//启动混合
osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc;
blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_CONSTANT_ALPHA);
stateSet->setAttributeAndModes