使用vs2015建立MFC单文档程序,记得添加包含目录、库目录以及附加依赖项。
关键代码如下:
DigitalEarthView.h
cpp
// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面
// ("Fluent UI")。该示例仅供参考,
// 用以补充《Microsoft 基础类参考》和
// MFC C++ 库软件随附的相关电子文档。
// 复制、使用或分发 Fluent UI 的许可条款是单独提供的。
// 若要了解有关 Fluent UI 许可计划的详细信息,请访问
// http://msdn.microsoft.com/officeui。
//
// 版权所有(C) Microsoft Corporation
// 保留所有权利。
// DigitalEarthView.h : CDigitalEarthView 类的接口
//
#pragma once
#include "DigitalEarthDoc.h"
#include "OSGObject.h"
class CDigitalEarthView : public CView
{
protected: // 仅从序列化创建
CDigitalEarthView();
DECLARE_DYNCREATE(CDigitalEarthView)
// 特性
public:
CDigitalEarthDoc* GetDocument() const;
public:
COSGObject* mOSG;
HANDLE mThreadHandle;
// 操作
public:
// 重写
public:
virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
// 实现
public:
virtual ~CDigitalEarthView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
afx_msg void OnFilePrintPreview();
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnDestroy();
virtual void OnInitialUpdate();
};
#ifndef _DEBUG // DigitalEarthView.cpp 中的调试版本
inline CDigitalEarthDoc* CDigitalEarthView::GetDocument() const
{ return reinterpret_cast<CDigitalEarthDoc*>(m_pDocument); }
#endif
DigitalEarthView.cpp
cpp
// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面
// ("Fluent UI")。该示例仅供参考,
// 用以补充《Microsoft 基础类参考》和
// MFC C++ 库软件随附的相关电子文档。
// 复制、使用或分发 Fluent UI 的许可条款是单独提供的。
// 若要了解有关 Fluent UI 许可计划的详细信息,请访问
// http://msdn.microsoft.com/officeui。
//
// 版权所有(C) Microsoft Corporation
// 保留所有权利。
// DigitalEarthView.cpp : CDigitalEarthView 类的实现
//
#include "stdafx.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "DigitalEarth.h"
#endif
#include "DigitalEarthDoc.h"
#include "DigitalEarthView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CDigitalEarthView
IMPLEMENT_DYNCREATE(CDigitalEarthView, CView)
BEGIN_MESSAGE_MAP(CDigitalEarthView, CView)
ON_WM_CONTEXTMENU()
ON_WM_RBUTTONUP()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_DESTROY()
END_MESSAGE_MAP()
// CDigitalEarthView 构造/析构
CDigitalEarthView::CDigitalEarthView()
{
mOSG=0;
mThreadHandle=0;
}
CDigitalEarthView::~CDigitalEarthView()
{
}
BOOL CDigitalEarthView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
// CDigitalEarthView 绘制
void CDigitalEarthView::OnDraw(CDC* /*pDC*/)
{
CDigitalEarthDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
}
void CDigitalEarthView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}
void CDigitalEarthView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
//theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}
// CDigitalEarthView 诊断
#ifdef _DEBUG
void CDigitalEarthView::AssertValid() const
{
CView::AssertValid();
}
void CDigitalEarthView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CDigitalEarthDoc* CDigitalEarthView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDigitalEarthDoc)));
return (CDigitalEarthDoc*)m_pDocument;
}
#endif //_DEBUG
// CDigitalEarthView 消息处理程序
int CDigitalEarthView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
mOSG = new COSGObject(m_hWnd);
return 0;
}
BOOL CDigitalEarthView::OnEraseBkgnd(CDC* pDC)
{
if(0 == mOSG)
{
return CView::OnEraseBkgnd(pDC);
}
else
{
return FALSE;
}
return CView::OnEraseBkgnd(pDC);
}
void CDigitalEarthView::OnDestroy()
{
CView::OnDestroy();
if(mOSG != 0) delete mOSG;
WaitForSingleObject(mThreadHandle, 1000);
}
void CDigitalEarthView::OnInitialUpdate()
{
CView::OnInitialUpdate();
mOSG->InitOSG();
mThreadHandle = (HANDLE)_beginthread(&COSGObject::Render, 0, mOSG);
}
OSGObject.h
cpp
#pragma once
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgViewer/api/win32/GraphicsWindowWin32>
#include <osgGA/TrackballManipulator>
class COSGObject
{
public:
COSGObject(HWND hWnd);
~COSGObject(void);
void InitOSG();
void InitSceneGraph();
void InitCameraConfig();
void PreFrameUpdate();
void PostFrameUpdate();
static void Render(void * ptr);
osgViewer::Viewer *getViewer();
private:
HWND m_hWnd;
osgViewer::Viewer * mViewer;
osg::ref_ptr<osg::Group> mRoot;
};
OSGObject.cpp
cpp
#include "StdAfx.h"
#include "OSGObject.h"
COSGObject::COSGObject(HWND hWnd)
{
m_hWnd = hWnd;
}
COSGObject::~COSGObject(void)
{
}
void COSGObject::InitOSG()
{
InitSceneGraph();
InitCameraConfig();
}
void COSGObject::InitSceneGraph()
{
mRoot = new osg::Group;
//mRoot->addChild(osgDB::readNodeFile("clock.osgt"));
mRoot->addChild(osgDB::readNodeFile("D:/Project/OSG/bili35/builder/earthfile/china-simple.earth"));
//mRoot->addChild(osgDB::readNodeFile("D:/Project/OSG/bili35/DemoCode/老路径/003.第三讲-VPB用法详解与常见问题处理/vpbtest/TestCommon10/output.ive"));
}
void COSGObject::InitCameraConfig()
{
RECT rect;
mViewer = 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);
traits->x = 0;
traits->y = 0;
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.0, 1000.0);
mViewer->setCamera(camera);
mViewer->setCameraManipulator(new osgGA::TrackballManipulator);
mViewer->setSceneData(mRoot);
mViewer->realize();
//下面这句不注释,看不到模型或者地球。这个问题困扰好几天。。。
//mViewer->getCamera()->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
mViewer->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 mViewer;
}
有图有真相,程序运行效果如下图所示:
这个章节,主要遇到的问题有两个:
1.osg加载的模型或地球不显示,设置了法线和光源都不行;
2.osg加载的模型或地球显示的位置往上偏了。
问题的解决已经在代码注释中了。