Add seamless view muliscreen configuration.
Add a new way to configure multi screen systems. The new version allows easier configuration of displays that need to fit at the edges as well as configurations where the screens match at reference points. This kind of screen configuration will again zoom.
This commit is contained in:
parent
ad660380c2
commit
fea00cc9f8
3 changed files with 482 additions and 8 deletions
|
@ -81,6 +81,31 @@ window, camera, or gui tags.
|
||||||
width, height - int
|
width, height - int
|
||||||
The dimensions of the viewport
|
The dimensions of the viewport
|
||||||
|
|
||||||
|
physical-dimensions
|
||||||
|
The physical dimension of the projection surface.
|
||||||
|
Use this together with the master-perspective, right-of-perspective
|
||||||
|
left-of-perspective, above-perspective, below-perspective or
|
||||||
|
reference-points-perspective
|
||||||
|
|
||||||
|
width, height - double
|
||||||
|
The dimensions of the projection plane, if unset the veiwport values
|
||||||
|
are taken as default.
|
||||||
|
|
||||||
|
bezel
|
||||||
|
Gives informantion about the bezel of monitors for a seamless view.
|
||||||
|
|
||||||
|
right
|
||||||
|
right bezel with in the same units than with and height above
|
||||||
|
|
||||||
|
left
|
||||||
|
left bezel with in the same units than with and height above
|
||||||
|
|
||||||
|
top
|
||||||
|
top bezel with in the same units than with and height above
|
||||||
|
|
||||||
|
bottom
|
||||||
|
bottom bezel with in the same units than with and height above
|
||||||
|
|
||||||
view
|
view
|
||||||
The view node specifies the origin and direction of the camera in
|
The view node specifies the origin and direction of the camera in
|
||||||
relation to the whole camera group. The coordinate system is +y up,
|
relation to the whole camera group. The coordinate system is +y up,
|
||||||
|
@ -133,6 +158,63 @@ window, camera, or gui tags.
|
||||||
This specifies an orthographic view. The parameters are the sames as
|
This specifies an orthographic view. The parameters are the sames as
|
||||||
the frustum node's.
|
the frustum node's.
|
||||||
|
|
||||||
|
master-perspective
|
||||||
|
Defines a persective projection matrix for use as the leading display
|
||||||
|
in a seamless multiscreen configuration. This kind of perspective
|
||||||
|
projection is zoomable.
|
||||||
|
|
||||||
|
eye-distance - double
|
||||||
|
The distance of the eyepoint from the projection surface in units of
|
||||||
|
the physical-dimensions values above.
|
||||||
|
|
||||||
|
x-offset, y-offset - double
|
||||||
|
Offset of the eyelpint from the center of the screen in units of
|
||||||
|
the physical-dimensions values above.
|
||||||
|
|
||||||
|
left-of-perspective, right-of-perspective, above-perspective,
|
||||||
|
below-perspective
|
||||||
|
Defines a perspective projection matrix for use as derived display
|
||||||
|
in a seamless multiscreen configuration. The projection matrix
|
||||||
|
is computed so that the respective edge of this display matches the
|
||||||
|
assiciated other edge of the other display. For example the right edge
|
||||||
|
of a left-of-perspective display matches the left edge of the parent
|
||||||
|
display. This also works with different zoom levels, leading to distorted
|
||||||
|
but still seamless multiview configurations.
|
||||||
|
The bezel with configured in the physical dimensions of this screen and
|
||||||
|
the parent screen are taken into account for this type of projection.
|
||||||
|
|
||||||
|
parent-camera - string
|
||||||
|
Name of the parent camera.
|
||||||
|
|
||||||
|
reference-points-perspective
|
||||||
|
Defines a perspective projection matrix for use as derived display
|
||||||
|
in a seamless multiscreen configuration. This type is very similar to
|
||||||
|
left-of-perspective and friends. It is just a more flexible but less
|
||||||
|
convenient way to get the same effect. A child display is configured
|
||||||
|
by 2 sets of reference points one in this current camera and one in
|
||||||
|
the parrent camera which should match in the final view.
|
||||||
|
|
||||||
|
parent-camera - string
|
||||||
|
Name of the parent camera.
|
||||||
|
|
||||||
|
this
|
||||||
|
reference points for this projection.
|
||||||
|
|
||||||
|
point - array of two points
|
||||||
|
|
||||||
|
x, y - double
|
||||||
|
x and y coodinates of the reference points in units of this
|
||||||
|
physical-dimensions.
|
||||||
|
|
||||||
|
parent
|
||||||
|
reference points for the parent projection.
|
||||||
|
|
||||||
|
point - array of two points
|
||||||
|
|
||||||
|
x, y - double
|
||||||
|
x and y coodinates of the reference points in units of the
|
||||||
|
parents physical-dimensions.
|
||||||
|
|
||||||
texture
|
texture
|
||||||
This tag indicates that the camera renders to a texture instead of the
|
This tag indicates that the camera renders to a texture instead of the
|
||||||
framebuffer. For now the following tags are supported, but obviously
|
framebuffer. For now the following tags are supported, but obviously
|
||||||
|
@ -395,3 +477,170 @@ This example renders the scene for projection onto a spherical screen.
|
||||||
</sim>
|
</sim>
|
||||||
</PropertyList>
|
</PropertyList>
|
||||||
|
|
||||||
|
Here is an example for a 3 screen seamless zoomable multiscreen
|
||||||
|
configuration using 3 533mmx300mm displays each with a 23mm bezel.
|
||||||
|
The side views are angled with 45 deg.
|
||||||
|
The commented out reference-points-perspective shows the
|
||||||
|
aequivalent configuration than the active right-of-perspective.
|
||||||
|
This is done by just using two reference points at the outer
|
||||||
|
edge of the bezel of the respective display.
|
||||||
|
|
||||||
|
<PropertyList>
|
||||||
|
<sim>
|
||||||
|
<view n="0">
|
||||||
|
<config>
|
||||||
|
<pitch-offset-deg>0.0</pitch-offset-deg>
|
||||||
|
</config>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<rendering>
|
||||||
|
<camera-group>
|
||||||
|
<window>
|
||||||
|
<name type="string">0.0</name>
|
||||||
|
<host-name type="string"></host-name>
|
||||||
|
<display>0</display>
|
||||||
|
<screen>0</screen>
|
||||||
|
<fullscreen type="bool">true</fullscreen>
|
||||||
|
</window>
|
||||||
|
|
||||||
|
<window>
|
||||||
|
<name type="string">0.1</name>
|
||||||
|
<host-name type="string"></host-name>
|
||||||
|
<display>0</display>
|
||||||
|
<screen>1</screen>
|
||||||
|
<fullscreen type="bool">true</fullscreen>
|
||||||
|
</window>
|
||||||
|
|
||||||
|
<camera>
|
||||||
|
<name type="string">CenterCamera</name>
|
||||||
|
<window>
|
||||||
|
<name>0.0</name>
|
||||||
|
</window>
|
||||||
|
<viewport>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1920</width>
|
||||||
|
<height>1080</height>
|
||||||
|
</viewport>
|
||||||
|
<view>
|
||||||
|
<heading-deg type="double">0.0</heading-deg>
|
||||||
|
<roll-deg type="double">0.0</roll-deg>
|
||||||
|
<pitch-deg type="double">0.0</pitch-deg>
|
||||||
|
</view>
|
||||||
|
<physical-dimensions>
|
||||||
|
<!-- The size of the projection plane: 533mm 300mm -->
|
||||||
|
<width>533</width>
|
||||||
|
<height>300</height>
|
||||||
|
<bezel>
|
||||||
|
<right>23</right>
|
||||||
|
<left>23</left>
|
||||||
|
<top>23</top>
|
||||||
|
<bottom>23</bottom>
|
||||||
|
</bezel>
|
||||||
|
</physical-dimensions>
|
||||||
|
<master-perspective>
|
||||||
|
<!-- Cheating, the real distance is about 800mm.
|
||||||
|
But then the screen does not show what is needed to fly.
|
||||||
|
By shortening this pictures get bigger but the view also gets
|
||||||
|
less realistic.
|
||||||
|
-->
|
||||||
|
<eye-distance>450</eye-distance>
|
||||||
|
<x-offset>0</x-offset>
|
||||||
|
<y-offset>130</y-offset>
|
||||||
|
</master-perspective>
|
||||||
|
</camera>
|
||||||
|
<camera>
|
||||||
|
<name type="string">RightCamera</name>
|
||||||
|
<window>
|
||||||
|
<name>0.0</name>
|
||||||
|
</window>
|
||||||
|
<viewport>
|
||||||
|
<x>1920</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1920</width>
|
||||||
|
<height>1080</height>
|
||||||
|
</viewport>
|
||||||
|
<view>
|
||||||
|
<heading-deg type="double">-45</heading-deg>
|
||||||
|
<roll-deg type="double">0</roll-deg>
|
||||||
|
<pitch-deg type="double">0</pitch-deg>
|
||||||
|
</view>
|
||||||
|
<physical-dimensions>
|
||||||
|
<!-- The size of the projection plane: 533mm 300mm -->
|
||||||
|
<width>533</width>
|
||||||
|
<height>300</height>
|
||||||
|
<bezel>
|
||||||
|
<right>23</right>
|
||||||
|
<left>23</left>
|
||||||
|
<top>23</top>
|
||||||
|
<bottom>23</bottom>
|
||||||
|
</bezel>
|
||||||
|
</physical-dimensions>
|
||||||
|
<right-of-perspective>
|
||||||
|
<parent-camera type="string">CenterCamera</parent-camera>
|
||||||
|
</right-of-perspective>
|
||||||
|
<!-- <reference-points-perspective> -->
|
||||||
|
<!-- <parent-camera type="string">CenterCamera</parent-camera> -->
|
||||||
|
<!-- <parent> -->
|
||||||
|
<!-- <point n="0"> -->
|
||||||
|
<!-- <x>289.5</x> -->
|
||||||
|
<!-- <y>100</y> -->
|
||||||
|
<!-- </point> -->
|
||||||
|
<!-- <point n="1"> -->
|
||||||
|
<!-- <x>289.5</x> -->
|
||||||
|
<!-- <y>-100</y> -->
|
||||||
|
<!-- </point> -->
|
||||||
|
<!-- </parent> -->
|
||||||
|
<!-- <this> -->
|
||||||
|
<!-- <point n="0"> -->
|
||||||
|
<!-- <x>-289.5</x> -->
|
||||||
|
<!-- <y>100</y> -->
|
||||||
|
<!-- </point> -->
|
||||||
|
<!-- <point n="1"> -->
|
||||||
|
<!-- <x>-289.5</x> -->
|
||||||
|
<!-- <y>-100</y> -->
|
||||||
|
<!-- </point> -->
|
||||||
|
<!-- </this> -->
|
||||||
|
<!-- </reference-points-perspective> -->
|
||||||
|
</camera>
|
||||||
|
|
||||||
|
<camera>
|
||||||
|
<name type="string">LeftCamera</name>
|
||||||
|
<window>
|
||||||
|
<name>0.1</name>
|
||||||
|
</window>
|
||||||
|
<viewport>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1920</width>
|
||||||
|
<height>1080</height>
|
||||||
|
</viewport>
|
||||||
|
<view>
|
||||||
|
<heading-deg type="double">45</heading-deg>
|
||||||
|
<roll-deg type="double">0</roll-deg>
|
||||||
|
<pitch-deg type="double">0</pitch-deg>
|
||||||
|
</view>
|
||||||
|
<physical-dimensions>
|
||||||
|
<!-- The size of the projection plane: 533mm 300mm -->
|
||||||
|
<width>533</width>
|
||||||
|
<height>300</height>
|
||||||
|
<bezel>
|
||||||
|
<right>23</right>
|
||||||
|
<left>23</left>
|
||||||
|
<top>23</top>
|
||||||
|
<bottom>23</bottom>
|
||||||
|
</bezel>
|
||||||
|
</physical-dimensions>
|
||||||
|
<left-of-perspective>
|
||||||
|
<parent-camera type="string">CenterCamera</parent-camera>
|
||||||
|
</left-of-perspective>
|
||||||
|
</camera>
|
||||||
|
<gui>
|
||||||
|
<window>
|
||||||
|
<name type="string">0.0</name>
|
||||||
|
</window>
|
||||||
|
</gui>
|
||||||
|
</camera-group>
|
||||||
|
</rendering>
|
||||||
|
</sim>
|
||||||
|
</PropertyList>
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "CameraGroup.hxx"
|
#include "CameraGroup.hxx"
|
||||||
|
|
||||||
|
#include "fg_props.hxx"
|
||||||
#include "globals.hxx"
|
#include "globals.hxx"
|
||||||
#include "renderer.hxx"
|
#include "renderer.hxx"
|
||||||
#include "FGEventHandler.hxx"
|
#include "FGEventHandler.hxx"
|
||||||
|
@ -54,6 +55,71 @@
|
||||||
#include <osgViewer/GraphicsWindow>
|
#include <osgViewer/GraphicsWindow>
|
||||||
#include <osgViewer/Renderer>
|
#include <osgViewer/Renderer>
|
||||||
|
|
||||||
|
static osg::Matrix
|
||||||
|
invert(const osg::Matrix& matrix)
|
||||||
|
{
|
||||||
|
return osg::Matrix::inverse(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the zoom factor of the master camera.
|
||||||
|
/// The reference fov is the historic 55 deg
|
||||||
|
static double
|
||||||
|
zoomFactor()
|
||||||
|
{
|
||||||
|
double fov = fgGetDouble("/sim/current-view/field-of-view", 55);
|
||||||
|
if (fov < 1)
|
||||||
|
fov = 1;
|
||||||
|
return tan(55*0.5*SG_DEGREES_TO_RADIANS)/tan(fov*0.5*SG_DEGREES_TO_RADIANS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static osg::Vec2d
|
||||||
|
preMult(const osg::Vec2d& v, const osg::Matrix& m)
|
||||||
|
{
|
||||||
|
osg::Vec3d tmp = m.preMult(osg::Vec3(v, 0));
|
||||||
|
return osg::Vec2d(tmp[0], tmp[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static osg::Matrix
|
||||||
|
relativeProjection(const osg::Matrix& P0, const osg::Matrix& R, const osg::Vec2d ref[2],
|
||||||
|
const osg::Matrix& pP, const osg::Matrix& pR, const osg::Vec2d pRef[2])
|
||||||
|
{
|
||||||
|
// Track the way from one projection space to the other:
|
||||||
|
// We want
|
||||||
|
// P = T*S*P0
|
||||||
|
// where P0 is the projection template sensible for the given window size,
|
||||||
|
// T is a translation matrix and S a scale matrix.
|
||||||
|
// We need to determine T and S so that the reference points in the parents
|
||||||
|
// projection space match the two reference points in this cameras projection space.
|
||||||
|
|
||||||
|
// Starting from the parents camera projection space, we get into this cameras
|
||||||
|
// projection space by the transform matrix:
|
||||||
|
// P*R*inv(pP*pR) = T*S*P0*R*inv(pP*pR)
|
||||||
|
// So, at first compute that matrix without T*S and determine S and T from that
|
||||||
|
|
||||||
|
// Ok, now osg uses the inverse matrix multiplication order, thus:
|
||||||
|
osg::Matrix PtoPwithoutTS = invert(pR*pP)*R*P0;
|
||||||
|
// Compute the parents reference points in the current projection space
|
||||||
|
// without the yet unknown T and S
|
||||||
|
osg::Vec2d pRefInThis[2] = {
|
||||||
|
preMult(pRef[0], PtoPwithoutTS),
|
||||||
|
preMult(pRef[1], PtoPwithoutTS)
|
||||||
|
};
|
||||||
|
|
||||||
|
// To get the same zoom, rescale to match the parents size
|
||||||
|
double s = (ref[0] - ref[1]).length()/(pRefInThis[0] - pRefInThis[1]).length();
|
||||||
|
osg::Matrix S = osg::Matrix::scale(s, s, 1);
|
||||||
|
|
||||||
|
// For the translation offset, incorporate the now known scale
|
||||||
|
// and recompute the position ot the first reference point in the
|
||||||
|
// currents projection space without the yet unknown T.
|
||||||
|
pRefInThis[0] = preMult(pRef[0], PtoPwithoutTS*S);
|
||||||
|
// The translation is then the difference of the reference points
|
||||||
|
osg::Matrix T = osg::Matrix::translate(osg::Vec3d(ref[0] - pRefInThis[0], 0));
|
||||||
|
|
||||||
|
// Compose and return the desired final projection matrix
|
||||||
|
return P0*S*T;
|
||||||
|
}
|
||||||
|
|
||||||
namespace flightgear
|
namespace flightgear
|
||||||
{
|
{
|
||||||
using namespace osg;
|
using namespace osg;
|
||||||
|
@ -205,6 +271,7 @@ void CameraGroup::update(const osg::Vec3d& position,
|
||||||
* osg::Matrix::rotate(orientation.inverse()));
|
* osg::Matrix::rotate(orientation.inverse()));
|
||||||
_viewer->getCamera()->setViewMatrix(masterView);
|
_viewer->getCamera()->setViewMatrix(masterView);
|
||||||
const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
|
const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
|
||||||
|
double masterZoomFactor = zoomFactor();
|
||||||
for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
|
for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
|
||||||
const CameraInfo* info = i->get();
|
const CameraInfo* info = i->get();
|
||||||
const View::Slave& slave = _viewer->getSlave(info->slaveIndex);
|
const View::Slave& slave = _viewer->getSlave(info->slaveIndex);
|
||||||
|
@ -220,10 +287,33 @@ void CameraGroup::update(const osg::Vec3d& position,
|
||||||
viewMatrix = masterView * slave._viewOffset;
|
viewMatrix = masterView * slave._viewOffset;
|
||||||
camera->setViewMatrix(viewMatrix);
|
camera->setViewMatrix(viewMatrix);
|
||||||
Matrix projectionMatrix;
|
Matrix projectionMatrix;
|
||||||
if ((info->flags & PROJECTION_ABSOLUTE) != 0)
|
if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
|
||||||
|
if (info->flags & ENABLE_MASTER_ZOOM) {
|
||||||
|
if (info->relativeCameraParent < _cameras.size()) {
|
||||||
|
// template projection matrix and view matrix of the current camera
|
||||||
|
osg::Matrix P0 = slave._projectionOffset;
|
||||||
|
osg::Matrix R = viewMatrix;
|
||||||
|
|
||||||
|
// The already known projection and view matrix of the parent camera
|
||||||
|
const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
|
||||||
|
osg::Matrix pP = parentInfo->camera->getProjectionMatrix();
|
||||||
|
osg::Matrix pR = parentInfo->camera->getViewMatrix();
|
||||||
|
|
||||||
|
// And the projection matrix derived from P0 so that the reference points match
|
||||||
|
projectionMatrix = relativeProjection(P0, R, info->thisReference,
|
||||||
|
pP, pR, info->parentReference);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We want to zoom, so take the original matrix and apply the zoom to it.
|
||||||
projectionMatrix = slave._projectionOffset;
|
projectionMatrix = slave._projectionOffset;
|
||||||
else
|
projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
projectionMatrix = slave._projectionOffset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
projectionMatrix = masterProj * slave._projectionOffset;
|
projectionMatrix = masterProj * slave._projectionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
if (!info->farCamera.valid()) {
|
if (!info->farCamera.valid()) {
|
||||||
camera->setProjectionMatrix(projectionMatrix);
|
camera->setProjectionMatrix(projectionMatrix);
|
||||||
|
@ -575,7 +665,6 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
||||||
#endif
|
#endif
|
||||||
));
|
));
|
||||||
|
|
||||||
osg::Matrix pOff;
|
|
||||||
osg::Matrix vOff;
|
osg::Matrix vOff;
|
||||||
const SGPropertyNode* viewNode = cameraNode->getNode("view");
|
const SGPropertyNode* viewNode = cameraNode->getNode("view");
|
||||||
if (viewNode) {
|
if (viewNode) {
|
||||||
|
@ -601,7 +690,31 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
||||||
double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
|
double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
|
||||||
vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
|
vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
|
||||||
}
|
}
|
||||||
const SGPropertyNode* projectionNode = 0;
|
// Configuring the physical dimensions of a monitor
|
||||||
|
SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
|
||||||
|
double physicalWidth = viewportNode->getDoubleValue("width", 1024);
|
||||||
|
double physicalHeight = viewportNode->getDoubleValue("height", 768);
|
||||||
|
double bezelHeightTop = 0;
|
||||||
|
double bezelHeightBottom = 0;
|
||||||
|
double bezelWidthLeft = 0;
|
||||||
|
double bezelWidthRight = 0;
|
||||||
|
const SGPropertyNode* physicalDimensionsNode = 0;
|
||||||
|
if ((physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) != 0) {
|
||||||
|
physicalWidth = physicalDimensionsNode->getDoubleValue("width", physicalWidth);
|
||||||
|
physicalHeight = physicalDimensionsNode->getDoubleValue("height", physicalHeight);
|
||||||
|
const SGPropertyNode* bezelNode = 0;
|
||||||
|
if ((bezelNode = physicalDimensionsNode->getNode("bezel")) != 0) {
|
||||||
|
bezelHeightTop = bezelNode->getDoubleValue("top", bezelHeightTop);
|
||||||
|
bezelHeightBottom = bezelNode->getDoubleValue("bottom", bezelHeightBottom);
|
||||||
|
bezelWidthLeft = bezelNode->getDoubleValue("left", bezelWidthLeft);
|
||||||
|
bezelWidthRight = bezelNode->getDoubleValue("right", bezelWidthRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osg::Matrix pOff;
|
||||||
|
unsigned parentCameraIndex = ~0u;
|
||||||
|
osg::Vec2d parentReference[2];
|
||||||
|
osg::Vec2d thisReference[2];
|
||||||
|
SGPropertyNode* projectionNode = 0;
|
||||||
if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
|
if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
|
||||||
double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
|
double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
|
||||||
double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
|
double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
|
||||||
|
@ -636,6 +749,83 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
||||||
}
|
}
|
||||||
if (projectionNode->getBoolValue("fixed-near-far", true))
|
if (projectionNode->getBoolValue("fixed-near-far", true))
|
||||||
cameraFlags |= FIXED_NEAR_FAR;
|
cameraFlags |= FIXED_NEAR_FAR;
|
||||||
|
} else if ((projectionNode = cameraNode->getNode("master-perspective")) != 0) {
|
||||||
|
double zNear = projectionNode->getDoubleValue("eye-distance", 0.4*physicalWidth);
|
||||||
|
double xoff = projectionNode->getDoubleValue("x-offset", 0);
|
||||||
|
double yoff = projectionNode->getDoubleValue("y-offset", 0);
|
||||||
|
double left = -0.5*physicalWidth - xoff;
|
||||||
|
double right = 0.5*physicalWidth - xoff;
|
||||||
|
double bottom = -0.5*physicalHeight - yoff;
|
||||||
|
double top = 0.5*physicalHeight - yoff;
|
||||||
|
pOff.makeFrustum(left, right, bottom, top, zNear, zNear*1000);
|
||||||
|
cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
|
||||||
|
} else if ((projectionNode = cameraNode->getNode("right-of-perspective"))
|
||||||
|
|| (projectionNode = cameraNode->getNode("left-of-perspective"))
|
||||||
|
|| (projectionNode = cameraNode->getNode("above-perspective"))
|
||||||
|
|| (projectionNode = cameraNode->getNode("below-perspective"))
|
||||||
|
|| (projectionNode = cameraNode->getNode("reference-points-perspective"))) {
|
||||||
|
std::string name = projectionNode->getStringValue("parent-camera");
|
||||||
|
for (unsigned i = 0; i < _cameras.size(); ++i) {
|
||||||
|
if (_cameras[i]->name != name)
|
||||||
|
continue;
|
||||||
|
parentCameraIndex = i;
|
||||||
|
}
|
||||||
|
if (_cameras.size() <= parentCameraIndex) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "CameraGroup::buildCamera: "
|
||||||
|
"failed to find parent camera for relative camera!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const CameraInfo* parentInfo = _cameras[parentCameraIndex].get();
|
||||||
|
if (projectionNode->getNameString() == "right-of-perspective") {
|
||||||
|
double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthRight)/parentInfo->physicalWidth;
|
||||||
|
parentReference[0] = osg::Vec2d(tmp, -1);
|
||||||
|
parentReference[1] = osg::Vec2d(tmp, 1);
|
||||||
|
tmp = (physicalWidth + 2*bezelWidthLeft)/physicalWidth;
|
||||||
|
thisReference[0] = osg::Vec2d(-tmp, -1);
|
||||||
|
thisReference[1] = osg::Vec2d(-tmp, 1);
|
||||||
|
} else if (projectionNode->getNameString() == "left-of-perspective") {
|
||||||
|
double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthLeft)/parentInfo->physicalWidth;
|
||||||
|
parentReference[0] = osg::Vec2d(-tmp, -1);
|
||||||
|
parentReference[1] = osg::Vec2d(-tmp, 1);
|
||||||
|
tmp = (physicalWidth + 2*bezelWidthRight)/physicalWidth;
|
||||||
|
thisReference[0] = osg::Vec2d(tmp, -1);
|
||||||
|
thisReference[1] = osg::Vec2d(tmp, 1);
|
||||||
|
} else if (projectionNode->getNameString() == "above-perspective") {
|
||||||
|
double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightTop)/parentInfo->physicalHeight;
|
||||||
|
parentReference[0] = osg::Vec2d(-1, tmp);
|
||||||
|
parentReference[1] = osg::Vec2d(1, tmp);
|
||||||
|
tmp = (physicalHeight + 2*bezelHeightBottom)/physicalHeight;
|
||||||
|
thisReference[0] = osg::Vec2d(-1, -tmp);
|
||||||
|
thisReference[1] = osg::Vec2d(1, -tmp);
|
||||||
|
} else if (projectionNode->getNameString() == "below-perspective") {
|
||||||
|
double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightBottom)/parentInfo->physicalHeight;
|
||||||
|
parentReference[0] = osg::Vec2d(-1, -tmp);
|
||||||
|
parentReference[1] = osg::Vec2d(1, -tmp);
|
||||||
|
tmp = (physicalHeight + 2*bezelHeightTop)/physicalHeight;
|
||||||
|
thisReference[0] = osg::Vec2d(-1, tmp);
|
||||||
|
thisReference[1] = osg::Vec2d(1, tmp);
|
||||||
|
} else if (projectionNode->getNameString() == "reference-points-perspective") {
|
||||||
|
SGPropertyNode* parentNode = projectionNode->getNode("parent", true);
|
||||||
|
SGPropertyNode* thisNode = projectionNode->getNode("this", true);
|
||||||
|
SGPropertyNode* pointNode;
|
||||||
|
|
||||||
|
pointNode = parentNode->getNode("point", 0, true);
|
||||||
|
parentReference[0][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
|
||||||
|
parentReference[0][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
|
||||||
|
pointNode = parentNode->getNode("point", 1, true);
|
||||||
|
parentReference[1][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
|
||||||
|
parentReference[1][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
|
||||||
|
|
||||||
|
pointNode = thisNode->getNode("point", 0, true);
|
||||||
|
thisReference[0][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
|
||||||
|
thisReference[0][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
|
||||||
|
pointNode = thisNode->getNode("point", 1, true);
|
||||||
|
thisReference[1][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
|
||||||
|
thisReference[1][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
pOff = osg::Matrix::perspective(45, physicalWidth/physicalHeight, 1, 20000);
|
||||||
|
cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
|
||||||
} else {
|
} else {
|
||||||
// old style shear parameters
|
// old style shear parameters
|
||||||
double shearx = cameraNode->getDoubleValue("shear-x", 0);
|
double shearx = cameraNode->getDoubleValue("shear-x", 0);
|
||||||
|
@ -668,10 +858,21 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
|
||||||
bool useMasterSceneGraph = !psNode;
|
bool useMasterSceneGraph = !psNode;
|
||||||
CameraInfo* info = addCamera(cameraFlags, camera, vOff, pOff,
|
CameraInfo* info = addCamera(cameraFlags, camera, vOff, pOff,
|
||||||
useMasterSceneGraph);
|
useMasterSceneGraph);
|
||||||
|
info->name = cameraNode->getStringValue("name");
|
||||||
|
info->physicalWidth = physicalWidth;
|
||||||
|
info->physicalHeight = physicalHeight;
|
||||||
|
info->bezelHeightTop = bezelHeightTop;
|
||||||
|
info->bezelHeightBottom = bezelHeightBottom;
|
||||||
|
info->bezelWidthLeft = bezelWidthLeft;
|
||||||
|
info->bezelWidthRight = bezelWidthRight;
|
||||||
|
info->relativeCameraParent = parentCameraIndex;
|
||||||
|
info->parentReference[0] = parentReference[0];
|
||||||
|
info->parentReference[1] = parentReference[1];
|
||||||
|
info->thisReference[0] = thisReference[0];
|
||||||
|
info->thisReference[1] = thisReference[1];
|
||||||
// If a viewport isn't set on the camera, then it's hard to dig it
|
// 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
|
// out of the SceneView objects in the viewer, and the coordinates
|
||||||
// of mouse events are somewhat bizzare.
|
// of mouse events are somewhat bizzare.
|
||||||
SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
|
|
||||||
buildViewport(info, viewportNode, window->gc->getTraits());
|
buildViewport(info, viewportNode, window->gc->getTraits());
|
||||||
updateCameras(info);
|
updateCameras(info);
|
||||||
// Distortion camera needs the viewport which is created by addCamera().
|
// Distortion camera needs the viewport which is created by addCamera().
|
||||||
|
|
|
@ -52,9 +52,15 @@ struct CameraInfo : public osg::Referenced
|
||||||
{
|
{
|
||||||
CameraInfo(unsigned flags_, osg::Camera* camera_ = 0)
|
CameraInfo(unsigned flags_, osg::Camera* camera_ = 0)
|
||||||
: flags(flags_), camera(camera_), slaveIndex(-1), farSlaveIndex(-1),
|
: flags(flags_), camera(camera_), slaveIndex(-1), farSlaveIndex(-1),
|
||||||
x(0.0), y(0.0), width(0.0), height(0.0)
|
x(0.0), y(0.0), width(0.0), height(0.0),
|
||||||
|
physicalWidth(0), physicalHeight(0), bezelHeightTop(0),
|
||||||
|
bezelHeightBottom(0), bezelWidthLeft(0), bezelWidthRight(0),
|
||||||
|
relativeCameraParent(~0u)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
/** The name as given in the config file.
|
||||||
|
*/
|
||||||
|
std::string name;
|
||||||
/** Properties of the camera. @see CameraGroup::Flags.
|
/** Properties of the camera. @see CameraGroup::Flags.
|
||||||
*/
|
*/
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
|
@ -76,6 +82,23 @@ struct CameraInfo : public osg::Referenced
|
||||||
double y;
|
double y;
|
||||||
double width;
|
double width;
|
||||||
double height;
|
double height;
|
||||||
|
/** Physical size parameters.
|
||||||
|
*/
|
||||||
|
double physicalWidth;
|
||||||
|
double physicalHeight;
|
||||||
|
double bezelHeightTop;
|
||||||
|
double bezelHeightBottom;
|
||||||
|
double bezelWidthLeft;
|
||||||
|
double bezelWidthRight;
|
||||||
|
/** The parent camera for relative camera configurations.
|
||||||
|
*/
|
||||||
|
unsigned relativeCameraParent;
|
||||||
|
/** The reference points in the parents projection space.
|
||||||
|
*/
|
||||||
|
osg::Vec2d parentReference[2];
|
||||||
|
/** The reference points in the current projection space.
|
||||||
|
*/
|
||||||
|
osg::Vec2d thisReference[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Update the OSG cameras from the camera info.
|
/** Update the OSG cameras from the camera info.
|
||||||
|
@ -96,8 +119,9 @@ public:
|
||||||
GUI = 0x8, /**< Camera draws the GUI. */
|
GUI = 0x8, /**< Camera draws the GUI. */
|
||||||
DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
|
DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
|
||||||
camera. */
|
camera. */
|
||||||
FIXED_NEAR_FAR = 0x20 /**< take the near far values in the
|
FIXED_NEAR_FAR = 0x20, /**< take the near far values in the
|
||||||
projection for real. */
|
projection for real. */
|
||||||
|
ENABLE_MASTER_ZOOM = 0x40 /**< Can apply the zoom algorithm. */
|
||||||
};
|
};
|
||||||
/** Create a camera group associated with an osgViewer::Viewer.
|
/** Create a camera group associated with an osgViewer::Viewer.
|
||||||
* @param viewer the viewer
|
* @param viewer the viewer
|
||||||
|
|
Loading…
Reference in a new issue