1
0
Fork 0

panoramic spherical distortion

This supports the panoramic distortion option, as found in osgViewer, in
the camera file syntax of flightgear.
This commit is contained in:
Tim Moore 2010-11-22 09:10:40 +01:00
parent 1cf207e054
commit d38fcc9979
3 changed files with 330 additions and 3 deletions

View file

@ -133,6 +133,30 @@ window, camera, or gui tags.
This specifies an orthographic view. The parameters are the sames as
the frustum node's.
texture
This tag indicates that the camera renders to a texture instead of the
framebuffer. For now the following tags are supported, but obviously
different texture formats should be specified too.
name - string
The name of the texture. This can be referred to by other cameras.
width, height - double
The dimensions of the texture
panoramic-distortion
This tag cause the camera to create distortion geometry that
corrects for projection onto a spherical screen. It is equivalent to
the --panoramic-sd option to osgviewer.
texture - string
The name of a texture, created by another camera, that will be
rendered on the distortion correction geometry.
radius - double
Radius of string
collar - double
size of screen collar.
gui
This is a special camera node that displays the 2D GUI.
@ -313,3 +337,61 @@ accounted for.
</rendering>
</sim>
</PropertyList>
This example renders the scene for projection onto a spherical screen.
<PropertyList>
<sim>
<rendering>
<camera-group>
<camera>
<window>
<name type="string">main</name>
<host-name type="string"></host-name>
<display>0</display>
<screen>0</screen>
<!-- <fullscreen type = "bool">true</fullscreen>-->
<width>1024</width>
<height>768</height>
</window>
<view>
<heading-deg type = "double">0</heading-deg>
</view>
<frustum>
<top>0.133</top>
<bottom>-0.133</bottom>
<left>-.1668</left>
<right>.1668</right>
<near>0.4</near>
<far>120000.0</far>
</frustum>
<texture>
<name>mainview</name>
<width>1024</width>
<height>768</height>
</texture>
</camera>
<camera>
<window><name>main</name></window>
<ortho>
<top>768</top>
<bottom>0</bottom>
<left>0</left>
<right>1024</right>
<near>-1.0</near>
<far>1.0</far>
</ortho>
<panoramic-spherical>
<texture>mainview</texture>
</panoramic-spherical>
</camera>
<gui>
<window>
<name type="string">main</name>
</window>
</gui>
</camera-group>
</rendering>
</sim>
</PropertyList>

View file

@ -36,9 +36,13 @@
#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osg/io_utils>
#include <osg/Math>
#include <osg/Matrix>
#include <osg/Notify>
#include <osg/Program>
#include <osg/Quat>
#include <osg/TexMat>
#include <osg/Vec3d>
#include <osg/Viewport>
@ -148,7 +152,18 @@ CameraInfo* CameraGroup::addCamera(unsigned flags, Camera* camera,
// resized; if the the viewport isn't copied here, it gets updated
// twice and ends up with the wrong value.
farCamera->setViewport(simgear::clone(camera->getViewport()));
_viewer->addSlave(farCamera, view, projection, useMasterSceneData);
farCamera->setDrawBuffer(camera->getDrawBuffer());
farCamera->setReadBuffer(camera->getReadBuffer());
farCamera->setRenderTargetImplementation(
camera->getRenderTargetImplementation());
const Camera::BufferAttachmentMap& bufferMap
= camera->getBufferAttachmentMap();
if (bufferMap.count(Camera::COLOR_BUFFER) != 0) {
farCamera->attach(
Camera::COLOR_BUFFER,
bufferMap.find(Camera::COLOR_BUFFER)->second._texture);
}
_viewer->addSlave(farCamera, projection, view, useMasterSceneData);
installCullVisitor(farCamera);
info->farCamera = farCamera;
info->farSlaveIndex = _viewer->getNumSlaves() - 1;
@ -156,7 +171,7 @@ CameraInfo* CameraGroup::addCamera(unsigned flags, Camera* camera,
camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT);
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
}
_viewer->addSlave(camera, view, projection, useMasterSceneData);
_viewer->addSlave(camera, projection, view, useMasterSceneData);
installCullVisitor(camera);
info->camera = camera;
info->slaveIndex = _viewer->getNumSlaves() - 1;
@ -297,6 +312,199 @@ void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode,
namespace flightgear
{
// Mostly copied from osg's osgViewer/View.cpp
static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(
const Vec3& origin, const Vec3& widthVector, const Vec3& heightVector,
double sphere_radius, double collar_radius,
Image* intensityMap = 0, const Matrix& projectorMatrix = Matrix())
{
osg::Vec3d center(0.0,0.0,0.0);
osg::Vec3d eye(0.0,0.0,0.0);
double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius);
bool flip = false;
bool texcoord_flip = false;
osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance);
OSG_INFO<<"createParoramicSphericalDisplayDistortionMesh : Projector position = "<<projector<<std::endl;
OSG_INFO<<"createParoramicSphericalDisplayDistortionMesh : distance = "<<distance<<std::endl;
// create the quad to visualize.
osg::Geometry* geometry = new osg::Geometry();
geometry->setSupportsDisplayList(false);
osg::Vec3 xAxis(widthVector);
float width = widthVector.length();
xAxis /= width;
osg::Vec3 yAxis(heightVector);
float height = heightVector.length();
yAxis /= height;
int noSteps = 160;
osg::Vec3Array* vertices = new osg::Vec3Array;
osg::Vec2Array* texcoords0 = new osg::Vec2Array;
osg::Vec2Array* texcoords1 = intensityMap==0 ? new osg::Vec2Array : 0;
osg::Vec4Array* colors = new osg::Vec4Array;
osg::Vec3 bottom = origin;
osg::Vec3 dx = xAxis*(width/((float)(noSteps-2)));
osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
osg::Vec3 top = origin + yAxis*height;
osg::Vec3 screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
float screenRadius = heightVector.length() * 0.5f;
geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
for(int i=0;i<noSteps;++i)
{
osg::Vec3 cursor = bottom+dy*(float)i;
for(int j=0;j<noSteps;++j)
{
osg::Vec2 texcoord(double(i)/double(noSteps-1), double(j)/double(noSteps-1));
double theta = texcoord.x() * 2.0 * osg::PI;
double phi = (1.0-texcoord.y()) * osg::PI;
if (texcoord_flip) texcoord.y() = 1.0f - texcoord.y();
osg::Vec3 pos(sin(phi)*sin(theta), sin(phi)*cos(theta), cos(phi));
pos = pos*projectorMatrix;
double alpha = atan2(pos.x(), pos.y());
if (alpha<0.0) alpha += 2.0*osg::PI;
double beta = atan2(sqrt(pos.x()*pos.x() + pos.y()*pos.y()), pos.z());
if (beta<0.0) beta += 2.0*osg::PI;
double gamma = atan2(sqrt(double(pos.x()*pos.x() + pos.y()*pos.y())), double(pos.z()+distance));
if (gamma<0.0) gamma += 2.0*osg::PI;
osg::Vec3 v = screenCenter + osg::Vec3(sin(alpha)*gamma*2.0/osg::PI, -cos(alpha)*gamma*2.0/osg::PI, 0.0f)*screenRadius;
if (flip)
vertices->push_back(osg::Vec3(v.x(), top.y()-(v.y()-origin.y()),v.z()));
else
vertices->push_back(v);
texcoords0->push_back( texcoord );
osg::Vec2 texcoord1(alpha/(2.0*osg::PI), 1.0f - beta/osg::PI);
if (intensityMap)
{
colors->push_back(intensityMap->getColor(texcoord1));
}
else
{
colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
if (texcoords1) texcoords1->push_back( texcoord1 );
}
}
}
// pass the created vertex array to the points geometry object.
geometry->setVertexArray(vertices);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
geometry->setTexCoordArray(0,texcoords0);
if (texcoords1) geometry->setTexCoordArray(1,texcoords1);
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
geometry->addPrimitiveSet(elements);
for(int i=0;i<noSteps-1;++i)
{
for(int j=0;j<noSteps-1;++j)
{
int i1 = j+(i+1)*noSteps;
int i2 = j+(i)*noSteps;
int i3 = j+1+(i)*noSteps;
int i4 = j+1+(i+1)*noSteps;
osg::Vec3& v1 = (*vertices)[i1];
osg::Vec3& v2 = (*vertices)[i2];
osg::Vec3& v3 = (*vertices)[i3];
osg::Vec3& v4 = (*vertices)[i4];
if ((v1-screenCenter).length()>screenRadius) continue;
if ((v2-screenCenter).length()>screenRadius) continue;
if ((v3-screenCenter).length()>screenRadius) continue;
if ((v4-screenCenter).length()>screenRadius) continue;
elements->push_back(i1);
elements->push_back(i2);
elements->push_back(i3);
elements->push_back(i1);
elements->push_back(i3);
elements->push_back(i4);
}
}
return geometry;
}
void CameraGroup::buildDistortionCamera(const SGPropertyNode* psNode,
Camera* camera)
{
const SGPropertyNode* texNode = psNode->getNode("texture");
if (!texNode) {
// error
return;
}
string texName = texNode->getStringValue();
TextureMap::iterator itr = _textureTargets.find(texName);
if (itr == _textureTargets.end()) {
// error
return;
}
Viewport* viewport = camera->getViewport();
float width = viewport->width();
float height = viewport->height();
TextureRectangle* texRect = itr->second.get();
double radius = psNode->getDoubleValue("radius", 1.0);
double collar = psNode->getDoubleValue("collar", 0.45);
Geode* geode = new Geode();
geode->addDrawable(createParoramicSphericalDisplayDistortionMesh(
Vec3(0.0f,0.0f,0.0f), Vec3(width,0.0f,0.0f),
Vec3(0.0f,height,0.0f), radius, collar));
// new we need to add the texture to the mesh, we do so by creating a
// StateSet to contain the Texture StateAttribute.
StateSet* stateset = geode->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0, texRect, StateAttribute::ON);
stateset->setMode(GL_LIGHTING, StateAttribute::OFF);
TexMat* texmat = new TexMat;
texmat->setScaleByTextureRectangleSize(true);
stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON);
#if 0
if (!applyIntensityMapAsColours && intensityMap)
{
stateset->setTextureAttributeAndModes(1, new osg::Texture2D(intensityMap), osg::StateAttribute::ON);
}
#endif
// add subgraph to render
camera->addChild(geode);
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
camera->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0));
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
camera->setCullingMode(osg::CullSettings::NO_CULLING);
camera->setName("DistortionCorrectionCamera");
}
CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
{
WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
@ -390,13 +598,43 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
double sheary = cameraNode->getDoubleValue("shear-y", 0);
pOff.makeTranslate(-shearx, -sheary, 0);
}
CameraInfo* info = addCamera(cameraFlags, camera, pOff, vOff);
const SGPropertyNode* textureNode = cameraNode->getNode("texture");
if (textureNode) {
string texName = textureNode->getStringValue("name");
int tex_width = textureNode->getIntValue("width");
int tex_height = textureNode->getIntValue("height");
TextureRectangle* texture = new TextureRectangle;
texture->setTextureSize(tex_width, tex_height);
texture->setInternalFormat(GL_RGB);
texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR);
texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
texture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
texture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
camera->setDrawBuffer(GL_FRONT);
camera->setReadBuffer(GL_FRONT);
camera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
camera->attach(Camera::COLOR_BUFFER, texture);
_textureTargets[texName] = texture;
} else {
camera->setDrawBuffer(GL_BACK);
camera->setReadBuffer(GL_BACK);
}
const SGPropertyNode* psNode = cameraNode->getNode("panoramic-spherical");
bool useMasterSceneGraph = !psNode;
CameraInfo* info = addCamera(cameraFlags, camera, vOff, pOff,
useMasterSceneGraph);
// If a viewport isn't set on the camera, then it's hard to dig it
// out of the SceneView objects in the viewer, and the coordinates
// of mouse events are somewhat bizzare.
SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
buildViewport(info, viewportNode, window->gc->getTraits());
updateCameras(info);
// Distortion camera needs the viewport which is created by addCamera().
if (psNode) {
info->flags = info->flags | VIEW_ABSOLUTE;
buildDistortionCamera(psNode, camera);
}
return info;
}

View file

@ -17,6 +17,7 @@
#ifndef CAMERAGROUP_HXX
#define CAMERAGROUP_HXX 1
#include <map>
#include <string>
#include <vector>
@ -24,6 +25,7 @@
#include <osg/ref_ptr>
#include <osg/Referenced>
#include <osg/Node>
#include <osg/TextureRectangle>
// For osgUtil::LineSegmentIntersector::Intersections, which is a typedef.
#include <osgUtil/LineSegmentIntersector>
@ -178,6 +180,9 @@ public:
/** Update camera properties after a resize event.
*/
void resized();
void buildDistortionCamera(const SGPropertyNode* psNode,
osg::Camera* camera);
protected:
CameraList _cameras;
osg::ref_ptr<osgViewer::Viewer> _viewer;
@ -186,6 +191,8 @@ protected:
float _zNear;
float _zFar;
float _nearField;
typedef std::map<std::string, osg::ref_ptr<osg::TextureRectangle> > TextureMap;
TextureMap _textureTargets;
};
}