osg--相机

这篇博客详细介绍了OpenGL中的osg库如何管理和控制相机,包括坐标系统、相机的视图矩阵和投影矩阵设置,以及osgViewer::Viewer和osgViewer::CompositeViewer的使用。还涉及了相机的默认全局设置,如立体视觉的实现,以及如何渲染到纹理并保存图片。内容涵盖从基本的相机操作到复杂的视图管理,是理解osg中相机和视图控制的重要参考资料。

坐标

Vs = V * modelViewMatrix * projectionMatrix * windowMatrix

  • V * modelViewMatrix * projectionMatrix为左手系,各分量在-1到1

unproject

  • V0 = (Xs, Ys, 0) * invMVPW
  • V1 = (Xs, Ys, 1) * invMVPW

相机

  • osg::Camera 是group节点
    • 功能

      • 管理坐标
        • setViewMatrix

        • setViewMatrixAsLookAt

        • setProjectionMatrix

        • setProjectionMatrixAsFrustum

        • setProjectionMatrixAsOrtho

        • setProjectionMatrixAsOrtho2D

        • setProjectionMatrixAsPerspective

        • setViewport 参数为osg::Viewport

        • get*()

            osg::Matrix viewMatrix = camera->getViewMatrix();
            osg::Vec3 eye, center, up
            camera->getViewMatrixAsLookAt( eye, center, up );
          
      • 封装opengl函数
        • setClearMask 参数为GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT
        • setClearColor 参数为osg::Vec4
        • setClearDepth
        • setClearStencil
        • setClearAccum
        • get*()
      • 显示上下文控制
      • 缓冲区控制
        • color buffer
        • depth buffer
    • 多个相机共享显示上下文

    • 设置相机顺序

        camera1->setRenderOrder( osg::Camera::PRE_RENDER );
        camera2->setRenderOrder( osg::Camera::PRE_RENDER, 5 );
        camera3->setRenderOrder( osg::Camera::POST_RENDER );
      
  • osgViewer::Viewer
    • getCamera() 获取主相机,主相机是osgViewer自动生成并添加为子节点

示例

#include <osg/Camera>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>

int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("lz.osg");
	osg::ref_ptr<osg::Node> hud_model = osgDB::readNodeFile("glider.osg");

	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setClearMask(GL_DEPTH_BUFFER_BIT);
	camera->setRenderOrder(osg::Camera::POST_RENDER);
	camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
	camera->setViewMatrixAsLookAt(
		osg::Vec3(0.0f, -5.0f, 5.0f), osg::Vec3(),
		osg::Vec3(0.0f, 1.0f, 1.0f)
	);
	camera->addChild(hud_model.get());

	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(model.get());
	root->addChild( camera.get() );

	osgViewer::Viewer viewer;
	viewer.setSceneData(root.get());
	return viewer.run();
}

视图类

  • osgViewer::Viewer

    • 管理场景树
      • setSceneData
      • run()
        • 指定主相机的控制器
        • 设置显示上下文
        • 帧循环
      • setRunFrameScheme()参数为osgViewer::Viewer::ON_DEMAND/osgViewer::Viewer::CONTINUOUS
      • setRunMaxFrameRate()
      • done()
        • Esc默认结束键
        • setKeyEventSetsDone指定结束键
      • setDone()
      • getFrameStamp()获取帧信息
    • 管理相机view matrix
      • setCameraManipulator(),参数为osgGA::CameraManipulator

          viewer.setCameraManipulator( new osgGA::TrackballManipulator );
          viewer.setCameraManipulator( NULL )
        

    在这里插入图片描述

    • 管理输入事件

      • osgGA::GUIEventHandler
      • view1->getCamera()->setAllowEventFocus( false );
    • 显示

      • 设置屏幕坐标
        • setUpViewInWindow
      • 设置屏幕
        • setUpViewOnSingleScreen 参数为代表显示器的整数序号
        • setUpViewFor3DSphericalDisplay 球面显示
  • osgViewer::CompositeViewer

    • run()
    • frame()
    • done()
    • addView()
    • removeView()
    • getView() 返回osgViewer::View,是osgViewer::Viewer的基类,无run()和frame(),不能用作单一视图

示例–osgViewer::Viewer

#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>
#include <iostream>

int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("lz.osg");

	osgViewer::Viewer viewer;
	viewer.setSceneData(model.get());

	viewer.setCameraManipulator(new osgGA::TrackballManipulator);

	while (!viewer.done())
	{
		viewer.frame();
		std::cout << "Frame number: " <<
			viewer.getFrameStamp()->getFrameNumber() << std::endl;
	}
	return 0;
}

示例–osgViewer::CompositeViewer

#include <osgDB/ReadFile>
#include <osgViewer/CompositeViewer>

osgViewer::View* createView(int x, int y, int w, int h,
	osg::Node* scene)
{
	osg::ref_ptr<osgViewer::View> view = new osgViewer::View;
	view->setSceneData(scene);
	view->setUpViewInWindow(x, y, w, h);
	return view.release();
}

int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model1 = osgDB::readNodeFile("cessna.osg");
	osg::ref_ptr<osg::Node> model2 = osgDB::readNodeFile("cow.osg");
	osg::ref_ptr<osg::Node> model3 = osgDB::readNodeFile("glider.osg");

	osgViewer::View* view1 = createView(50, 50, 320, 240, model1);
	osgViewer::View* view2 = createView(370, 50, 320, 240, model2);
	osgViewer::View* view3 = createView(185, 310, 320, 240, model3);

	osgViewer::CompositeViewer viewer;
	viewer.addView(view1);
	viewer.addView(view2);
	viewer.addView(view3);
	return viewer.run();
}

注:通过多个相机的setViewport()也可在同一视图不同区域绘制,但是事件不独立

相机/视图等的默认全局设置

osg::DisplaySettings* ds = osg::DisplaySettings::instance();

  • setDoubleBuffer() 开/关
  • setDepthBuffer 开/关
  • setMinimumNumAlphaBits 设置alpha buffer, a stencil buffer, and an accumulation buffer位数,默认为0
  • setNumMultiSamples 设置多重采样,默认为0
  • 设置stereo渲染

示例

#include <osgDB/ReadFile>
#include <osgViewer/Viewer>

int main(int argc, char** argv)
{
	osg::DisplaySettings::instance()->setNumMultiSamples(4);

	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("cessna.osg");
	osgViewer::Viewer viewer;
	viewer.setSceneData(model.get());
	return viewer.run();
}

立体视觉

  • setStereoMode()

    • ANAGLYPHIC
    • QUAD_BUFFER
    • HORIZONTAL_SPLIT
    • VERTICAL_SPLIT
    • HORIZONTAL_INTERLACE
    • VERTICAL_INTERLACE
    • CHECKERBOARD
    • LEFT_EYE
    • RIGHT_EYE
  • setStereo

      osg::DisplaySettings::instance()->setStereoMode( mode );
      osg::DisplaySettings::instance()->setStereo( true );
    
      osg::DisplaySettings::instance()->setStereoMode(osg::DisplaySettings::ANAGLYPHIC);
      osg::DisplaySettings::instance()->setEyeSeparation(0.05f);
      osg::DisplaySettings::instance()->setStereo(true);
    

示例

#include <osgDB/ReadFile>
#include <osgViewer/Viewer>

int main(int argc, char** argv)
{
	osg::DisplaySettings::instance()->setStereoMode(osg::DisplaySettings::ANAGLYPHIC);
	osg::DisplaySettings::instance()->setEyeSeparation(0.05f);
	osg::DisplaySettings::instance()->setStereo(true);

	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(
		"cessna.osg");
	osgViewer::Viewer viewer;
	viewer.setSceneData(model.get());
	return viewer.run();
}

渲染到纹理

  • 三种方法
    • 直接拷贝默认frame buffer,默认使用
      • camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER );
        • 内部使用glCopyTexSubImage拷贝到附加到相机的纹理
    • pixel buffer 直接渲染到pixel buffer
      • camera->setRenderTargetImplementation( osg::Camera::PIXEL_BUFFER );
    • FBO 渲染到自定义FBO
      • camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
  • 步骤
    • 创建纹理
      • osg::Texture
      • setTextureSize()
    • 渲染到纹理
      • osg::Camera::COLOR_BUFFER

      • osg::Camera::COLOR_BUFFER0-osg::Camera::COLOR_BUFFER15

      • osg::Camera::DEPTH_BUFFER

      • osg::Camera::STENCIL_BUFFER

          camera->attach( osg::Camera::COLOR_BUFFER, texture.get() );
        
    • 使用纹理

示例–渲染到纹理

#include <osg/Camera>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>

class FindTextureVisitor : public osg::NodeVisitor
{
public:
	FindTextureVisitor(osg::Texture* tex) : _texture(tex)
	{
		setTraversalMode(
			osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
	}


	virtual void apply(osg::Node& node);
	virtual void apply(osg::Geode& geode);
	void replaceTexture(osg::StateSet* ss);


protected:
	osg::ref_ptr<osg::Texture> _texture;
};

void FindTextureVisitor::apply(osg::Node& node)
{
	replaceTexture(node.getStateSet());
	traverse(node);
}
void FindTextureVisitor::apply(osg::Geode& geode)
{
	replaceTexture(geode.getStateSet());
	for (unsigned int i = 0; i<geode.getNumDrawables(); ++i)
	{
		replaceTexture(geode.getDrawable(i)->getStateSet());
	}
	traverse(geode);
}
void FindTextureVisitor::replaceTexture(osg::StateSet* ss)
{
	if (ss)
	{
		osg::Texture* oldTexture = dynamic_cast<osg::Texture*>(
			ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE)
			);
		if (oldTexture) ss->setTextureAttribute(
			0, _texture.get());
	}
}
int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("lz.osg");
	osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("glider.osg");

	int tex_width = 1024, tex_height = 1024;

	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
	texture->setTextureSize(tex_width, tex_height);
	texture->setInternalFormat(GL_RGBA);
	texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
	texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);

	FindTextureVisitor ftv(texture.get());
	if (model.valid()) model->accept(ftv);

	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setViewport(0, 0, tex_width, tex_height);
	camera->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
	camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	camera->setRenderOrder(osg::Camera::PRE_RENDER);
	camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
	camera->attach(osg::Camera::COLOR_BUFFER, texture.get());

	camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
	camera->addChild(sub_model.get());

	osgViewer::Viewer viewer;
	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(model.get());
	root->addChild(camera.get());
	viewer.setSceneData(root.get());
	viewer.setCameraManipulator(new osgGA::TrackballManipulator);

	float delta = 0.1f, bias = 0.0f;
	osg::Vec3 eye(0.0f, -5.0f, 5.0f);
	while (!viewer.done())
	{
		if (bias<-1.0f) delta = 0.1f;
		else if (bias>1.0f) delta = -0.1f;
		bias += delta;
		camera->setViewMatrixAsLookAt(eye, osg::Vec3(), osg::Vec3(bias, 1.0f, 1.0f));

		viewer.frame();
	}
	return 0;
}

示例–渲染并保存图片

#include <osg/Camera>
#include <osgDB/WriteFile>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>

class FindTextureVisitor : public osg::NodeVisitor
{
public:
	FindTextureVisitor(osg::Texture* tex) : _texture(tex)
	{
		setTraversalMode(
			osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
	}


	virtual void apply(osg::Node& node);
	virtual void apply(osg::Geode& geode);
	void replaceTexture(osg::StateSet* ss);


protected:
	osg::ref_ptr<osg::Texture> _texture;
};

void FindTextureVisitor::apply(osg::Node& node)
{
	replaceTexture(node.getStateSet());
	traverse(node);
}
void FindTextureVisitor::apply(osg::Geode& geode)
{
	replaceTexture(geode.getStateSet());
	for (unsigned int i = 0; i<geode.getNumDrawables(); ++i)
	{
		replaceTexture(geode.getDrawable(i)->getStateSet());
	}
	traverse(geode);
}
void FindTextureVisitor::replaceTexture(osg::StateSet* ss)
{
	if (ss)
	{
		osg::Texture* oldTexture = dynamic_cast<osg::Texture*>(
			ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE)
			);
		if (oldTexture) ss->setTextureAttribute(
			0, _texture.get());
	}
}
int main(int argc, char** argv)
{
	osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("lz.osg");
	osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("glider.osg");

	int tex_width = 1024, tex_height = 1024;

	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
	texture->setTextureSize(tex_width, tex_height);
	texture->setInternalFormat(GL_RGBA);
	texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
	texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);

	FindTextureVisitor ftv(texture.get());
	if (model.valid()) model->accept(ftv);

	osg::ref_ptr<osg::Camera> camera = new osg::Camera;
	camera->setViewport(0, 0, tex_width, tex_height);
	camera->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
	camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	camera->setRenderOrder(osg::Camera::PRE_RENDER);
	camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
	camera->attach(osg::Camera::COLOR_BUFFER, texture.get());

	camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
	camera->addChild(sub_model.get());

	osg::ref_ptr<osg::Image> image = new osg::Image;
	osg::ref_ptr<osg::Camera> camera2 = new osg::Camera;
	camera2->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
	camera2->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	camera2->setRenderOrder(osg::Camera::POST_RENDER);
	camera2->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER);
	camera2->attach(osg::Camera::COLOR_BUFFER, image.get());

	camera2->addChild(model.get());

	osgViewer::Viewer viewer;
	osg::ref_ptr<osg::Group> root = new osg::Group;
	root->addChild(camera2.get());
	root->addChild(camera.get());
	viewer.setSceneData(root.get());
	viewer.setCameraManipulator(new osgGA::TrackballManipulator);

	float delta = 0.1f, bias = 0.0f;
	osg::Vec3 eye(0.0f, -5.0f, 5.0f);
	while (!viewer.done())
	{
		if (bias<-1.0f) delta = 0.1f;
		else if (bias>1.0f) delta = -0.1f;
		bias += delta;
		camera->setViewMatrixAsLookAt(eye, osg::Vec3(), osg::Vec3(bias, 1.0f, 1.0f));

		viewer.frame();
		if(viewer.getFrameStamp()->getFrameNumber()%120==0)
			osgDB::writeImageFile(*image, "saved_image.bmp");
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值