*** empty log message ***

This commit is contained in:
Robert Osfield 2003-10-27 16:07:21 +00:00
parent bce184e87c
commit eb4ee3afad
16 changed files with 1306 additions and 424 deletions

View File

@ -128,6 +128,7 @@ EXAMPLE_DIRS = \
osgautotransform\
osgbillboard\
osgbluemarble\
osgdem\
osgcallback\
osgcameragroup\
osgclip\

View File

@ -1,306 +1,228 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.77 [en] (X11; U; Linux 2.4.3-20mdk i686) [Netscape]">
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta name="GENERATOR"
content="Mozilla/4.77 [en] (X11; U; Linux 2.4.3-20mdk i686) [Netscape]">
<title>Native stereo support</title>
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EE" vlink="#551A8B" alink="#FF0000">
<img SRC="images/OpenSceneGraphBanner_Distribution.jpg">
<body text="#000000" bgcolor="#ffffff" link="#0000ee" vlink="#551a8b"
alink="#ff0000">
<img src="images/OpenSceneGraphBanner_Distribution.jpg">
<table>
<tbody>
<tr>
<td><a href="index.html">Index</a></td>
<td><a href="introduction.html">Introduction</a></td>
<td><a href="contents.html">Contents</a></td>
<td><a href="install.html">Install</a></td>
<td><a href="dependencies.html">Dependencies</a></td>
<td><a href="examples.html">examples</a></td>
<td><a href="data.html">Data</a></td>
<td><a href="osgviewer.html">Viewer</a></td>
<td><a href="stereo.html">Stereo</a></td>
<td><a href="plan.html">Plan</a></td>
<td><a href="documentation.html">Reference Guides</a></td>
</tr>
</tbody>
</table>
<h2>
<u>Native Support for Stereo</u></h2>
The OSG has support for anaglyphic stereo (i.e. red/green or red/cyan glasses),
quad buffered stereo (i.e. active stereo using shutter glasses, or passive
stereo using polarized projectors &amp; glasses) and horizontal and vertical
split window stereo implementations. Almost all OSG applications have the
potential for stereo support simply by setting the relevant environmental
variables, or via command line arguments. Little or no code changes will
be required, the support is handled transparently inside osgUtil::SceneView's
handling of rendering. It is a simple as:
<br><b>&nbsp;&nbsp;&nbsp; osgviewer --stereo cow.osg</b>
<p>If the user is planning to use head tracked stereo, or a cave then it
is currently recommend to set it up via a VR toolkit such as VRjuggler,
in this case refer to the VR toolkits handling of stereo, and keep all
the OSG's stereo specific environment variables (below) set to OFF, or
set the values to off within own your own applications.
<br>
<h2> <u>Native Support for Stereo</u></h2>
The OSG has support for anaglyphic stereo (i.e. red/green or red/cyan
glasses), quad buffered stereo (i.e. active stereo using shutter
glasses, or passive stereo using polarized projectors &amp; glasses)
and horizontal and vertical split window stereo implementations. Almost
all OSG applications have the potential for stereo support simply by
setting the relevant environmental variables, or via command line
arguments. Little or no code changes will be required, the support is
handled transparently inside osgUtil::SceneView's handling of
rendering. It is a simple as: <br>
<b>&nbsp;&nbsp;&nbsp; osgviewer --stereo cow.osg</b>
<p>If the user is planning to use head tracked stereo, or a cave then
it is currently recommend to set it up via a VR toolkit such as
VRjuggler, in this case refer to the VR toolkits handling of stereo,
and keep all the OSG's stereo specific environment variables (below)
set to OFF, or set the values to off within own your own applications. <br>
</p>
<hr>
<h3>
The environmental variables of interest:</h3>
<h3> The environmental variables of interest:</h3>
<table>
<tbody>
<tr>
<td><b>OSG_STEREO</b></td>
<td><b>ON</b></td>
<td>Turn stereo on&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>OFF</b></td>
<td>Turn stereo off (default).&nbsp;</td>
</tr>
<tr>
<td><b>OSG_STEREO_MODE</b></td>
<td><b>ANAGLYPHIC</b></td>
<td>Use anaglyphic stereo when in stereo (default).&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>QUAD_BUFFER</b></td>
<td>Use quad buffered stereo when in stereo.&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>HORIZONTAL_SPLIT</b></td>
<td>Use horizontal split stereo mode when in stereo&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>VERTICAL_SPLIT</b></td>
<td>Use vertical split stereo mode when in stereo&nbsp;</td>
</tr>
<tr>
<td><b>OSG_SCREEN_DISTANCE</b></td>
<td><b>0.50</b></td>
<td>Set the distance the viewer is from screen in metres (default shown)&nbsp;</td>
<td>Set the distance the viewer is from screen in metres (default
shown)&nbsp;</td>
</tr>
<tr>
<td><b>OSG_SCREEN_HEIGHT</b></td>
<td><b>0.26</b></td>
<td>Set the height if image on the screen in metres (default shown)&nbsp;</td>
<td>Set the height if image on the screen in metres (default
shown)&nbsp;</td>
</tr>
<tr>
<td><b>OSG_EYE_SEPARATION</b></td>
<td><b>0.06</b></td>
<td>Set the eye separation - interoccular distance (default shown.)&nbsp;</td>
<td>Set the eye separation - interoccular distance (default
shown.)&nbsp;</td>
</tr>
<tr>
<td><b>OSG_SPLIT_STEREO_HORIZONTAL_SEPARATION</b></td>
<td><b>42</b></td>
<td>Set the number of pixels between the left and right viewports (default
shown).</td>
<td>Set the number of pixels between the left and right viewports
(default shown).</td>
</tr>
<tr>
<td><b>OSG_SPLIT_STEREO_HORIZONTAL_EYE_MAPPING</b></td>
<td><b>LEFT_EYE_LEFT_VIEWPORT</b></td>
<td>Set the left eye to render to left viewport, right eye to right viewport
(default).&nbsp;</td>
<td>Set the left eye to render to left viewport, right eye to
right viewport (default).&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>LEFT_EYE_RIGHT_VIEWPORT</b></td>
<td>Set the left eye to render to right viewport, right eye to left viewport.&nbsp;</td>
<td>Set the left eye to render to right viewport, right eye to
left viewport.&nbsp;</td>
</tr>
<tr>
<td><b>OSG_SPLIT_STEREO_VERTICAL_SEPARATION</b></td>
<td><b>42</b></td>
<td>Set the number of pixels between the top and bottom viewports (default
shown).</td>
<td>Set the number of pixels between the top and bottom viewports
(default shown).</td>
</tr>
<tr>
<td><b>OSG_SPLIT_STEREO_VERTICAL_EYE_MAPPING</b></td>
<td><b>LEFT_EYE_TOP_VIEWPORT</b></td>
<td>Set the left eye to render to top viewport, right eye to bottom viewport
(default).&nbsp;</td>
<td>Set the left eye to render to top viewport, right eye to
bottom viewport (default).&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>LEFT_EYE_BOTTOM_VIEWPORT</b></td>
<td>Set the left eye to render to bottom viewport, right eye to top viewport.&nbsp;</td>
<td>Set the left eye to render to bottom viewport, right eye to
top viewport.&nbsp;</td>
</tr>
</tbody>
</table>
<hr>
<h3>
Command line arguments can be used to override these settings:</h3>
<h3> Command line arguments can be used to override these settings:</h3>
<table>
<tbody>
<tr>
<td><b>-stereo</b></td>
<td></td>
<td><br>
</td>
<td>Switch on stereo.&nbsp;</td>
</tr>
<tr>
<td><b>-stereo</b></td>
<td><b>ON</b></td>
<td>Switch on stereo.&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>OFF</b></td>
<td>Switch off stereo.&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>ANAGLYPHIC</b></td>
<td>Switch on ANAGLYPHIC stereo.&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>QUAD_BUFFER</b></td>
<td>Switch on QUAD_BUFFER stereo.&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>VERTICAL_SPLIT</b></td>
<td>Switch on VERTICAL_SPLIT stereo.&nbsp;</td>
</tr>
<tr>
<td></td>
<td><br>
</td>
<td><b>HORIZONTAL_SPLIT</b></td>
<td>Switch on VERTICAL_SPLIT stereo.&nbsp;</td>
</tr>
</tbody>
</table>
<hr>
<h3>
Examples:</h3>
To invoke stereo from the comandline:
<br><b>&nbsp;&nbsp;&nbsp; osgviewer -stereo cow.osg</b>
<p>To invoke quad buffered stereo from the commandline:
<br><b>&nbsp;&nbsp;&nbsp; osgviewer -stereo QUAD_BUFFER cow.osg</b>
<p>To force all apps to start up in quad buffered stereo (if system supports
it)
<br><b>&nbsp;&nbsp;&nbsp; export OSG_STEREO=ON</b>
<br><b>&nbsp;&nbsp;&nbsp; export OSG_STEREO_MODE=QUAD_BUFFER</b>
<br><b>&nbsp;&nbsp;&nbsp; osgviewer cow.osg</b>
<h3> Examples:</h3>
To invoke stereo from the comandline: <br>
<b>&nbsp;&nbsp;&nbsp; osgviewer -stereo cow.osg</b>
<p>To invoke quad buffered stereo from the commandline: <br>
<b>&nbsp;&nbsp;&nbsp; osgviewer -stereo QUAD_BUFFER cow.osg</b> </p>
<p>To force all apps to start up in quad buffered stereo (if system
supports it) <br>
<b>&nbsp;&nbsp;&nbsp; export OSG_STEREO=ON</b> <br>
<b>&nbsp;&nbsp;&nbsp; export OSG_STEREO_MODE=QUAD_BUFFER</b> <br>
<b>&nbsp;&nbsp;&nbsp; osgviewer cow.osg</b> </p>
<p>To set quad buffered stereo to the default, but use the commandline
to switch stereo on:
<br><b>&nbsp;&nbsp;&nbsp; export OSG_STEREO=OFF</b>
<br><b>&nbsp;&nbsp;&nbsp; export OSG_STEREO_MODE=QUAD_BUFFER</b>
<br><b>&nbsp;&nbsp;&nbsp; osgviewer -stereo cow.osg</b>
<p>
to switch stereo on: <br>
<b>&nbsp;&nbsp;&nbsp; export OSG_STEREO=OFF</b> <br>
<b>&nbsp;&nbsp;&nbsp; export OSG_STEREO_MODE=QUAD_BUFFER</b> <br>
<b>&nbsp;&nbsp;&nbsp; osgviewer -stereo cow.osg</b> </p>
<p> </p>
<hr>
<h3>
Size matters:</h3>
<h3> Size matters:</h3>
For appropriate depth perception the stereo code creates separate left
and eye views, both the frustum and modelview are shifted to account for
the separate eye views.&nbsp; To achieve the right amount of adjustment
the OSG requires the users eye separation, the distance from the eyes to
the screen and the height of the screen.&nbsp; The OSG will use the defaults
of 0.05m,0.5m and 0.26m respectively which are assumed to be reasonable
defaults for most users workstation configurations, note the OSG_SCREEN_HEIGHT
is the image height rather than total size of your monitor/display surface.&nbsp;
For the best stereo effects please measure these values and set them up
via the environmental variables.&nbsp; Once set the views you get should
give improved depth perception.&nbsp; A good way of measuring how well
you are configured for your display is to fly away from objects (using
the FlightManipulator for instance, but not the TrackballManipulator, see
the screen and the height of the screen.&nbsp; The OSG will use the
defaults of 0.05m,0.5m and 0.26m respectively which are assumed to be
reasonable defaults for most users workstation configurations, note the
OSG_SCREEN_HEIGHT is the image height rather than total size of your
monitor/display surface.&nbsp; For the best stereo effects please
measure these values and set them up via the environmental
variables.&nbsp; Once set the views you get should give improved depth
perception.&nbsp; A good way of measuring how well you are configured
for your display is to fly away from objects (using the
FlightManipulator for instance, but not the TrackballManipulator, see
below) so that they go of toward infinity. As they move away the offset
between the two images should tend towards your eye separation, if you
achieve this then the object will be perceived as at infinity.
achieve this then the object will be perceived as at infinity. <br>
<br>
<hr>
<h3>
Camera Manipulator Modes:</h3>
There are three osgUtil::CameraManipulator's which come with osgUtil, which
operate as a Trackball, Drive and Flight modes of interaction (see osgviewer.html
for how to invoke them in the scene graph viewer). The osgUtil::Trackball
Manipulator automatically scales the fusion distance to that which will
fusion on center point of rotation - this will appear at the middle of
the monitor at the monitors depth. Whereas, the osgUtil::DriveManipualtor,
osgUtil::FlightManipulator scale the fusion distance to the distance the
viewer is from the screen, the results in a perception that the virtual
world is scaled to physical world, this is clearly better for simulators
and alike. You can control the fusion of the image in these two modes via
the osg::Camera::setFusionDistanceMode(FusionDistanceMode mode) where mode
can be osg::Camera::PROPORTIONAL_TO_LOOK_DISTANCE (used by Trackball) or
osg::Camera::PROPORTIONAL_TO_SCREEN_DISTANCE (used by Drive and Flight),
and osg::Camera::setFusionDistanceRatio(float). See include/osg/Camera
for further details, and the camera manipulators for implementation details.
The fusion distance ratio defaults to 1.0 but can be biased to move objects
out or into screen, they will also appear to get smaller and larger respectively.
The camera manipulators allow the user to alter this value at runtime via
the '+' and '-' keys.
</body>
</html>

View File

@ -69,10 +69,14 @@ osg::Node* createTile(const std::string& filename, bool leftHemisphere, double x
options->_destinationImageWindowMode = osgDB::ImageOptions::PIXEL_WINDOW;
options->_destinationPixelWindow.set(0,0,256,256);
osgDB::ImageOptions::TexCoordRange* texCoordRange = 0;
osgDB::Registry::instance()->setOptions(options.get());
osg::Image* image = osgDB::readImageFile(filename.c_str());
if (image)
{
texCoordRange = dynamic_cast<osgDB::ImageOptions::TexCoordRange*>(image->getUserData());
osg::Texture2D* texture = new osg::Texture2D;
texture->setImage(image);
texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP);
@ -82,6 +86,9 @@ osg::Node* createTile(const std::string& filename, bool leftHemisphere, double x
texture->setMaxAnisotropy(8);
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
bool useCompressedTextures = true;
if (useCompressedTextures)
{
texture->setInternalFormatMode(osg::Texture::USE_S3TC_DXT3_COMPRESSION);
osg::ref_ptr<osg::State> state = new osg::State;
@ -90,8 +97,7 @@ osg::Node* createTile(const std::string& filename, bool leftHemisphere, double x
image->readImageFromCurrentTexture();
texture->setInternalFormatMode(osg::Texture::USE_IMAGE_DATA_FORMAT);
std::cout<<"glGetError()=="<<glGetError()<<std::endl;
}
}
@ -114,9 +120,24 @@ osg::Node* createTile(const std::string& filename, bool leftHemisphere, double x
color[0].set(255,255,255,255);
osg::Vec2 tex_orig(0.0f,0.0f);
float rowTexDelta = 1.0f/(float)(numRows-1);
float columnTexDelta = 1.0f/(float)(numColumns-1);
if (texCoordRange)
{
tex_orig.set(texCoordRange->_x,texCoordRange->_y);
rowTexDelta = texCoordRange->_h/(float)(numRows-1);
columnTexDelta = texCoordRange->_w/(float)(numColumns-1);
std::cout<<"setting tex values to use texCoordRange"<<std::endl;
std::cout<<" tex_orig="<<tex_orig<<std::endl;
std::cout<<" rowTexDelta"<<rowTexDelta<<std::endl;
std::cout<<" columnTexDelta"<<columnTexDelta<<std::endl;
}
double orig_latitude = osg::PI*x;
double delta_latitude = osg::PI*w/(double)(numColumns-1);
@ -124,7 +145,7 @@ osg::Node* createTile(const std::string& filename, bool leftHemisphere, double x
double orig_longitude = osg::PI*y;
double delta_longitude = osg::PI*h/(double)(numRows-1);
osg::Vec2 tex(0.0f,0.0f);
osg::Vec2 tex(tex_orig);
int vi=0;
double longitude = orig_longitude;
osg::Vec3 normal;
@ -132,7 +153,7 @@ osg::Node* createTile(const std::string& filename, bool leftHemisphere, double x
{
double latitude = orig_latitude;
tex.x() = 0.0f;
tex.x() = tex_orig.x();
for(c=0;c<numColumns;++c)
{
double sin_longitude = sin(longitude);
@ -302,7 +323,9 @@ bool createWorld(const std::string& left_hemisphere, const std::string& right_he
// create the world
std::string base = osgDB::getFilePath(baseName)+'/'+osgDB::getStrippedName(baseName);
std::string path = osgDB::getFilePath(baseName);
std::string base = path.empty()?osgDB::getStrippedName(baseName):
path +'/'+ osgDB::getStrippedName(baseName);
std::string extension = '.'+osgDB::getLowerCaseFileExtension(baseName);
std::cout << "baseName = "<<baseName<<std::endl;
@ -337,8 +360,19 @@ int main( int argc, char **argv )
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
arguments.getApplicationUsage()->addCommandLineOption("-i <filename>","Specify the input file to process");
arguments.getApplicationUsage()->addCommandLineOption("-o <outputfile>","Specify the output master file to generate");
arguments.getApplicationUsage()->addCommandLineOption("-l <numOfLevels>","Specify the number of PagedLOD levels to generate");
arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
std::string inputFile;
while (arguments.read("-i",inputFile)) {}
std::string basename("output.ive");
while (arguments.read("-o",basename)) {}
float numLevels;
while (arguments.read("-l",numLevels)) {}
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
@ -365,7 +399,6 @@ int main( int argc, char **argv )
std::string left_hemisphere("land_shallow_topo_west.tif");
std::string right_hemisphere("land_shallow_topo_east.tif");
std::string basename("BlueMarble/bluemarble.ive");
// create a graphics context to allow us to use OpenGL to compress textures.
GraphicsContext gfx;

View File

@ -0,0 +1,18 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
osgdem.cpp\
LIBS += -losgProducer -lProducer -losgFX -losgText -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
INSTFILES = \
$(CXXFILES)\
GNUmakefile.inst=GNUmakefile
EXEC = osgdem
INC += $(X_INC)
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,13 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
osgdem.cpp\
LIBS += -losgProducer -lProducer -losgDB -losgText -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS)
EXEC = osgdem
INC += $(X_INC)
include $(TOPDIR)/Make/makerules

883
examples/osgdem/osgdem.cpp Normal file
View File

@ -0,0 +1,883 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial applications,
* as long as this copyright notice is maintained.
*
* This application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <osg/Texture2D>
#include <osg/Geometry>
#include <osg/State>
#include <osg/ShapeDrawable>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/ImageOptions>
#include <osgDB/FileNameUtils>
#include <osgUtil/Optimizer>
#include <osgUtil/TriStripVisitor>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/TangentSpaceGenerator>
#include <osgFX/BumpMapping>
#include <osgProducer/Viewer>
float VERTICAL_SIZE = 0.0005;
class GraphicsContext {
public:
GraphicsContext()
{
rs = new Producer::RenderSurface;
rs->setWindowRectangle(0,0,1,1);
rs->useBorder(false);
rs->useConfigEventThread(false);
rs->realize();
std::cout<<"Realized window"<<std::endl;
}
virtual ~GraphicsContext()
{
}
private:
Producer::ref_ptr<Producer::RenderSurface> rs;
};
osg::Image* createNormalMap(osg::HeightField* grid)
{
osg::Image* image = new osg::Image;
image->allocateImage(grid->getNumColumns(),grid->getNumRows(),1,GL_RGB,GL_BYTE);
char* ptr = (char*) image->data();
for(unsigned int r=0;r<grid->getNumRows();++r)
{
for(unsigned int c=0;c<grid->getNumColumns();++c)
{
osg::Vec3 normal = grid->getNormal(c,r);
(*ptr++) = (char)((normal.x()+1.0)*0.5*255);
(*ptr++) = (char)((normal.y()+1.0)*0.5*255);
(*ptr++) = (char)((normal.z()+1.0)*0.5*255);
}
}
return image;
}
template< typename T>
osg::HeightField* _createHeightField(osg::Image* image, float zScale)
{
unsigned char* ptr = image->data();
unsigned int rowSizeInBytes = image->getRowSizeInBytes();
unsigned int pixelSizeInBits = image->getPixelSizeInBits();
unsigned int pixelSizeInBytes = pixelSizeInBits/8;
unsigned int numColumns = image->s();
unsigned int numRows = image->t();
osg::HeightField* grid = new osg::HeightField;
grid->allocateGrid(numColumns,numRows);
for(unsigned int r=0;r<numRows;++r)
{
unsigned char* ptr_in_row = ptr;
for(unsigned int c=0;c<numColumns;++c)
{
grid->setHeight(c,r,zScale*(float)(*((T*)ptr_in_row)));
ptr_in_row += pixelSizeInBytes;
}
ptr += rowSizeInBytes;
}
return grid;
}
osg::HeightField* createHeightField(osg::Image* image, const osg::Vec3& origin, const osg::Vec3& size)
{
osg::HeightField* grid = new osg::HeightField;
switch(image->getDataType())
{
case(GL_UNSIGNED_BYTE): grid = _createHeightField<unsigned char>(image,size.z()); break;
case(GL_BYTE): grid = _createHeightField<char>(image,size.z()); break;
case(GL_UNSIGNED_SHORT): grid = _createHeightField<unsigned short>(image,size.z()); break;
case(GL_SHORT): grid = _createHeightField<short>(image,size.z()); break;
case(GL_UNSIGNED_INT): grid = _createHeightField<unsigned int>(image,size.z()); break;
case(GL_INT): grid = _createHeightField<int>(image,size.z()); break;
case(GL_FLOAT): grid = _createHeightField<float>(image,size.z()); break;
}
grid->setOrigin(origin);
grid->setXInterval(size.x()/(float)(image->s()-1));
grid->setYInterval(size.y()/(float)(image->s()-1));
return grid;
}
osg::Node* createTile(osg::HeightField* grid,
unsigned int columnBegin, unsigned int columnEnd,
unsigned int rowBegin, unsigned int rowEnd,
float xTexCoordBegin, float xTexCoordEnd,
float yTexCoordBegin, float yTexCoordEnd,
unsigned int targetNumPolygonsPerTile)
{
int numPolys = (columnEnd-columnBegin)*(rowEnd-rowBegin)*2;
int numColumns, numRows;
bool oneToOneMapping = numPolys<=targetNumPolygonsPerTile;
if (oneToOneMapping)
{
numColumns = (columnEnd-columnBegin)+1;
numRows = (rowEnd-rowBegin)+1;
}
else
{
numColumns = (int)sqrtf((float)targetNumPolygonsPerTile/2.0) + 1;
numRows = targetNumPolygonsPerTile/(2*(numColumns)-1) + 1;
}
bool createSkirt = true;
int numVerticesInBody = numColumns*numRows;
int numVerticesInSkirt = createSkirt ? numColumns*2 + numRows*2 - 4 : 0;
int numVertices = numVerticesInBody+numVerticesInSkirt;
osg::Vec3 skirtVector(0.0f,0.0f,-0.003f);
osg::Geometry* geometry = new osg::Geometry;
osg::Vec3Array& v = *(new osg::Vec3Array(numVertices));
osg::Vec2Array& t = *(new osg::Vec2Array(numVertices));
osg::UByte4Array& color = *(new osg::UByte4Array(1));
color[0].set(255,255,255,255);
int vi=0;
int r,c;
if (!oneToOneMapping)
{
for(r=0;r<numRows;++r)
{
unsigned int row = rowBegin + (unsigned int)((float)(rowEnd-rowBegin) * ((float)r/(float)(numRows-1)));
for(c=0;c<numColumns;++c)
{
unsigned int col = columnBegin + (unsigned int)((float)(columnEnd-columnBegin) * ((float)c/(float)(numColumns-1)));
v[vi] = grid->getOrigin()+osg::Vec3(grid->getXInterval()*(float)col,
grid->getYInterval()*(float)row,
grid->getHeight(col,row));
t[vi].x() = xTexCoordBegin + (xTexCoordEnd-xTexCoordBegin)*(float)(col-columnBegin)/(float)(columnEnd-columnBegin);
t[vi].y() = yTexCoordBegin + (yTexCoordEnd-yTexCoordBegin)*(float)(row-rowBegin)/(float)(rowEnd-rowBegin);
++vi;
}
}
}
else
{
for(r=rowBegin;r<=rowEnd;++r)
{
for(c=columnBegin;c<=columnEnd;++c)
{
v[vi] = grid->getOrigin()+osg::Vec3(grid->getXInterval()*c,
grid->getYInterval()*r,
grid->getHeight(c,r));
t[vi].x() = xTexCoordBegin + (xTexCoordEnd-xTexCoordBegin)*(float)(c-columnBegin)/(float)(columnEnd-columnBegin);
t[vi].y() = yTexCoordBegin + (yTexCoordEnd-yTexCoordBegin)*(float)(r-rowBegin)/(float)(rowEnd-rowBegin);
++vi;
}
}
}
geometry->setVertexArray(&v);
geometry->setColorArray(&color);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
geometry->setTexCoordArray(0,&t);
geometry->setTexCoordArray(1,&t);
bool pickOutDiagonals = true;
if (pickOutDiagonals)
{
osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_TRIANGLES,2*3*(numColumns-1)*(numRows-1)));
geometry->addPrimitiveSet(&drawElements);
int ei=0;
for(r=0;r<numRows-1;++r)
{
for(c=0;c<numColumns-1;++c)
{
unsigned short i00 = (r)*numColumns+c;
unsigned short i10 = (r)*numColumns+c+1;
unsigned short i01 = (r+1)*numColumns+c;
unsigned short i11 = (r+1)*numColumns+c+1;
float diff_00_11 = fabsf(v[i00].z()-v[i11].z());
float diff_01_10 = fabsf(v[i01].z()-v[i10].z());
if (diff_00_11<diff_01_10)
{
// diagonal between 00 and 11
drawElements[ei++] = i00;
drawElements[ei++] = i10;
drawElements[ei++] = i11;
drawElements[ei++] = i00;
drawElements[ei++] = i11;
drawElements[ei++] = i01;
}
else
{
// diagonal between 01 and 10
drawElements[ei++] = i01;
drawElements[ei++] = i00;
drawElements[ei++] = i10;
drawElements[ei++] = i01;
drawElements[ei++] = i10;
drawElements[ei++] = i11;
}
}
}
}
else
{
for(r=0;r<numRows-1;++r)
{
osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
geometry->addPrimitiveSet(&drawElements);
int ei=0;
for(c=0;c<numColumns;++c)
{
drawElements[ei++] = (r+1)*numColumns+c;
drawElements[ei++] = (r)*numColumns+c;
}
}
}
if (numVerticesInSkirt>0)
{
osg::DrawElementsUShort& skirtDrawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numVerticesInSkirt+2));
geometry->addPrimitiveSet(&skirtDrawElements);
int ei=0;
int firstSkirtVertexIndex = vi;
// create bottom skirt vertices
r=0;
for(c=0;c<numColumns-1;++c)
{
skirtDrawElements[ei++] = (r)*numColumns+c;
skirtDrawElements[ei++] = vi;
v[vi] = v[(r)*numColumns+c]+skirtVector;
t[vi++] = t[(r)*numColumns+c];
}
// create right skirt vertices
c=numColumns-1;
for(r=0;r<numRows-1;++r)
{
skirtDrawElements[ei++] = (r)*numColumns+c;
skirtDrawElements[ei++] = vi;
v[vi] = v[(r)*numColumns+c]+skirtVector;
t[vi++] = t[(r)*numColumns+c];
}
// create top skirt vertices
r=numRows-1;
for(c=numColumns-1;c>0;--c)
{
skirtDrawElements[ei++] = (r)*numColumns+c;
skirtDrawElements[ei++] = vi;
v[vi] = v[(r)*numColumns+c]+skirtVector;
t[vi++] = t[(r)*numColumns+c];
}
// create left skirt vertices
c=0;
for(r=numRows-1;r>0;--r)
{
skirtDrawElements[ei++] = (r)*numColumns+c;
skirtDrawElements[ei++] = vi;
v[vi] = v[(r)*numColumns+c]+skirtVector;
t[vi++] = t[(r)*numColumns+c];
}
skirtDrawElements[ei++] = 0;
skirtDrawElements[ei++] = firstSkirtVertexIndex;
}
osgUtil::TriStripVisitor tsv;
tsv.stripify(*geometry);
//
// osgUtil::SmoothingVisitor sv;
// sv.smooth(*geometry);
osg::Vec4Array& tsgTangentArray = *(new osg::Vec4Array(1));
osg::Vec4Array& tsgBinormalArray = *(new osg::Vec4Array(1));
osg::Vec4Array& tsgNormalArray = *(new osg::Vec4Array(1));
tsgTangentArray[0].set(1.0f,0.0f,0.0f,0.0f);
tsgBinormalArray[0].set(0.0f,1.0f,0.0f,0.0f);
tsgNormalArray[0].set(0.0f,0.0f,1.0f,0.0f);
geometry->setVertexAttribData(6, osg::Geometry::ArrayData(&tsgTangentArray, osg::Geometry::BIND_OVERALL,GL_FALSE));
geometry->setVertexAttribData(7, osg::Geometry::ArrayData(&tsgBinormalArray, osg::Geometry::BIND_OVERALL,GL_FALSE));
geometry->setVertexAttribData(15, osg::Geometry::ArrayData(&tsgNormalArray, osg::Geometry::BIND_OVERALL,GL_FALSE));
//geometry->setUseVertexBufferObjects(true);
geometry->setUseDisplayList(false);
geometry->setUseVertexBufferObjects(false);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(geometry);
return geode;
}
osg::Node* createQuadTree(osg::HeightField* grid,
unsigned int columnBegin, unsigned int columnEnd,
unsigned int rowBegin, unsigned int rowEnd,
float xTexCoordBegin, float xTexCoordEnd,
float yTexCoordBegin, float yTexCoordEnd,
unsigned int targetNumPolygonsPerTile)
{
unsigned int numPolys = (columnEnd-columnBegin)*(rowEnd-rowBegin)*2;
std::cout << "createQuadTree "<<columnBegin<<","<<columnEnd<<std::endl;
osg::Node* tile = createTile(grid,
columnBegin, columnEnd,
rowBegin, rowEnd,
xTexCoordBegin, xTexCoordEnd,
yTexCoordBegin, yTexCoordEnd,
targetNumPolygonsPerTile);
if (numPolys<=targetNumPolygonsPerTile)
{
return tile;
}
else
{
float cut_off_distance = tile->getBound().radius()*4.0f;
float max_visible_distance = 1e7;
unsigned int columnCenter = (columnBegin + columnEnd)/2;
unsigned int rowCenter = (rowBegin + rowEnd)/2;
float xTexCoordCenter = xTexCoordBegin+
(xTexCoordEnd-xTexCoordBegin)*((float)(columnCenter-columnBegin)/(float)(columnEnd-columnBegin));
float yTexCoordCenter = yTexCoordBegin+
(yTexCoordEnd-yTexCoordBegin)*((float)(rowCenter-rowBegin)/(float)(rowEnd-rowBegin));
osg::Group* group = new osg::Group;
group->addChild(createQuadTree(grid,
columnBegin, columnCenter,
rowBegin, rowCenter,
xTexCoordBegin, xTexCoordCenter,
yTexCoordBegin, yTexCoordCenter,
targetNumPolygonsPerTile));
group->addChild(createQuadTree(grid,
columnCenter, columnEnd,
rowBegin, rowCenter,
xTexCoordCenter, xTexCoordEnd,
yTexCoordBegin, yTexCoordCenter,
targetNumPolygonsPerTile));
group->addChild(createQuadTree(grid,
columnCenter, columnEnd,
rowCenter, rowEnd,
xTexCoordCenter, xTexCoordEnd,
yTexCoordCenter, yTexCoordEnd,
targetNumPolygonsPerTile));
group->addChild(createQuadTree(grid,
columnBegin, columnCenter,
rowCenter, rowEnd,
xTexCoordBegin, xTexCoordCenter,
yTexCoordCenter, yTexCoordEnd,
targetNumPolygonsPerTile));
osg::LOD* lod = new osg::LOD;
lod->addChild(tile,cut_off_distance,max_visible_distance);
lod->addChild(group,0.0f,cut_off_distance);
return lod;
}
}
template< typename T>
void populate_z(osg::Image* image, const osg::Vec3& zAxis,osg::Vec3Array& v)
{
unsigned char* ptr = image->data();
unsigned int rowSizeInBytes = image->getRowSizeInBytes();
unsigned int pixelSizeInBits = image->getPixelSizeInBits();
unsigned int pixelSizeInBytes = pixelSizeInBits/8;
unsigned int numColumns = image->s();
unsigned int numRows = image->t();
for(unsigned int r=0,vi=0;r<numRows;++r)
{
unsigned char* ptr_in_row = ptr;
for(unsigned int c=0;c<numColumns;++c)
{
v[vi++] += zAxis * (float)(*((T*)ptr_in_row));
ptr_in_row += pixelSizeInBytes;
}
ptr += rowSizeInBytes;
}
}
osg::Node* computeGeometry(osg::Image* image, const osg::Vec3& origin, const osg::Vec3& xAxis, const osg::Vec3& yAxis, const osg::Vec3& zAxis)
{
if (!image) return 0;
osgDB::ImageOptions::TexCoordRange* texCoordRange = dynamic_cast<osgDB::ImageOptions::TexCoordRange*>(image->getUserData());
unsigned int numColumns = image->s();
unsigned int numRows = image->t();
unsigned int r;
unsigned int c;
osg::Geode* geode = new osg::Geode;
bool useGeometry = true;
if (useGeometry)
{
osg::Geometry* geometry = new osg::Geometry;
osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
//osg::Vec3Array& n = *(new osg::Vec3Array(numColumns*numRows));
osg::Vec2Array& t = *(new osg::Vec2Array(numColumns*numRows));
osg::UByte4Array& color = *(new osg::UByte4Array(1));
color[0].set(255,255,255,255);
#if 0
osg::Vec2 tex_orig(0.0f,0.0f);
float rowTexDelta = 1.0f/(float)(numRows-1);
float columnTexDelta = 1.0f/(float)(numColumns-1);
#else
osg::Vec2 tex_orig(origin.x(),origin.y());
float columnTexDelta = xAxis.length()/(float)(numColumns-1);
float rowTexDelta = yAxis.length()/(float)(numRows-1);
#endif
if (texCoordRange)
{
// tex_orig.set(texCoordRange->_x,texCoordRange->_y);
// rowTexDelta = texCoordRange->_h/(float)(numRows-1);
// columnTexDelta = texCoordRange->_w/(float)(numColumns-1);
std::cout<<"setting tex values to use texCoordRange"<<std::endl;
std::cout<<" tex_orig="<<tex_orig<<std::endl;
std::cout<<" rowTexDelta"<<rowTexDelta<<std::endl;
std::cout<<" columnTexDelta"<<columnTexDelta<<std::endl;
}
osg::Vec2 tex(tex_orig);
int vi=0;
osg::Vec3 normal(0.0f,0.0f,1.0f);
osg::Vec3 pos = origin;
osg::Vec3 delta_x = xAxis/(double)(numColumns-1);
osg::Vec3 delta_y = yAxis/(double)(numRows-1);
for(r=0;r<numRows;++r)
{
tex.x() = tex_orig.x();
osg::Vec3 pos_in_row = pos;
for(c=0;c<numColumns;++c)
{
v[vi] = pos_in_row; // + zAxis * (sin(pos_in_row.x()*osg::PI*2)*cos(pos_in_row.y()*osg::PI*2));
//n[vi] = normal;
t[vi].set(tex.x(),tex.y());
pos_in_row +=delta_x;
tex.x()+=columnTexDelta;
++vi;
}
pos += delta_y;
tex.y() += rowTexDelta;
}
switch(image->getDataType())
{
case(GL_UNSIGNED_BYTE): populate_z<unsigned char>(image,zAxis,v); break;
case(GL_BYTE): populate_z<char>(image,zAxis,v); break;
case(GL_UNSIGNED_SHORT): populate_z<unsigned short>(image,zAxis,v); break;
case(GL_SHORT): populate_z<short>(image,zAxis,v); break;
case(GL_UNSIGNED_INT): populate_z<unsigned int>(image,zAxis,v); break;
case(GL_INT): populate_z<int>(image,zAxis,v); break;
case(GL_FLOAT): populate_z<float>(image,zAxis,v); break;
}
geometry->setVertexArray(&v);
//geometry->setNormalArray(&n);
//geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
geometry->setColorArray(&color);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
geometry->setTexCoordArray(0,&t);
geometry->setTexCoordArray(1,&t);
for(r=0;r<numRows-1;++r)
{
osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
geometry->addPrimitiveSet(&drawElements);
int ei=0;
for(c=0;c<numColumns;++c)
{
drawElements[ei++] = (r+1)*numColumns+c;
drawElements[ei++] = (r)*numColumns+c;
}
}
osgUtil::TriStripVisitor tsv;
tsv.stripify(*geometry);
//
// osgUtil::SmoothingVisitor sv;
// sv.smooth(*geometry);
osg::Vec4Array& tsgTangentArray = *(new osg::Vec4Array(1));
osg::Vec4Array& tsgBinormalArray = *(new osg::Vec4Array(1));
osg::Vec4Array& tsgNormalArray = *(new osg::Vec4Array(1));
tsgTangentArray[0].set(1.0f,0.0f,0.0f,0.0f);
tsgBinormalArray[0].set(0.0f,1.0f,0.0f,0.0f);
tsgNormalArray[0].set(0.0f,0.0f,1.0f,0.0f);
geometry->setVertexAttribData(6, osg::Geometry::ArrayData(&tsgTangentArray, osg::Geometry::BIND_OVERALL,GL_FALSE));
geometry->setVertexAttribData(7, osg::Geometry::ArrayData(&tsgBinormalArray, osg::Geometry::BIND_OVERALL,GL_FALSE));
geometry->setVertexAttribData(15, osg::Geometry::ArrayData(&tsgNormalArray, osg::Geometry::BIND_OVERALL,GL_FALSE));
//geometry->setUseVertexBufferObjects(true);
geometry->setUseDisplayList(false);
geometry->setUseVertexBufferObjects(false);
geode->addDrawable(geometry);
}
else
{
osg::HeightField* grid = createHeightField(image,origin,osg::Vec3(xAxis.length(),yAxis.length(),zAxis.length()));
geode->addDrawable(new osg::ShapeDrawable(grid));
}
return geode;
}
osg::Node* computeGeometry(osg::Image* image, const osg::Vec3& origin, const osg::Vec3& size)
{
return computeGeometry(image,origin,osg::Vec3(size.x(),0.0f,0.0f),osg::Vec3(0.0f,size.y(),0.0f),osg::Vec3(0.0f,0.0f,size.z()));
}
osg::Node* createTile(const std::string& filename, double x, double y, double w,double h)
{
osg::ref_ptr<osgDB::ImageOptions> options = new osgDB::ImageOptions;
options->_sourceImageWindowMode = osgDB::ImageOptions::RATIO_WINDOW;
options->_sourceRatioWindow.set(x,1-(y+h),w,h);
options->_destinationImageWindowMode = osgDB::ImageOptions::PIXEL_WINDOW;
options->_destinationPixelWindow.set(0,0,20,20);
osgDB::Registry::instance()->setOptions(options.get());
osg::Image* image = osgDB::readImageFile(filename.c_str());
if (image)
{
return computeGeometry(image,osg::Vec3(x,y,0.0),osg::Vec3(w,h,VERTICAL_SIZE));
}
else
{
return 0;
}
}
osg::Node* createTileAndRecurse(const std::string& filename, const std::string& basename, const std::string& extension, unsigned int noTilesX, unsigned int noTilesY, double x, double y, double w,double h, unsigned int numLevelsLeft)
{
osg::Group* group = new osg::Group;
double dx = w / (double) noTilesX;
double dy = h / (double) noTilesY;
if (numLevelsLeft>0)
{
float cut_off_distance = 4.0f*dy;
float max_visible_distance = 1e7;
// create current layer, and write to disk.
unsigned int numTiles = 0;
double lx = x;
for(unsigned i=0;i<noTilesX;++i,lx+=dx)
{
double ly = y;
for(unsigned j=0;j<noTilesY;++j,ly+=dy)
{
// create name for tile.
char char_num = 'A'+numTiles;
std::string lbasename = basename+"_"+char_num;
// create the subtiles and write out to disk.
{
osg::ref_ptr<osg::Node> node = createTileAndRecurse(filename,lbasename,extension,2,2,lx,ly,dx,dy,numLevelsLeft-1);
osgDB::writeNodeFile(*node, lbasename+extension);
}
// create PagedLOD for tile.
osg::PagedLOD* pagedlod = new osg::PagedLOD;
osg::Node* tile = createTile(filename,lx,ly,dx,dy);
pagedlod->addChild(tile, cut_off_distance,max_visible_distance);
pagedlod->setRange(1,0.0f,cut_off_distance);
pagedlod->setFileName(1,lbasename+extension);
pagedlod->setCenter(tile->getBound().center());
group->addChild(pagedlod);
// increment number of tiles.
++numTiles;
}
}
}
else
{
double lx = x;
for(unsigned i=0;i<noTilesX;++i,lx+=dx)
{
double ly = y;
for(unsigned j=0;j<noTilesY;++j,ly+=dy)
{
group->addChild(createTile(filename,lx,ly,dx,dy));
}
}
}
return group;
}
bool createWorld(const std::string& inputFile, const std::string& baseName, unsigned int numLevels)
{
osgDB::ReaderWriter* readerWriter = osgDB::Registry::instance()->getReaderWriterForExtension("gdal");
if (!readerWriter)
{
std::cout<<"Error: GDAL plugin not available, cannot preceed with database creation"<<std::endl;
return false;
}
osg::Timer timer;
osg::Timer_t start_tick = timer.tick();
// create the world
std::string path = osgDB::getFilePath(baseName);
std::string base = path.empty()?osgDB::getStrippedName(baseName):
path +'/'+ osgDB::getStrippedName(baseName);
std::string extension = '.'+osgDB::getLowerCaseFileExtension(baseName);
std::cout << "baseName = "<<baseName<<std::endl;
std::cout << "base = "<<base<<std::endl;
std::cout << "extension = "<<extension<<std::endl;
bool doBumpMapping = true;
int bumpMapSize = 512;
if (doBumpMapping)
{
osg::ref_ptr<osg::Node> scene;
// = createTileAndRecurse(inputFile, base, /*extension*/".ive", 2,2, 0.0, 0.0, 1.0, 1.0, numLevels);
// generate normal map
osg::Image* normalMap = 0;
{
osg::ref_ptr<osgDB::ImageOptions> options = new osgDB::ImageOptions;
options->_sourceImageWindowMode = osgDB::ImageOptions::RATIO_WINDOW;
options->_sourceRatioWindow.set(0,0,1,1);
options->_destinationImageWindowMode = osgDB::ImageOptions::PIXEL_WINDOW;
options->_destinationPixelWindow.set(0,0,512,512);
osgDB::Registry::instance()->setOptions(options.get());
osg::Image* image = osgDB::readImageFile(inputFile.c_str());
if (image)
{
osg::HeightField* grid = createHeightField(image,osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(1.0,1.0,VERTICAL_SIZE));
normalMap = createNormalMap(grid);
normalMap->setFileName("normalmap.rgb");
osgDB::writeImageFile(*normalMap,"normalmap.rgb");
scene = createQuadTree(grid,
0, grid->getNumColumns()-1,
0, grid->getNumRows()-1,
0.0f, 1.0f,
0.0f, 1.0f,
2000);
}
}
// generate diffuse map
osg::Image* diffuseMap = 0;
// {
// osg::ref_ptr<osgDB::ImageOptions> options = new osgDB::ImageOptions;
// options->_sourceImageWindowMode = osgDB::ImageOptions::RATIO_WINDOW;
// options->_sourceRatioWindow.set(0,0,1,1);
//
// options->_destinationImageWindowMode = osgDB::ImageOptions::PIXEL_WINDOW;
// options->_destinationPixelWindow.set(0,0,2048,2048);
//
// osgDB::Registry::instance()->setOptions(options.get());
// diffuseMap = osgDB::readImageFile(inputFile.c_str());
// if (diffuseMap)
// {
// diffuseMap->setFileName("diffuse.rgb");
// osgDB::writeImageFile(*diffuseMap,"diffuse.rgb");
// }
//
// }
diffuseMap = osgDB::readImageFile("LlanoTex.jpg");
osg::Texture2D* diffuseMapTexture = new osg::Texture2D(diffuseMap);
osg::Texture2D* normalMapTexture = new osg::Texture2D(normalMap);
// create osgFX::BumpingMapping
osg::ref_ptr<osgFX::BumpMapping> bumpMap = new osgFX::BumpMapping;
bumpMap->setLightNumber(0);
bumpMap->setNormalMapTextureUnit(0);
bumpMap->setDiffuseTextureUnit(1);
bumpMap->setOverrideDiffuseTexture(diffuseMapTexture);
bumpMap->setOverrideNormalMapTexture(normalMapTexture);
bumpMap->addChild(scene.get());
#ifdef USE_PREPARE
bumpMap->prepareChildren();
#endif
osg::ref_ptr<osg::Group> group = new osg::Group;
group->addChild(bumpMap.get());
osg::StateSet* stateset = group->getOrCreateStateSet();
stateset->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
osgDB::writeNodeFile(*group, baseName);
}
else
{
osg::ref_ptr<osg::Group> group = new osg::Group;
group->addChild(createTileAndRecurse(inputFile, base, extension, 2,2, 0.0, 0.0, 1.0, 1.0, numLevels));
osg::StateSet* stateset = group->getOrCreateStateSet();
stateset->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
osgDB::writeNodeFile(*group, baseName);
}
osg::Timer_t end_tick = timer.tick();
std::cout << "Time to create world "<<timer.delta_s(start_tick,end_tick)<<std::endl;
return true;
}
int main( int argc, char **argv )
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
// set up the usage document, in case we need to print out how to use this program.
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
arguments.getApplicationUsage()->addCommandLineOption("-i <filename>","Specify the input file to process");
arguments.getApplicationUsage()->addCommandLineOption("-o <outputfile>","Specify the output master file to generate");
arguments.getApplicationUsage()->addCommandLineOption("-l <numOfLevels>","Specify the number of PagedLOD levels to generate");
arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
std::string inputFile;
while (arguments.read("-i",inputFile)) {}
std::string basename("output.ive");
while (arguments.read("-o",basename)) {}
float numLevels;
while (arguments.read("-l",numLevels)) {}
while (arguments.read("-v",VERTICAL_SIZE)) {}
// if user request help write it out to cout.
if (arguments.read("-h") || arguments.read("--help"))
{
arguments.getApplicationUsage()->write(std::cout);
return 1;
}
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occured when parsing the program aguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// if (arguments.argc()<=1)
// {
// arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
// return 1;
// }
// create a graphics context to allow us to use OpenGL to compress textures.
GraphicsContext gfx;
createWorld(inputFile,basename,(unsigned int)numLevels);
return 0;
}

View File

@ -384,7 +384,7 @@ osg::Geode* ForestTechniqueManager::createTerrain(const osg::Vec3& origin, const
if (createGrid)
{
osg::Grid* grid = new osg::Grid;
osg::HeightField* grid = new osg::HeightField;
grid->allocateGrid(numColumns,numRows);
grid->setOrigin(origin);
grid->setXInterval(size.x()/(float)(numColumns-1));

View File

@ -68,7 +68,7 @@ osg::Node* createBase(const osg::Vec3& center,float radius)
geode->setStateSet( stateset );
osg::Grid* grid = new osg::Grid;
osg::HeightField* grid = new osg::HeightField;
grid->allocateGrid(38,39);
grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
grid->setXInterval(radius*2.0f/(float)(38-1));

View File

@ -42,7 +42,7 @@ osg::Geode* createShapes()
geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(4.0f,0.0f,0.0f),radius,height),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(6.0f,0.0f,0.0f),radius,height),hints));
osg::Grid* grid = new osg::Grid;
osg::HeightField* grid = new osg::HeightField;
grid->allocateGrid(38,39);
grid->setXInterval(0.28f);
grid->setYInterval(0.28f);

View File

@ -418,21 +418,25 @@ class SG_EXPORT HeightField : public Shape
{
public:
HeightField() {}
HeightField(const HeightField& mesh,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
Shape(mesh,copyop),
HeightField():
_columns(0),
_rows(0),
_origin(0.0f,0.0f,0.0f),
_dx(1.0f),
_dy(1.0f) {}
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const HeightField*>(obj)!=NULL; }
virtual const char* libraryName() const { return "osg"; }
virtual const char* className() const { return "HeightField"; }
virtual void accept(osg::ShapeVisitor& sv) { sv.apply(*this); }
virtual void accept(osg::ConstShapeVisitor& csv) const { csv.apply(*this); }
HeightField(const HeightField& mesh,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
Shape(mesh,copyop),
_columns(mesh._columns),
_rows(mesh._rows),
_origin(mesh._origin),
_dx(mesh._dx),
_dy(mesh._dy),
_heights(mesh._heights) {}
META_Shape(osg, HeightField)
void allocateGrid(unsigned int numColumns,unsigned int numRows);
inline unsigned int getNumColumns() const { return _columns; }
inline unsigned int getNumRows() const { return _rows; }
@ -446,9 +450,23 @@ class SG_EXPORT HeightField : public Shape
inline void setYInterval(float dy) { _dy = dy; }
inline float getYInterval() const { return _dy; }
virtual float getHeight(unsigned int c,unsigned int r) const = 0;
virtual Vec3 getNormal(unsigned int c,unsigned int r) const;
inline void setHeight(unsigned int c,unsigned int r,float value)
{
_heights[c+r*_columns] = value;
}
inline float& getHeight(unsigned int c,unsigned int r)
{
return _heights[c+r*_columns];
}
inline float getHeight(unsigned int c,unsigned int r) const
{
return _heights[c+r*_columns];
}
Vec3 getNormal(unsigned int c,unsigned int r) const;
inline void setRotation(const Quat& quat) { _rotation = quat; }
inline const Quat& getRotation() const { return _rotation; }
@ -467,39 +485,11 @@ class SG_EXPORT HeightField : public Shape
Quat _rotation;
};
class SG_EXPORT Grid : public HeightField
{
public:
Grid();
Grid(const Grid& mesh,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_Shape(osg,Grid);
void allocateGrid(unsigned int numColumns,unsigned int numRows);
void setHeight(unsigned int c,unsigned int r,float value)
{
_heights[c+r*_columns] = value;
}
virtual float getHeight(unsigned int c,unsigned int r) const
{
return _heights[c+r*_columns];
}
protected:
~Grid();
typedef std::vector<float> HeightList;
HeightList _heights;
};
class CompositeShape : public Shape
{
public:

View File

@ -86,14 +86,33 @@ class OSGDB_EXPORT ImageOptions : public osgDB::ReaderWriter::Options
CUBIC
};
/** Used as UserData attached to generated osg::Image's*/
struct TexCoordRange : public osg::Referenced
{
TexCoordRange():
_x(0.0),
_y(0.0),
_w(1.0),
_h(1.0) {}
void set(double x,double y, double w, double h)
{
_x = x;
_y = y;
_w = w;
_h = h;
}
double _x,_y,_w,_h;
};
// source
ImageSamplingMode _sourceImageSamplingMode;
ImageWindowMode _sourceImageWindowMode;
RatioWindow _sourceRatioWindow;
PixelWindow _sourcePixelWindow;
// destination
osg::ref_ptr<osg::Image> _destinationImage;

View File

@ -21,7 +21,7 @@
namespace osgGA{
//
// The AnimationPathManipulator is a Camera Manipulator that reads an
// The AnimationPathManipulator is a Matrix Manipulator that reads an
// animation path from a file and plays it back. The file is expected
// to be ascii and a succession of lines with 8 floating point values
// per line. The succession of values are:

View File

@ -15,6 +15,16 @@
using namespace osg;
void HeightField::allocateGrid(unsigned int numColumns,unsigned int numRows)
{
if (_columns!=numColumns || _rows!=numRows)
{
_heights.resize(numColumns*numRows);
}
_columns=numColumns;
_rows=numRows;
}
Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const
{
// four point normal generation.
@ -53,27 +63,4 @@ Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const
return normal;
}
Grid::Grid()
{
}
Grid::Grid(const Grid& mesh,const CopyOp& copyop):
HeightField(mesh,copyop)
{
_heights = mesh._heights;
}
Grid::~Grid()
{
}
void Grid::allocateGrid(unsigned int numColumns,unsigned int numRows)
{
if (_columns!=numColumns || _rows!=numRows)
{
_heights.resize(numColumns*numRows);
}
_columns=numColumns;
_rows=numRows;
}

View File

@ -42,18 +42,35 @@ class ReaderWriterGDAL : public osgDB::ReaderWriter
int destHeight = osg::minimum(dataHeight,1024);
osgDB::ImageOptions::TexCoordRange* texCoordRange = 0;
const osgDB::ImageOptions* imageOptions = dynamic_cast<const osgDB::ImageOptions*>(options);
if (imageOptions)
{
std::cout<<"Got ImageOptions"<<std::endl;
int margin = 0;
switch(imageOptions->_sourceImageWindowMode)
{
case(osgDB::ImageOptions::RATIO_WINDOW):
windowX = osg::maximum((int)(floor((double)dataWidth * imageOptions->_sourceRatioWindow.windowX)),0);
windowY = osg::maximum((int)(floor((double)dataHeight * imageOptions->_sourceRatioWindow.windowY)),0);
windowWidth = osg::minimum((int)(ceil((double)dataWidth * (imageOptions->_sourceRatioWindow.windowX + imageOptions->_sourceRatioWindow.windowWidth))),dataWidth)-windowX;
windowHeight = osg::minimum((int)(ceil((double)dataHeight * (imageOptions->_sourceRatioWindow.windowY + imageOptions->_sourceRatioWindow.windowHeight))),dataHeight)-windowY;
{
double desiredX = (double)dataWidth * imageOptions->_sourceRatioWindow.windowX;
double desiredY = (double)dataHeight * imageOptions->_sourceRatioWindow.windowY;
double desiredWidth = (double)dataWidth * imageOptions->_sourceRatioWindow.windowWidth;
double desiredHeight = (double)dataHeight * imageOptions->_sourceRatioWindow.windowHeight;
windowX = osg::maximum((int)(floor(desiredX))-margin,0);
windowY = osg::maximum((int)(floor(desiredY))-margin,0);
windowWidth = osg::minimum((int)(ceil(desiredX + desiredWidth))+margin,dataWidth)-windowX;
windowHeight = osg::minimum((int)(ceil(desiredY + desiredHeight))+margin,dataHeight)-windowY;
texCoordRange = new osgDB::ImageOptions::TexCoordRange;
texCoordRange->set((desiredX-(double)windowX)/(double)windowWidth,
((double)(windowY+windowHeight) -(desiredY+desiredHeight))/(double)windowHeight,
(desiredWidth)/(double)windowWidth,
(desiredHeight)/(double)windowHeight);
std::cout<<"tex coord range "<<texCoordRange->_x<<" "<<texCoordRange->_y<<" "<<texCoordRange->_w<<" "<<texCoordRange->_h<<std::endl;
}
break;
case(osgDB::ImageOptions::PIXEL_WINDOW):
windowX = imageOptions->_sourcePixelWindow.windowX;
@ -145,6 +162,7 @@ class ReaderWriterGDAL : public osgDB::ReaderWriter
else if (band->GetColorInterpretation()==GCI_GreenBand) bandGreen = band;
else if (band->GetColorInterpretation()==GCI_BlueBand) bandBlue = band;
else if (band->GetColorInterpretation()==GCI_AlphaBand) bandAlpha = band;
else bandGray = band;
// int gotMin,gotMax;
// double minmax[2];
@ -282,6 +300,8 @@ class ReaderWriterGDAL : public osgDB::ReaderWriter
(unsigned char *)imageData,
osg::Image::USE_NEW_DELETE);
if (texCoordRange) image->setUserData(texCoordRange);
image->flipVertical();
return image;

View File

@ -73,6 +73,21 @@ bool Drawable_readLocalData(Object& obj, Input& fr)
}
}
if (fr[0].matchWord("useVertexBufferObjects"))
{
if (fr[1].matchWord("TRUE"))
{
drawable.setUseVertexBufferObjects(true);
fr+=2;
iteratorAdvanced = true;
}
else if (fr[1].matchWord("FALSE"))
{
drawable.setUseVertexBufferObjects(false);
fr+=2;
iteratorAdvanced = true;
}
}
return iteratorAdvanced;
}
@ -103,6 +118,9 @@ bool Drawable_writeLocalData(const Object& obj, Output& fw)
if (drawable.getUseDisplayList()) fw << "TRUE" << std::endl;
else fw << "FALSE" << std::endl;
fw.indent()<<"useVertexBufferObjects ";
if (drawable.getUseVertexBufferObjects()) fw << "TRUE" << std::endl;
else fw << "FALSE" << std::endl;
return true;
}

View File

@ -305,14 +305,25 @@ bool HeightField_writeLocalData(const Object& obj, Output& fw);
//register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_HeightFieldFuncProxy
(
0,
new osg::HeightField,
"HeightField",
"Object HieghtField",
"Object HeightField",
&HeightField_readLocalData,
&HeightField_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
//register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_GridFuncProxy
(
new osg::HeightField,
"Grid",
"Object HeightField",
0,
0,
DotOsgWrapper::READ_AND_WRITE
);
bool HeightField_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
@ -359,49 +370,12 @@ bool HeightField_readLocalData(Object& obj, Input& fr)
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool HeightField_writeLocalData(const Object& obj, Output& fw)
{
const HeightField& heightfield = static_cast<const HeightField&>(obj);
fw.indent()<<"Origin "<<heightfield.getOrigin()<<std::endl;
fw.indent()<<"XInterval "<<heightfield.getXInterval()<<std::endl;
fw.indent()<<"YInterval "<<heightfield.getYInterval()<<std::endl;
fw.indent()<<"Rotation "<<heightfield.getRotation()<<std::endl;
return true;
}
//////////////////////////////////////////////////////////////////////////////
// forward declare functions to use later.
bool Grid_readLocalData(Object& obj, Input& fr);
bool Grid_writeLocalData(const Object& obj, Output& fw);
//register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_GridFuncProxy
(
new osg::Grid,
"Grid",
"Object HeightField Grid",
&Grid_readLocalData,
&Grid_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool Grid_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
Grid& grid = static_cast<Grid&>(obj);
if (fr.matchSequence("NumColumnsAndRows %i %i"))
{
int numcolumns,numrows;
fr[1].getInt(numcolumns);
fr[2].getInt(numrows);
grid.allocateGrid(numcolumns,numrows);
heightfield.allocateGrid(numcolumns,numrows);
fr+=3;
iteratorAdvanced = true;
}
@ -421,9 +395,9 @@ bool Grid_readLocalData(Object& obj, Input& fr)
{
if (fr.readSequence(height))
{
grid.setHeight(column,row,height);
heightfield.setHeight(column,row,height);
++column;
if (column>=grid.getNumColumns())
if (column>=heightfield.getNumColumns())
{
column = 0;
++row;
@ -440,25 +414,29 @@ bool Grid_readLocalData(Object& obj, Input& fr)
}
return iteratorAdvanced;
}
bool Grid_writeLocalData(const Object& obj, Output& fw)
bool HeightField_writeLocalData(const Object& obj, Output& fw)
{
const Grid& grid = static_cast<const Grid&>(obj);
const HeightField& heightfield = static_cast<const HeightField&>(obj);
fw.indent()<<"NumColumnsAndRows "<<grid.getNumColumns()<<" "<<grid.getNumRows()<<std::endl;
fw.indent()<<"Origin "<<heightfield.getOrigin()<<std::endl;
fw.indent()<<"XInterval "<<heightfield.getXInterval()<<std::endl;
fw.indent()<<"YInterval "<<heightfield.getYInterval()<<std::endl;
fw.indent()<<"Rotation "<<heightfield.getRotation()<<std::endl;
fw.indent()<<"NumColumnsAndRows "<<heightfield.getNumColumns()<<" "<<heightfield.getNumRows()<<std::endl;
fw.indent()<<"Heights"<<std::endl;
ParameterOutput po(fw);
po.begin();
for(unsigned int row=0;row<grid.getNumRows();++row)
for(unsigned int row=0;row<heightfield.getNumRows();++row)
{
for(unsigned int column=0;column<grid.getNumColumns();++column)
for(unsigned int column=0;column<heightfield.getNumColumns();++column)
{
po.write(grid.getHeight(column,row));
po.write(heightfield.getHeight(column,row));
}
po.newLine();
}