查看: 1200|回复: 8

请教如何通过改变视点使窗口场景中的模型自动填充满窗口

[复制链接]

该用户从未签到

发表于 2013-4-11 18:08:13 | 显示全部楼层 |阅读模式
在程序中使用了FreeSouth的Csouth类,试图通过求场景的包围盒范围来设置相机位置,但始终不能使场景填充满窗口,请教高手如何解决?

该用户从未签到

发表于 2013-4-11 18:17:06 | 显示全部楼层
首先说一句,我是来打酱油的

该用户从未签到

发表于 2013-4-12 07:52:39 | 显示全部楼层
不知道这个Csouth类是怎么样实现的,又开始猜谜语了

该用户从未签到

 楼主| 发表于 2013-4-12 08:39:07 | 显示全部楼层
Csouth头文件如下:
/* -*-c++-*- OpenSceneGraph - 2008.6.16 by FreeSouth * * RambleSystem操作器管理类,用来管理操作器 */
//------------------------------//------------------------------
#pragma once
//------------------------------//------------------------------
#include <osgViewer/Viewer>
#include <osgGA/MatrixManipulator>
#include <osgUtil/IntersectVisitor>
#include <osg/LineSegment>
#include <osg/MatrixTransform>
#include <osg/Geometry>
#include <sstream>
#include <osg/ComputeBoundsVisitor>
//------------------------------//------------------------------
class CSouth: public osgGA::MatrixManipulator
{
public:
        CSouth(void);
public:
        ~CSouth(void);
        //碰撞检测开启状态查询。
        bool m_bPeng;
        //得到当前视点位置
        osg::Vec3 GetPosition() ;
private:
        //结点值,用来测试碰撞检测的
        osg::ref_ptr<osg::Node> m_node;
        //相机操作器
        unsigned int m_nID;
        //移动速度
        float m_fMoveSpeed;
         //位置
        osg::Vec3 m_vPosition;
        //旋转角度
        osg::Vec3 m_vRotation;
        //左键是否按下
        bool m_bLeftButtonDown;
        //左键点下时屏幕坐标
        float m_fpushX;
        //右键点下时屏幕坐标
        float m_fpushY; public:
        //碰撞检测是否开启
        void setPeng(bool peng) ;
        //得到碰撞检测开启状态
        bool getPeng() ;
        //如果碰撞检测开启则关闭,如果关闭则开启
        void setFpeng() ;
        //设置要进行碰撞检测的数据
        virtual void setNode(osg::Node*);
        // 虚函数
        virtual void setByMatrix(const osg::Matrixd& matrix);
        // 虚函数
        virtual void setByInverseMatrix(const osg::Matrixd& matrix);
        virtual osg::Matrixd getMatrix(void) const;
        // 得到逆矩阵
        virtual osg::Matrixd getInverseMatrix(void)const ;
        // 主要事件控制器
        virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);
        // 屏目角度
        float m_fAngle;
        // 位置变换函数
        void ChangePosition(osg::Vec3& delta);
        //得到当前速度
        float getSpeed() ;
        //设置当前速度
        void setSpeed(float ) ;
        //设置视点位置
        void SetPosition(osg::Vec3 &position) ;
        void SetPosition(double *) ;

        //计算家的位置 len为绘制图形左右宽度,单位米
        void computeHomePosition(float len,CString type);
        //在树结构中使用name查找需要的节点
        osg::Node* findNamedNode(const std::string& searchName,osg::Node* currNode);

};
//------------------------------//------------------------------
Csouth.cpp文件服下:
//------------------------------//------------------------------
//By FreeSouth at 2008 6 16 ieysx@163.com www.osgChina.org

#include <stdafx.h >
#include "South.h"
//------------------------------//------------------------------
//设置一些初始值
CSouth::CSouth(void): m_fMoveSpeed(1350.0f)
//左键没有按下
, m_bLeftButtonDown(false)
//左键点下时初始坐标为0
, m_fpushX(0)
//初始角速度是2.5
, m_fAngle(2.5)
//开始时碰撞检测关闭
, m_bPeng(true)
//右键点下时初始坐标也为0
, m_fpushY(0)
{
        //出生点为000 ,即视点所在的初始位置
        m_vPosition = osg::Vec3(0.0f, -35000.0f,190.0f); //-35000 190
        //初始角度
        m_vRotation = osg::Vec3(osg:I_2,0,0.0f);//osg::PI_2
       
}
//------------------------------//------------------------------
//析构函数
CSouth::~CSouth(void) { }
//------------------------------//------------------------------
void CSouth::setByMatrix(const osg::Matrixd & matrix) { }
//------------------------------//------------------------------
void CSouth::setByInverseMatrix(const osg::Matrixd& matrix) { }
//------------------------------//------------------------------
//得到矩阵,这是标准接口,用于控制场景
osg::Matrixd CSouth::getMatrix(void) const
{
//得到旋转后的矩阵,其实也就是视口矩阵,用此控制场景
        osg::Matrixd mat;
        mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f)
                , m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f)
                , m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));
        return mat * osg::Matrixd::translate(m_vPosition);
}
//------------------------------//------------------------------
//得到逆矩阵,标准接口,控制场景
osg::Matrixd CSouth::getInverseMatrix(void) const
{
        osg::Matrixd mat;
        mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),
        m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),
        m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));
        return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition));
}
//------------------------------//------------------------------
//handle
bool CSouth::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
{
        //得到x的初始屏幕坐标
        float mouseX = ea.getX();
        //得到y的初始屏幕坐标
        float mouseY = ea.getY();
        //判断事件类型
        switch(ea.getEventType())
        {
        //如果是鼠标按下的事件
        case(osgGA::GUIEventAdapter::KEYDOWN):
        {
                //如果是空格
                if (ea.getKey() == 0x20)//' '
                 {
                //重绘
                         us.requestRedraw();
                        us.requestContinuousUpdate(false);
                        return true;
                }
                //如果是home键,则视点向上移动
                if (ea.getKey() == 0xFF50)//home
                {
                        ChangePosition(osg::Vec3 (0, 0, m_fMoveSpeed)) ;
                        return true;
                }
                //如果是end键,同视点向下移动
                 if (ea.getKey() == 0xFF57) //end
                {
                        ChangePosition(osg::Vec3 (0, 0, -m_fMoveSpeed)) ;
                        return true;
                }
                //如果是加号键则加速
                if (ea.getKey() == 0x2B)//+
                {
                        m_fMoveSpeed += 1.0f;
                        return true;
                 }
                //如果是减号键则减速
                if (ea.getKey() == 0x2D)//-
                 {
                        m_fMoveSpeed -= 1.0f;
                        if (m_fMoveSpeed < 1.0f)
                        {
                                m_fMoveSpeed = 1.0f;
                        }
                        return true;
                 }
                //向前走,W键
                 if ( ea.getKey () == 0x57 || ea.getKey () == 0x77)//up
                {
                        ChangePosition(osg::Vec3 (0, m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0)) ;
                        ChangePosition(osg::Vec3 (m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0, 0)) ;
                        return true;
                }
                //向后退,S键,或者DOWN键
                if (ea.getKey() == 0xFF54 || ea.getKey () == 0x53 || ea.getKey () == 0x73 )//down
                 {
                        ChangePosition(osg::Vec3 (0, -m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0)) ;
                        ChangePosition(osg::Vec3(-m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0, 0)) ;
                        return true;
                }
                //A  left 向左平移
                if (ea.getKey () == 0x41||ea.getKey () == 0x61||ea.getKey()== 37)
                {
                        ChangePosition(osg::Vec3 (0, -m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0)) ;
                        ChangePosition(osg::Vec3 (m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0, 0)) ;
                        return true;
                }
                //D  right 向右平移
                if (ea.getKey () == 0x44||ea.getKey () == 0x64||ea.getKey() == 39)
                {
                        ChangePosition(osg::Vec3 (0,m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0)) ;
                        ChangePosition(osg::Vec3 (-m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]),0,0)) ;
                        return true;
                }
                //Up 向上平移
                if (ea.getKey() == 38)
                {
                        ChangePosition(osg::Vec3 (0,0,-m_fMoveSpeed )) ;//* cosf(osg::PI_2+m_vRotation._v[1]
                        //ChangePosition(osg::Vec3 (0,m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[1]),0)) ;
                        return true;
                }
                //Down 向下平移
                if (ea.getKey() == 40)
                {
                        ChangePosition(osg::Vec3 (0,0,m_fMoveSpeed )) ;
                        /*ChangePosition(osg::Vec3 (0,-m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[1]),0)) ;
                        ChangePosition(osg::Vec3 (-m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[1]),0,0)) ;*/
                        return true;
                }
                if (ea.getKey() == 0xFF53)//Right
                {
                        m_vRotation._v[2] -= osg:egreesToRadians(m_fAngle);
                        /*if(m_node.get())
                        {
                        osg::Node* foundNode = NULL;
                        foundNode = findNamedNode("Axis",m_node);
                        if (foundNode!=NULL)
                        {
                                osg::ref_ptr<osg::Node> temp=new osg::Node();
                                temp=foundNode;
                                foundNode->asGroup()->getParent(0)->removeChildren(0,foundNode->asGroup()->getParent(0)->getNumChildren());
                                osg::ref_ptr<osg::MatrixTransform> pat=new osg::MatrixTransform();
                                osg::Vec3d delta(-m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]),m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0);
                                m_vPosition += delta;
                                pat->setMatrix(osg::Matrix::translate(m_vPosition));
                                pat->addChild(temp.get());
                                foundNode->asGroup()->addChild(pat.get());

                        }
                        }*/
                 }
                if (ea.getKey()== 0xFF51)//Left
                 {
                        m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);
                 }
                 if (ea.getKey() == 0x46 || ea.getKey() == 0x66)//F    返回初始位置
                {
                        computeHomePosition(-35000,"");
                        m_fAngle -= 0.2 ;
                        return true ;
                }
                if (ea.getKey() == 0x47 || ea.getKey() == 0x67)//G
                {
                        m_fAngle += 0.2 ;
                        return true ;
                }
                        return false;
        }
        //单击
        case (osgGA::GUIEventAdapter ::PUSH ):
               
                //如果是左键,记录下来,因为左键拖动时场景也要转的
                if ( ea.getButton () == 1)
                {
                        m_fpushX = mouseX ;
                        m_fpushY = mouseY ;
                        m_bLeftButtonDown = true ;
                 }
                 return false ;
        //拖动
        case (osgGA::GUIEventAdapter ::DRAG ):
                if ( m_bLeftButtonDown)
                {
                       
                        //m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle * (mouseX-m_fpushX));
                        //m_vRotation._v[0] += osg::DegreesToRadians(1.1*(mouseY-m_fpushY)) ;
                        ////防止背过去
                        //if (m_vRotation._v [0] >= 3.14)
                        //m_vRotation._v [0] = 3.14 ;
                        //if (m_vRotation._v [0] <= 0)
                        //m_vRotation._v [0] = 0 ;
                }
                return false ;
        //键弹起
        case (osgGA::GUIEventAdapter ::RELEASE ):
                if ( ea.getButton () == 1)
                 {
                        m_bLeftButtonDown = false ;
                 }
                return false ;
        default: return false;
        }
}
//在树结构中使用name查找需要的节点
osg::Node* CSouth::findNamedNode(const std::string& searchName,osg::Node* currNode)
{
        osg::Group* currGroup;
        osg::Node* foundNode;
                // 检查输入的节点是否是合法的,
        // 如果输入节点为NULL,则直接返回NULL。
        if ( !currNode)
        {
                return NULL;
        }
        // 如果输入节点合法,那么先检查该节点是否就是我们想要的结果。
        // 如果确为所求,那么直接返回输入节点。
        if (currNode->getName() == searchName)
        {
                return currNode;
        }
        // 如果输入节点并非所求,那么检查它的子节点(不包括叶节点)情况。
        // 如果子节点存在,则使用递归调用来检查每个子节点。
        // 如果某一次递归的返回值非空,说明已经找到所求的节点,返回其指针。
        // 如果所有的节点都已经遍历过,那么说明不存在所求节点,返回NULL。
        currGroup = currNode->asGroup(); // returns NULL if not a group.
        if ( currGroup )
        {
                for (unsigned int i = 0 ; i <currGroup->getNumChildren(); i ++)
        {
                foundNode = findNamedNode(searchName,currGroup->getChild(i));
                if (foundNode)
                        return foundNode; // 找到所求节点。
        }
                return NULL; // 遍历结束,不存在所求节点。
        }
        else
        {
                return NULL; // 该节点不是组节点,返回NULL
        }
}
//------------------------------//------------------------------
//改变位置
void CSouth::ChangePosition(osg::Vec3 &delta)
{
if (m_bPeng)
{
        //看新值与旧值之间的连线是否与模型有交点!如果要到达的位置与现在的位置有交点的话,如果碰撞检测也开启了,就不移动。
        osg::Vec3 newPos = m_vPosition + delta;
        osgUtil::IntersectVisitor iv;
        //前后的线段
        osg::ref_ptr<osg:ineSegment> line = new osg::LineSegment(newPos,m_vPosition);
        //上下移动的线段,加入两条线段来检测碰撞
        osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(newPos + osg::Vec3(0.0f, 0.0f, m_fMoveSpeed), newPos - osg::Vec3(0.0f, 0.0f, m_fMoveSpeed));
        iv.addLineSegment(lineZ.get());
        iv.addLineSegment (line.get()) ;
        //接受碰撞的检测node
        m_node ->accept(iv);
        if (!iv.hits())
        {
                //如果没有碰撞,则移动旧位置到新的位置上
                m_vPosition += delta;
        }
}
else //如果碰撞检测根本没开,则直接移过去,
                m_vPosition += delta;
}
//------------------------------//------------------------------
//得到移动速度
float CSouth::getSpeed()
{
        return m_fMoveSpeed ;
}
//------------------------------//------------------------------
//设置移动速度
void CSouth::setSpeed(float sp)
{
        m_fMoveSpeed = sp ;
}
//------------------------------//------------------------------
//设置视点所在位置
void CSouth::SetPosition(osg::Vec3 &position)
{
        m_vPosition = position ;
}
void CSouth::SetPosition(double* position)
{
        m_vPosition._v[0] = position[0] ;
        m_vPosition._v[1] = position[1] ;
        m_vPosition._v[2] = position[2] ;
}
//------------------------------//------------------------------
//得到视点所在位置
osg::Vec3 CSouth::GetPosition()
{
        return m_vPosition ;
}
//------------------------------//------------------------------
//设置碰撞检测所起作用的物体
void CSouth::setNode(osg::Node* node)
{
         m_node = node ;
}
//------------------------------//------------------------------
//计算家的位置,其实是包围盒的中心处 len为绘制图形左右宽度,单位米
void CSouth::computeHomePosition(float len,CString type)
{
        //如果有模型,则计算包围球的球心
        if(m_node.get())
        {
                osg::BoundingBox bb;
                osg::ComputeBoundsVisitor cbv;
                osg::Vec3 posBQ(0,0,0);
                m_node->dirtyBound();
                m_node->accept(cbv);
                bb=cbv.getBoundingBox();
                posBQ.x()=bb.xMax()-(bb.xMax()-bb.xMin())/2;
                posBQ.z()=bb.zMax()-(bb.zMax()-bb.zMin())/2;
                float x,z;
                x=bb.xMax()-bb.xMin();
                z=bb.zMax()-bb.zMin();
                if(x>z)
                        posBQ.y()=-x*2+2*x/11;
                else
                        posBQ.y()=-z*2+2*z/11;
                /*if(type=="空心板")
                        posBQ.y()+=1700;
                if(type=="空心板桥面")
                        posBQ.y()+=8000;
                if(type=="盖梁柱式墩盖梁")
                        posBQ.y()+=5000;
                if(type.Left(8)=="轻型桥台")
                        posBQ.y()+=7000;*/
               
                SetPosition(posBQ);
        }
        ////空心板的初始视点位置
        //if(m_node.get())
        //{
        //        osg::Vec3 bp(0,-35000,50);
        //        SetPosition(bp) ;
        //}

}
//------------------------------//------------------------------
//设置碰撞检测为开启或者关闭
void CSouth::setPeng(bool peng)
{
        m_bPeng = peng ;
}
//------------------------------//------------------------------
//得到碰撞检测的状态
bool CSouth::getPeng()
{
        return m_bPeng ;
}
//------------------------------//------------------------------
//如果碰撞测试在开启,则关闭它,如果在关闭,则开启它
void CSouth::setFpeng()
{
        m_bPeng = !m_bPeng ;
}
//------------------------------//------------------------------

该用户从未签到

 楼主| 发表于 2013-4-12 08:45:10 | 显示全部楼层
重点是计算家位置函数,按理来说计算节点的包围盒,然后将视点设置在-y轴2倍的想方向宽度上,就可以全窗口显示场景,但每次显示的场景总不能填满窗口。

该用户从未签到

发表于 2013-4-12 08:46:17 | 显示全部楼层
您确定 这个类 实现了 你要的这个 “试图通过求场景的包围盒范围来设置相机位置”功能?这个类的代码 您看明白了么?

该用户从未签到

 楼主| 发表于 2013-4-12 08:53:30 | 显示全部楼层
不了解它是如何通过SetPosition(posBQ)函数来设置视点位置的。

该用户从未签到

发表于 2013-4-12 08:55:53 | 显示全部楼层
看一下 computeHomePosition 这个函数吧,这个才是重点

该用户从未签到

 楼主| 发表于 2013-4-12 10:10:34 | 显示全部楼层
谢谢,liuzhiyu123
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表