使用osgearth使渲染地球中间被黑色遮挡

osg系列文章目录

前言

我使用的是osg3.6.5,osgearth3.2版本,使用osgearth使渲染地球,运行效果中间被黑色遮挡,不知道具体原因,请看下图
在这里插入图片描述

一、代码

#pragma once

#include <osg/Group>
#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 的定义

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();
private:
	HWND m_hWnd;
	osg::ref_ptr<osgViewer::Viewer> m_viewer;
	osg::ref_ptr<osg::Group> m_root;
	osg::ref_ptr<osgEarth::MapNode> m_mapNode;
	osg::ref_ptr<osgEarth::EarthManipulator> m_em;
};


#include "pch.h"
#include "COSGObject.h"

COSGObject::COSGObject(HWND hWnd)
{
	m_hWnd = hWnd;
	m_viewer = NULL;
	m_root = NULL;
}

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"));
	}

	catch(const std::exception& e) {
		AfxMessageBox(CString("Failed to create osg::Group in constructor: ") + CString(e.what()));
		throw std::runtime_error(std::string("Failed to create osg::Group in constructor: ") + e.what());
	}
}

void COSGObject::InitCameraConfig()
{
	RECT rect;
	m_viewer = new osgViewer::Viewer;
	//osg::ref_ptr<osgViewer::View> viewer = new osgViewer::Viewer;
	//osg::ref_ptr<osgViewer::Viewer> m_vv = new osgViewer::Viewer;
	::GetWindowRect(m_hWnd, &rect);
	osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
	osg::ref_ptr<osg::Referenced> winData = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
	traits->x = 0;
	traits->y = 0;
	traits->width = rect.right - rect.left;
	traits->height = rect.bottom - rect.top;
	traits->windowDecoration = false;
	traits->doubleBuffer = true;
	traits->sharedContext = 0;
	traits->setInheritedWindowPixelFormat = true;
	traits->inheritedWindowData = winData;
	osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits);

	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setGraphicsContext(gc);
	camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height));
	camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height),
		1.0f, 1000.f);

	m_viewer->setCamera(camera);
	m_viewer->setCameraManipulator(new osgGA::TrackballManipulator);
	m_viewer->setSceneData(m_root);
	m_viewer->realize();
	m_viewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
	m_viewer->getCamera()->setNearFarRatio(0.000003f);
}

void COSGObject::PreFrameUpdate()
{

}

void COSGObject::PostFrameUpdate()
{

}

void COSGObject::Render(void* ptr)
{
	COSGObject* osg = (COSGObject*)ptr;
	osgViewer::Viewer* viewer = osg->GetViewer();
	while (!viewer->done())
	{
		osg->PreFrameUpdate();
		viewer->frame();
		osg->PostFrameUpdate();
	}

	_endthread();
}

osgViewer::Viewer* COSGObject::GetViewer()
{
	return m_viewer;
}

void COSGObject::InitOsgEarth()
{
	osgEarth::initialize();
	//初始化操作器
	m_em = new osgEarth::EarthManipulator;
	if (m_mapNode)
	{
		m_em->setNode(m_mapNode.get());
	}
	m_em->getSettings()->setArcViewpointTransitions(true);
	m_viewer->setCameraManipulator(m_em);

	//初始化天空
	osgEarth::Config skyConf;
	double hours = skyConf.value("hours", 12.0);
	//osg::ref_ptr<osgEarth::SkyNode> skyNode = new osgEarth::SkyNode(skyConf);
	
}

二、分析原因

1.刚开始我以为是我下载的全球30米高程图片和影像图片不匹配导致的原因,我还专门求教了国内osgearth顶尖大佬—杨石兴老师,他直接给出了结论是:“应该不是,应该是远近裁切面的问题”,大佬就是大佬一下就定位到问题所在,在此特别感恩一下杨老师的的耐心解答。杨老师还在B站无私奉献了:OSG的B站小讲堂 --35讲osgEarth视频教程

以及OSG的B站小讲堂—72讲OSG视频教程
全部免费观看,还有资料下载地址

2.经过调试发现问题是:
setComputeNearFarMode这个函数,

m_viewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);

在CullSettings中,camera和cullvisitor都使用了这个函数进
行远近平面的自动计算,可以优化远近平面的深度范围。

m_viewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);

这行代码修改成:

m_viewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);

运行效果如下图:
在这里插入图片描述

我还是贴出完整代码,方便读者查看

#pragma once

#include <osg/Group>
#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>

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();

	void setChinaBoundariesOpacity(double opt);
	double getChinaBoundariesOpacity();
	void initializeChinaBoundaries();

	osgViewer::Viewer* GetViewer();
private:
	HWND m_hWnd;
	osg::ref_ptr<osgViewer::Viewer> m_viewer;
	osg::ref_ptr<osg::Group> m_root;
	osg::ref_ptr<osgEarth::MapNode> m_mapNode;
	osg::ref_ptr<osgEarth::EarthManipulator> m_em;
	osg::ref_ptr<osgEarth::SkyNode> m_skyNode;

	time_t m_nowTime;
	tm* m_tm;

	//国界线图层
	//osg::ref_ptr<osgEarth::Layer> m_chinaBoundaries;
	osg::ref_ptr<osgEarth::ImageLayer> m_chinaBoundaries;
};


#include "pch.h"
#include "COSGObject.h"

COSGObject::COSGObject(HWND hWnd)
{
	m_hWnd = hWnd;
	m_viewer = NULL;
	m_root = NULL;
}

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::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());
		
	}

	catch(const std::exception& e) {
		AfxMessageBox(CString("Failed to create osg::Group in constructor: ") + CString(e.what()));
		throw std::runtime_error(std::string("Failed to create osg::Group in constructor: ") + e.what());
	}
}

void COSGObject::InitCameraConfig()
{
	RECT rect;
	m_viewer = new osgViewer::Viewer;
	//osg::ref_ptr<osgViewer::View> viewer = new osgViewer::Viewer;
	//osg::ref_ptr<osgViewer::Viewer> m_vv = new osgViewer::Viewer;
	::GetWindowRect(m_hWnd, &rect);
	osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
	osg::ref_ptr<osg::Referenced> winData = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
	traits->x = 0;
	traits->y = 0;
	traits->width = rect.right - rect.left;
	traits->height = rect.bottom - rect.top;
	traits->windowDecoration = false;
	traits->doubleBuffer = true;
	traits->sharedContext = 0;
	traits->setInheritedWindowPixelFormat = true;
	traits->inheritedWindowData = winData;
	osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits);

	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setGraphicsContext(gc);
	camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height));
	camera->setProjectionMatrixAsPerspective(30.0f, double(traits->width) / static_cast<double>(traits->height),
		1.0f, 1000.f);

	m_viewer->setCamera(camera);
	//m_viewer->setCameraManipulator(new osgGA::TrackballManipulator);
	m_viewer->setSceneData(m_root);
	m_viewer->realize();
	m_viewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
	m_viewer->getCamera()->setNearFarRatio(0.000003f);
}

void COSGObject::PreFrameUpdate()
{

}

void COSGObject::PostFrameUpdate()
{

}

void COSGObject::Render(void* ptr)
{
	COSGObject* osg = (COSGObject*)ptr;
	osgViewer::Viewer* viewer = osg->GetViewer();
	while (!viewer->done())
	{
		osg->PreFrameUpdate();
		viewer->frame();
		osg->PostFrameUpdate();
	}

	_endthread();
}

osgViewer::Viewer* COSGObject::GetViewer()
{
	return m_viewer;
}

void COSGObject::InitOsgEarth()
{
	//初始化操作器
	m_em = new osgEarth::EarthManipulator;
	if (m_mapNode.valid())
	{
		m_em->setNode(m_mapNode);
	}
	m_em->getSettings()->setArcViewpointTransitions(true);
	m_viewer->setCameraManipulator(m_em);

	//获取当前时间
	m_nowTime = time(0);
	m_tm = localtime(&m_nowTime);
	osgEarth::DateTime currTime(m_nowTime);
	osg::ref_ptr<osgEarth::Ephemeris> ephemeris = new osgEarth::Ephemeris;
	//初始化天空
	osgEarth::Util::SkyOptions skyOptions;
	m_skyNode = osgEarth::SkyNode::create(skyOptions);

	//osgEarth::Util::SkyOptions skyOptions;
	osgEarth::Config skyConf;
	double hours = skyConf.value("hours", 12.0);
	m_skyNode->setName("skyNode");
	m_skyNode->setEphemeris(ephemeris);
	m_skyNode->setDateTime(currTime);
	m_viewer->setLightingMode(osg::View::SKY_LIGHT);
	m_skyNode->attach(m_viewer, 0);
	m_skyNode->setLighting(true);
	m_skyNode->addChild(m_mapNode);
	m_root->addChild(m_skyNode);
	
	//获取国界线图层
	//m_chinaBoundaries = m_mapNode->getMap()->getImageLayerByName("china_boundaries");
	osg::ref_ptr<osgEarth::Layer> layer = m_mapNode->getMap()->getLayerByName("china_boundaries");
	if (layer)
	{
		auto imageLayer = dynamic_cast<osgEarth::ImageLayer*>(layer.get());
		if (imageLayer)
		{
			m_chinaBoundaries = imageLayer;
		}
	}

	setChinaBoundariesOpacity(1.0);
}

void COSGObject::initializeChinaBoundaries()
{
	/*for (auto layer : m_mapNode->getMap()->getLayers())
	{
		if (layer && layer->getName() == "china_boundaries")
		{
			auto imageLayer = dynamic_cast<osgEarth::ImageLayer*>(layer.get());
			if (imageLayer)
			{
				m_chinaBoundaries = imageLayer;
				break;
			}
		}
	}*/
}

void COSGObject::setChinaBoundariesOpacity(double opt)
{
	if (m_chinaBoundaries)
	{
		m_chinaBoundaries->setOpacity(opt);
	}
}

double COSGObject::getChinaBoundariesOpacity()
{
	if (m_chinaBoundaries)
	{
		return m_chinaBoundaries->getOpacity();
	}
	else
	{
		return -1.0;
	}
}



工程下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值