查看: 3368|回复: 14

通过键盘控制相机位置和角度

[复制链接]

该用户从未签到

发表于 2014-3-28 19:31:52 | 显示全部楼层 |阅读模式
我想实现的是通过键盘来控制移动相机的位置和角度,从而改变osg模型的显示的大小和角度。

例如,把相机位置移往y轴正方向,在KeyboardEventHandler中是这么更新camera位置的:

case 'd':{
        viewer->getCamera()->getViewMatrixAsLookAt(cameraEye, center,up);
        cameraEye.y()+=50
        viewer->getCamera()->setViewMatrixAsLookAt(cameraEye, center, up );
        }

但是程序运行后,键盘按‘d’后并没有更新camera的位置,这是为什么呢?

该用户从未签到

发表于 2014-3-28 22:30:15 | 显示全部楼层

Viewer里一般会添加继承自CameraManipulator的相机操作器。
即便你没加,默认会给你加个trackball。

凡是CameraManipulator的子类必须实现getInverseMatrix()接口。
否则相机姿态不会更新,除非你自己实现了刷新。

CameraManipulator影响ViewMatrix的机制可以查看osg源码的以下三个函数:
ViewerBase::frame()
Viewer::updateTraversal()
CameraManipulator::updateCamera(osg::Camera& camera) { camera.setViewMatrix(getInverseMatrix()); }

如果你直接用camera的setViewMatrix, 而没有修改或影响CameraManipulator的InverseMatrix。
你的修改会被frame()覆盖。


希望我的调查是准确的。。。

该用户从未签到

 楼主| 发表于 2014-4-1 17:13:37 | 显示全部楼层
cenfer 发表于 2014-3-28 22:30
Viewer里一般会添加继承自CameraManipulator的相机操作器。
即便你没加,默认会给你加个trackball。

我接触osg的时间不长,不太理解CameraManipulator对相机位置的影响。

更新相机的位置,可以这么做吗?
while(!viewer->done())
{
        viewer->getCamera()->setViewMatrixAsLookAt(eye,center,up);
        viewer->frame();
}

请问如何设置CameraManipulator,才能让相机的位置和角度根据setViewMatrix的矩阵变化呢?

该用户从未签到

发表于 2014-4-1 19:59:55 | 显示全部楼层
你是在帧前设置 还是会被覆盖

建议学者继承CameraManipulator写自己的相机操作器吧

该用户从未签到

 楼主| 发表于 2014-4-1 20:12:49 | 显示全部楼层
cenfer 发表于 2014-4-1 19:59
你是在帧前设置 还是会被覆盖

建议学者继承CameraManipulator写自己的相机操作器吧

我只是想移动相机的位置只是用来做一个简单的测试,只要能实现变换相机的位置就行,所以不想弄的太复杂。不知道还有没有其他的办法呢?

多谢你的回答了~

该用户从未签到

发表于 2014-4-1 20:27:26 | 显示全部楼层
viewer->getCameraManipulator()->setByMatrix(const osg::Matrixd& matrix)

该用户从未签到

发表于 2014-4-1 20:28:48 | 显示全部楼层
或者viewer->getCameraManipulator()->setByInverseMatrix(const osg::Matrixd& matrix)

这样就可以 改变相机的位置和姿态啦

该用户从未签到

 楼主| 发表于 2014-4-1 21:20:41 | 显示全部楼层
cenfer 发表于 2014-4-1 20:28
或者viewer->getCameraManipulator()->setByInverseMatrix(const osg::Matrixd& matrix)

这样就可以 改 ...

我试了一下,还是不得行啊。

我先定义了一个矩阵,然后调用getCameraManipulator:

        osg::Matrixd cameraRotation;
            cameraRotation.makeRotate(
          osg:egreesToRadians(-20.0), osg::Vec3(0,1,0), // roll
          osg::DegreesToRadians(-15.0), osg::Vec3(1,0,0) , // pitch
          osg::DegreesToRadians( 10.0), osg::Vec3(0,0,1) ); // heading

        viewer->getCameraManipulator()->setByMatrix(cameraRotation);

但是系统会报错:
Unhandled exception at 0x009b4460 in backwardprojection.exe: 0xC0000005: Access violation reading location 0x00000000.

请问你知道为什么吗?

该用户从未签到

发表于 2014-4-1 21:35:05 | 显示全部楼层
viewer是不是没有操作器啊
viewer->setCameraManipulator(new osgGA::TrackballManipulator);

该用户从未签到

 楼主| 发表于 2014-4-1 21:51:19 | 显示全部楼层
cenfer 发表于 2014-4-1 21:35
viewer是不是没有操作器啊
viewer->setCameraManipulator(new osgGA::TrackballManipulator);

是的。但是添加了操作器后屏幕一片空白,方块也没有显示出来。会不会是osg::ShapeDrawable的问题呢?

我把我的代码贴出来了,方便的话可不可以帮我看一下问题出在哪儿?

#include <osgViewer/Viewer>
#include<osg/Node>
#include<osg/Geode>
#include<osg/Group>
#include<osg/ShapeDrawable>
#include<osgDB/ReadFile>
#include<osgDB/WriteFile>

#include <osgGA/TrackballManipulator>
#include<osgUtil/Optimizer>

const float pi = atan(1.0f)*4;

int main()
{
        osg::ref_ptr<osgViewer::Viewer> viewer= new osgViewer::Viewer();

        osg::ref_ptr<osg::Group> root= new osg::Group();

        osg::ShapeDrawable* box;
        root->addChild(createCube(box));

        viewer->setSceneData(root.get());
       
        viewer->realize();

        viewer->setCameraManipulator(new osgGA::TrackballManipulator);

         //position the camera
        osg::Matrixd myCameraMatrix;

    osg::Matrixd cameraRotation;
    osg::Matrixd cameraTrans;
    cameraRotation.makeRotate(
          osg:egreesToRadians(-20.0), osg::Vec3(0,1,0), // roll
          osg::DegreesToRadians(-15.0), osg::Vec3(1,0,0) , // pitch
          osg::DegreesToRadians( 10.0), osg::Vec3(0,0,1) ); // heading

    cameraTrans.makeTranslate( 10,-50,15 );

    myCameraMatrix = cameraRotation * cameraTrans;

    viewer->getCameraManipulator()->setByMatrix(myCameraMatrix);


        viewer->run();

        return 0;

}

该用户从未签到

发表于 2014-4-1 22:00:48 | 显示全部楼层
因为你改变了相机操作器的姿态 物体不在视野里 当然看不见了。
和osg::ShapeDrawable没关系。

你还是先研究下怎么设置CameraMatrix才能正好看到目标物体把

该用户从未签到

发表于 2014-4-1 22:06:35 | 显示全部楼层
先把漫游器的参数设置的简单点,比如设置在坐标轴上,能看到效果了再调节吧,你现在的代码应该没问题了

该用户从未签到

 楼主| 发表于 2014-4-1 22:57:51 | 显示全部楼层
cenfer 发表于 2014-4-1 22:00
因为你改变了相机操作器的姿态 物体不在视野里 当然看不见了。
和osg::ShapeDrawable没关系。

好的,多谢cenfer

该用户从未签到

 楼主| 发表于 2014-4-2 17:34:58 | 显示全部楼层
本帖最后由 becky 于 2014-4-2 17:36 编辑

回答我自己的问题。viewer::run会自动创建一个TrackballManipulator来控制摄像机,所以,如果想要直接设置Camera对象的矩阵值,就不要用viewer::run,可以编写一个循环,来渲染图像,如下:

while (!viewer.done())
{
        viewer.getCamera()->setViewMatrix( myCameraMatrix );
        viewer.frame();
}

(可参见Openscenegraph Quick Start第三章)

该用户从未签到

 楼主| 发表于 2014-4-2 17:35:07 | 显示全部楼层
回答我自己的问题。viewer::run会自动创建一个TrackballManipulator来控制摄像机,所以,如果想要直接设置Camera对象的矩阵值,就不要用viewer::run,可以编写一个循环,来渲染图像,如下:

while (!viewer.done())
{
        viewer.getCamera()->setViewMatrix( myCameraMatrix );
        viewer.frame();
}

(可参见Openscenegraph Quick Start第三章)
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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