Added projectorMatrix parameter support to *SphericalDisplay setup functions and .view, this allows one

to flip, rotate, or turn up side the position of the projector.  Note, projector at base of display is the default.
This commit is contained in:
Robert Osfield 2008-01-28 15:41:42 +00:00
parent 2db7fe500f
commit 54129105a4
3 changed files with 130 additions and 143 deletions

View File

@ -161,10 +161,10 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter
/** Convenience method for spherical display using 6 slave cameras rendering the 6 sides of a cube map, and 7th camera doing distortion correction to present on a spherical display.*/
void setUpViewFor3DSphericalDisplay(double radius=1.0, double collar=0.45, unsigned int screenNum=0, osg::Image* intensityMap=0);
void setUpViewFor3DSphericalDisplay(double radius=1.0, double collar=0.45, unsigned int screenNum=0, osg::Image* intensityMap=0, const osg::Matrixd& projectorMatrix = osg::Matrixd());
/** Convenience method for spherical display by rendering main scene to as panoramic 2:1 texture and then doing distortion correction to present onto a spherical display.*/
void setUpViewForPanoramicSphericalDisplay(double radius=1.0, double collar=0.45, unsigned int screenNum=0, osg::Image* intensityMap=0);
void setUpViewForPanoramicSphericalDisplay(double radius=1.0, double collar=0.45, unsigned int screenNum=0, osg::Image* intensityMap=0, const osg::Matrixd& projectorMatrix = osg::Matrixd());
/** Return true if this view contains a specified camera.*/

View File

@ -21,6 +21,55 @@ osgDB::RegisterDotOsgWrapperProxy View_Proxy
View_writeLocalData
);
static bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword)
{
bool iteratorAdvanced = false;
if (fr[0].matchWord(keyword) && fr[1].isOpenBracket())
{
int entry = fr[0].getNoNestedBrackets();
fr += 2;
int row=0;
int col=0;
double v;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
if (fr[0].getFloat(v))
{
matrix(row,col)=v;
++col;
if (col>=4)
{
col = 0;
++row;
}
++fr;
}
else fr.advanceOverCurrentFieldOrBlock();
}
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
static bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword)
{
fw.indent() << keyword <<" {" << std::endl;
fw.moveIn();
fw.indent() << matrix(0,0) << " " << matrix(0,1) << " " << matrix(0,2) << " " << matrix(0,3) << std::endl;
fw.indent() << matrix(1,0) << " " << matrix(1,1) << " " << matrix(1,2) << " " << matrix(1,3) << std::endl;
fw.indent() << matrix(2,0) << " " << matrix(2,1) << " " << matrix(2,2) << " " << matrix(2,3) << std::endl;
fw.indent() << matrix(3,0) << " " << matrix(3,1) << " " << matrix(3,2) << " " << matrix(3,3) << std::endl;
fw.moveOut();
fw.indent() << "}"<< std::endl;
return true;
}
osg::Image* readIntensityImage(osgDB::Input& fr, bool& itrAdvanced)
{
if (fr.matchSequence("intensityMap {"))
@ -107,6 +156,7 @@ bool View_readLocalData(osg::Object &obj, osgDB::Input &fr)
double collar = 0.45;
unsigned int screenNum = 0;
unsigned int intensityFormat = 8;
osg::Matrix matrix;
std::string filename;
osg::ref_ptr<osg::Image> intensityMap;
int entry = fr[0].getNoNestedBrackets();
@ -122,6 +172,7 @@ bool View_readLocalData(osg::Object &obj, osgDB::Input &fr)
if (fr.read("intensityFile",filename)) local_itrAdvanced = true;
if (fr.matchSequence("intensityMap {")) intensityMap = readIntensityImage(fr,local_itrAdvanced);
if (fr.read("intensityFormat",intensityFormat)) local_itrAdvanced = true;
if (readMatrix(matrix,fr,"projectorMatrix")) local_itrAdvanced = true;
if (!local_itrAdvanced) ++fr;
}
@ -144,8 +195,8 @@ bool View_readLocalData(osg::Object &obj, osgDB::Input &fr)
}
if (matchedFirst) view.setUpViewFor3DSphericalDisplay(radius, collar, screenNum, intensityMap.get());
else view.setUpViewForPanoramicSphericalDisplay(radius, collar, screenNum, intensityMap.get());
if (matchedFirst) view.setUpViewFor3DSphericalDisplay(radius, collar, screenNum, intensityMap.get(), matrix);
else view.setUpViewForPanoramicSphericalDisplay(radius, collar, screenNum, intensityMap.get(), matrix);
}
int x = 0;

View File

@ -703,7 +703,7 @@ void View::setUpViewOnSingleScreen(unsigned int screenNum)
_camera->setReadBuffer(buffer);
}
static osg::Geometry* create3DSphericalDisplayDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, double sphere_radius, double collar_radius,osg::Image* intensityMap)
static osg::Geometry* create3DSphericalDisplayDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, double sphere_radius, double collar_radius,osg::Image* intensityMap, const osg::Matrix& projectorMatrix)
{
osg::Vec3d center(0.0,0.0,0.0);
osg::Vec3d eye(0.0,0.0,0.0);
@ -747,8 +747,7 @@ static osg::Geometry* create3DSphericalDisplayDistortionMesh(const osg::Vec3& or
osg::Vec3 cursor = bottom;
int i,j;
if (centerProjection)
{
for(i=0;i<noSteps;++i)
@ -772,7 +771,7 @@ static osg::Geometry* create3DSphericalDisplayDistortionMesh(const osg::Vec3& or
cos(phi));
vertices->push_back(cursor);
texcoords0->push_back(texcoord);
texcoords0->push_back(texcoord * projectorMatrix);
osg::Vec2 texcoord1(theta/(2.0*osg::PI), 1.0f - phi/osg::PI_2);
if (intensityMap)
@ -816,7 +815,7 @@ static osg::Geometry* create3DSphericalDisplayDistortionMesh(const osg::Vec3& or
z / sphere_radius);
vertices->push_back(cursor);
texcoords0->push_back(texcoord);
texcoords0->push_back(texcoord * projectorMatrix);
osg::Vec2 texcoord1(theta/(2.0*osg::PI), 1.0f - phi/osg::PI_2);
if (intensityMap)
@ -858,7 +857,7 @@ static osg::Geometry* create3DSphericalDisplayDistortionMesh(const osg::Vec3& or
return geometry;
}
void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned int screenNum, osg::Image* intensityMap)
void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned int screenNum, osg::Image* intensityMap, const osg::Matrixd& projectorMatrix)
{
osg::notify(osg::INFO)<<"View::setUpViewFor3DSphericalDisplay(rad="<<radius<<", cllr="<<collar<<", sn="<<screenNum<<", im="<<intensityMap<<")"<<std::endl;
osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
@ -868,7 +867,6 @@ void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned
return;
}
osg::GraphicsContext::ScreenIdentifier si;
si.readDISPLAY();
@ -1047,7 +1045,7 @@ void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned
// distortion correction set up.
{
osg::Geode* geode = new osg::Geode();
geode->addDrawable(create3DSphericalDisplayDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), radius, collar, applyIntensityMapAsColours ? intensityMap : 0));
geode->addDrawable(create3DSphericalDisplayDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), radius, collar, applyIntensityMapAsColours ? intensityMap : 0, projectorMatrix));
// new we need to add the texture to the mesh, we do so by creating a
// StateSet to contain the Texture StateAttribute.
@ -1063,14 +1061,14 @@ void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(gc.get());
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
camera->setClearColor( osg::Vec4(0.1,0.1,1.0,1.0) );
camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) );
camera->setViewport(new osg::Viewport(0, 0, width, height));
GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
camera->setDrawBuffer(buffer);
camera->setReadBuffer(buffer);
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
camera->setAllowEventFocus(false);
//camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE);
camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE);
//camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
camera->setProjectionMatrixAsOrtho2D(0,width,0,height);
@ -1093,7 +1091,7 @@ void View::setUpViewFor3DSphericalDisplay(double radius, double collar, unsigned
}
}
static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, double sphere_radius, double collar_radius, osg::Image* intensityMap)
static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const osg::Vec3& origin, const osg::Vec3& widthVector, const osg::Vec3& heightVector, double sphere_radius, double collar_radius, osg::Image* intensityMap, const osg::Matrix& projectorMatrix)
{
osg::Vec3d center(0.0,0.0,0.0);
osg::Vec3d eye(0.0,0.0,0.0);
@ -1110,7 +1108,6 @@ static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const osg::V
osg::notify(osg::INFO)<<"createParoramicSphericalDisplayDistortionMesh : Projector position = "<<projector<<std::endl;
osg::notify(osg::INFO)<<"createParoramicSphericalDisplayDistortionMesh : distance = "<<distance<<std::endl;
// create the quad to visualize.
osg::Geometry* geometry = new osg::Geometry();
@ -1137,48 +1134,49 @@ static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const osg::V
osg::Vec3 top = origin + yAxis*height;
osg::Vec3d screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
osg::Vec3 screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
float screenRadius = heightVector.length() * 0.5f;
double rotation = 0.0;
osg::Vec3 cursor = bottom;
int i,j;
int midSteps = noSteps/2;
for(i=0;i<midSteps;++i)
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(j=0;j<midSteps;++j)
for(int j=0;j<noSteps;++j)
{
osg::Vec2 delta(cursor.x() - screenCenter.x(), cursor.y() - screenCenter.y());
double theta = atan2(delta.x(), -delta.y());
theta += 2*osg::PI;
double phi = osg::PI_2 * delta.length() / screenRadius;
if (phi > osg::PI_2) phi = osg::PI_2;
double f = distance * sin(phi);
double e = distance * cos(phi) + sqrt( sphere_radius*sphere_radius - f*f);
double l = e * cos(phi);
double h = e * sin(phi);
double gamma = atan2(h, l-distance);
osg::Vec2 texcoord(theta/(2.0*osg::PI), 1.0-gamma/osg::PI);
// osg::notify(osg::NOTICE)<<"cursor = "<<cursor<< " theta = "<<theta<< "phi="<<phi<<" gamma = "<<gamma<<" texcoord="<<texcoord<<std::endl;
if (flip)
vertices->push_back(osg::Vec3(cursor.x(), top.y()-(cursor.y()-origin.y()),cursor.z()));
else
vertices->push_back(cursor);
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;
texcoords0->push_back( texcoord_flip ? osg::Vec2(texcoord.x(), 1.0f - texcoord.y()) : texcoord);
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(pos.x()*pos.x() + pos.y()*pos.y()), 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(theta/(2.0*osg::PI), 1.0f - phi/osg::PI_2);
osg::Vec2 texcoord1(alpha/(2.0*osg::PI), 1.0f - beta/osg::PI);
if (intensityMap)
{
{
colors->push_back(intensityMap->getColor(texcoord1));
}
else
@ -1187,93 +1185,10 @@ static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const osg::V
if (texcoords1) texcoords1->push_back( texcoord1 );
}
if (j+1<midSteps) cursor += dx;
}
for(;j<noSteps;++j)
{
osg::Vec2 delta(cursor.x() - screenCenter.x(), cursor.y() - screenCenter.y());
double theta = atan2(delta.x(), -delta.y());
double phi = osg::PI_2 * delta.length() / screenRadius;
if (phi > osg::PI_2) phi = osg::PI_2;
double f = distance * sin(phi);
double e = distance * cos(phi) + sqrt( sphere_radius*sphere_radius - f*f);
double l = e * cos(phi);
double h = e * sin(phi);
double gamma = atan2(h, l-distance);
osg::Vec2 texcoord(theta/(2.0*osg::PI), 1.0-gamma/osg::PI);
// osg::notify(osg::NOTICE)<<"cursor = "<<cursor<< " theta = "<<theta<< "phi="<<phi<<" gamma = "<<gamma<<" texcoord="<<texcoord<<std::endl;
if (flip)
vertices->push_back(osg::Vec3(cursor.x(), top.y()-(cursor.y()-origin.y()),cursor.z()));
else
vertices->push_back(cursor);
texcoords0->push_back( texcoord_flip ? osg::Vec2(texcoord.x(), 1.0f - texcoord.y()) : texcoord);
osg::Vec2 texcoord1(theta/(2.0*osg::PI), 1.0f - phi/osg::PI_2);
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 );
}
cursor += dx;
}
// osg::notify(osg::NOTICE)<<std::endl;
}
for(;i<noSteps;++i)
{
osg::Vec3 cursor = bottom+dy*(float)i;
for(j=0;j<noSteps;++j)
{
osg::Vec2 delta(cursor.x() - screenCenter.x(), cursor.y() - screenCenter.y());
double theta = atan2(delta.x(), -delta.y());
if (theta<0.0) theta += 2*osg::PI;
double phi = osg::PI_2 * delta.length() / screenRadius;
if (phi > osg::PI_2) phi = osg::PI_2;
double f = distance * sin(phi);
double e = distance * cos(phi) + sqrt( sphere_radius*sphere_radius - f*f);
double l = e * cos(phi);
double h = e * sin(phi);
double gamma = atan2(h, l-distance);
osg::Vec2 texcoord(theta/(2.0*osg::PI), 1.0-gamma/osg::PI);
// osg::notify(osg::NOTICE)<<"cursor = "<<cursor<< " theta = "<<theta<< "phi="<<phi<<" gamma = "<<gamma<<" texcoord="<<texcoord<<std::endl;
if (flip)
vertices->push_back(osg::Vec3(cursor.x(), top.y()-(cursor.y()-origin.y()),cursor.z()));
else
vertices->push_back(cursor);
texcoords0->push_back( texcoord_flip ? osg::Vec2(texcoord.x(), 1.0f - texcoord.y()) : texcoord);
osg::Vec2 texcoord1(theta/(2.0*osg::PI), 1.0f - phi/osg::PI_2);
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 );
}
cursor += dx;
}
// osg::notify(osg::NOTICE)<<std::endl;
}
// pass the created vertex array to the points geometry object.
geometry->setVertexArray(vertices);
@ -1284,21 +1199,42 @@ static osg::Geometry* createParoramicSphericalDisplayDistortionMesh(const osg::V
geometry->setTexCoordArray(0,texcoords0);
if (texcoords1) geometry->setTexCoordArray(1,texcoords1);
for(i=0;i<noSteps-1;++i)
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
geometry->addPrimitiveSet(elements);
for(int i=0;i<noSteps-1;++i)
{
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);
for(j=0;j<noSteps;++j)
for(int j=0;j<noSteps-1;++j)
{
elements->push_back(j+(i+1)*noSteps);
elements->push_back(j+(i)*noSteps);
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);
}
geometry->addPrimitiveSet(elements);
}
return geometry;
}
void View::setUpViewForPanoramicSphericalDisplay(double radius, double collar, unsigned int screenNum, osg::Image* intensityMap)
void View::setUpViewForPanoramicSphericalDisplay(double radius, double collar, unsigned int screenNum, osg::Image* intensityMap, const osg::Matrixd& projectorMatrix)
{
osg::notify(osg::INFO)<<"View::setUpViewForPanoramicSphericalDisplay(rad="<<radius<<", cllr="<<collar<<", sn="<<screenNum<<", im="<<intensityMap<<")"<<std::endl;
@ -1386,7 +1322,7 @@ void View::setUpViewForPanoramicSphericalDisplay(double radius, double collar, u
// distortion correction set up.
{
osg::Geode* geode = new osg::Geode();
geode->addDrawable(createParoramicSphericalDisplayDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), radius, collar, applyIntensityMapAsColours ? intensityMap : 0));
geode->addDrawable(createParoramicSphericalDisplayDistortionMesh(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(width,0.0f,0.0f), osg::Vec3(0.0f,height,0.0f), radius, collar, applyIntensityMapAsColours ? intensityMap : 0, projectorMatrix));
// new we need to add the texture to the mesh, we do so by creating a
// StateSet to contain the Texture StateAttribute.
@ -1406,14 +1342,14 @@ void View::setUpViewForPanoramicSphericalDisplay(double radius, double collar, u
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(gc.get());
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
camera->setClearColor( osg::Vec4(0.1,0.1,1.0,1.0) );
camera->setClearColor( osg::Vec4(0.0,0.0,0.0,1.0) );
camera->setViewport(new osg::Viewport(0, 0, width, height));
GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
camera->setDrawBuffer(buffer);
camera->setReadBuffer(buffer);
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
camera->setAllowEventFocus(false);
//camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE);
camera->setInheritanceMask(camera->getInheritanceMask() & ~osg::CullSettings::CLEAR_COLOR & ~osg::CullSettings::COMPUTE_NEAR_FAR_MODE);
//camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
camera->setProjectionMatrixAsOrtho2D(0,width,0,height);