当前位置:网站首页>OSG笔记:设置DO_NOT_COMPUTE_NEAR_FAR,手动计算远近平面
OSG笔记:设置DO_NOT_COMPUTE_NEAR_FAR,手动计算远近平面
2022-08-01 20:31:00 【shanql】
问题
实现正交投影的操作杆时,缩放平移后,会产生图形部分消息的情况。没研究透osg自动计算算法,暂时认为自动计算远近平面对透视投影可能没啥问题,但正交投影则有。
思路(记录下,没有严格推敲,不保证正确性)
left, right, top, bottom使用模型包围球的半径即可。远近平面的距离思路如下图所示,z轴一半的长度需取最大可能的长度(即视点沿着视线到包围盒另一侧的距离),这样才能保证怎么旋转模型,模型都在以眼睛为坐标原点的观察范围内。
代码
#include <iostream>
#include <osgViewer/Viewer>
#include <osg/Group>
#include <osg/ShapeDrawable>
#include <osgGA/GUIEventHandler>
#include <osg/Viewport>
#include <osg/NodeCallback>
#include <osgGA/StandardManipulator>
#include <osgGA/EventVisitor>
using namespace std;
class MyGUIEventHandler : public osgGA::GUIEventHandler
{
public:
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa,
osg::Object* pObject, osg::NodeVisitor* pNodeVisitor)
{
osgViewer::Viewer* pViewer = dynamic_cast<osgViewer::Viewer*>(aa.asView());
if (!pViewer || !pViewer->getSceneData() )
{
return false;
}
osg::ref_ptr<osg::Camera> pCamera = pViewer->getCamera();
if (!pCamera)
{
return false;
}
osg::Viewport* pViewport = pCamera->getViewport();
if (!pViewport)
{
return false;
}
osgGA::StandardManipulator* pManipulator = dynamic_cast<osgGA::StandardManipulator*>(
pViewer->getCameraManipulator());
if (!pManipulator)
{
return false;
}
double aspecRadio = double(pViewport->width()) / double(pViewport->height());
osg::BoundingSphere modelBound = pViewer->getSceneData()->getBound();
double dModelHalfSize = modelBound.radius();
static double s_dScale = 1.0;
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::EventType::KEYDOWN:
{
bool bZoom = false;
if (int(osgGA::GUIEventAdapter::KeySymbol::KEY_R) == ea.getKey())
{
s_dScale = 1.0; //恢复
bZoom = true;
}
else if (int(osgGA::GUIEventAdapter::KeySymbol::KEY_D) == ea.getKey())
{
s_dScale *= 1.2; //缩小
bZoom = true;
}
else if (int(osgGA::GUIEventAdapter::KeySymbol::KEY_U) == ea.getKey())
{
s_dScale *= 0.8;//放大
bZoom = true;
}
else
{
bZoom = false; //修正远近平面
}
//计算眼睛到视点距离使用操作杆的观察矩阵,使用相机的结果不对
// osg::Vec3d eye0;
// osg::Vec3d center0;
// osg::Vec3d up0;
// pCamera->getViewMatrixAsLookAt(eye0, center0, up0);
// double dDistance0 = (eye0 - center0).length();
double left = 0.0;
double right = 0.0;
double bottom = 0.0;
double top = 0.0;
double zNear = 0.0;
double zFar = 0.0;
if (pViewer->getCamera()->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar))
{
//正交投影
osg::Vec3d eye1;
osg::Vec3d center1;
osg::Vec3d up1;
pManipulator->getTransformation(eye1, center1, up1);
double dDistance1 = (eye1 - center1).length();
double dDistance2 = (center1 - modelBound.center()).length();
std::cout << "dDistance1:" << dDistance1
<< ", dDistance2:" << dDistance2 << std::endl;
if (bZoom)//正交投影的缩放
{
double dHalfRange = dModelHalfSize * s_dScale;
if (aspecRadio > 1.0)
{
pViewer->getCamera()->setProjectionMatrixAsOrtho(
-dHalfRange*aspecRadio, dHalfRange*aspecRadio,
-dHalfRange, dHalfRange, zNear * s_dScale, zFar * s_dScale);
}
else
{
pViewer->getCamera()->setProjectionMatrixAsOrtho(
-dHalfRange, dHalfRange,
-dHalfRange*aspecRadio, dHalfRange*aspecRadio,
zNear * s_dScale, zFar * s_dScale);
}
}
else //修正远近平面
{
double dHalfRangeZ = dDistance1 + dDistance2 + dModelHalfSize*0.7;
pViewer->getCamera()->setProjectionMatrixAsOrtho(
left, right, bottom, top, -dHalfRangeZ, dHalfRangeZ);
}
}
break;
}
}
return osgGA::GUIEventHandler::handle(ea, aa, pObject, pNodeVisitor);
}
};
int main(int argc, char** argv)
{
osgViewer::Viewer* pViewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Group> pRoot = new osg::Group();
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode();
pRoot->addChild(pGeode);
osg::ref_ptr<osg::Box> pBox = new osg::Box(osg::Vec3(0, 0, 0), 100.0);
pGeode->addDrawable(new osg::ShapeDrawable(pBox));
const osg::BoundingSphere& boundingSphere = pRoot->getBound();
pViewer->addEventHandler(new MyGUIEventHandler());
pViewer->setSceneData(pRoot);
pViewer->getCamera()->setClearColor(osg::Vec4(0, 0, 0, 1.0));
pViewer->setUpViewInWindow(450, 220, 720, 450);
pViewer->realize();
//不自动计算远近平面
pViewer->getCamera()->setComputeNearFarMode(
osg::CullSettings::ComputeNearFarMode::DO_NOT_COMPUTE_NEAR_FAR);
//设置个默认的投影范围
const osg::Viewport* pViewport = pViewer->getCamera()->getViewport();
if (pViewport)
{
double dHalfRange = 100;
double aspecRadio = double(pViewport->width()) / double(pViewport->height());
if (aspecRadio > 1.0)
{
pViewer->getCamera()->setProjectionMatrixAsOrtho(
-dHalfRange*aspecRadio, dHalfRange*aspecRadio,
-dHalfRange, dHalfRange, -dHalfRange, dHalfRange);
}
else
{
pViewer->getCamera()->setProjectionMatrixAsOrtho(
-dHalfRange, dHalfRange,
-dHalfRange*aspecRadio, dHalfRange*aspecRadio, -dHalfRange, dHalfRange);
}
}
//aspecRadio
pViewer->run();
return 0;
}
截图
轴测视图下,正方体,未计算正确远近平面

手动计算了远近平面后

边栏推荐
猜你喜欢

数字孪生北京故宫,元宇宙推进旅游业进程

XSS range intermediate bypass
![[Personal Work] Remember - Serial Logging Tool](/img/8c/56639e234ec3472f4133342eec96d6.png)
[Personal Work] Remember - Serial Logging Tool

我的驾照考试笔记(3)

第59章 ApplicationPart内置依赖注入中间件

面试突击70:什么是粘包和半包?怎么解决?

Buttons with good user experience should not have hover state on mobile phones

AQS原理和介绍

【节能学院】智能操控装置在高压开关柜的应用

泰德制药董事长郑翔玲荣膺“2022卓越影响力企业家奖” 泰德制药荣获“企业社会责任典范奖”
随机推荐
98.嵌入式控制器EC实战 EC开发板开发完成
Redis does check-in statistics
自定义指令,获取焦点
Creo5.0 rough hexagon is how to draw
Does LabVIEW really close the COM port using VISA Close?
第60章 ApplicationPart自动集成整体性和独立性插件项
【无标题】
Go 语言中常见的坑
研究生新同学,牛人看英文文献的经验,值得你收藏
The configuration manual for the secondary development of the XE training system of the missing moment document system
使用微信公众号给指定微信用户发送信息
WhatsApp group sending actual combat sharing - WhatsApp Business API account
数字孪生北京故宫,元宇宙推进旅游业进程
MySQL语法基础
密码学的基础:X.690和对应的BER CER DER编码
What is the difference between a utility model patent and an invention patent?Understand in seconds!
密码学的基础:X.690和对应的BER CER DER编码
Zheng Xiangling, Chairman of Tide Pharmaceuticals, won the "2022 Outstanding Influential Entrepreneur Award" Tide Pharmaceuticals won the "Corporate Social Responsibility Model Award"
Use WeChat official account to send information to designated WeChat users
LTE时域、频域资源