[osg-users] [3rdparty] Use PNG as texture for terrain in osgEarth

60 views
Skip to first unread message

Rodrigo Dias

unread,
Jan 7, 2019, 12:13:20 PM1/7/19
to osg-...@lists.openscenegraph.org
Hi,

Following this example (http://docs.osgearth.org/en/latest/developer/maps.html#programmatic-map-creation), I'm trying to use a PNG instead of a link (like the example uses a TIFF for elevation). However, I got the following error:


> [osgEarth]* Error in XML document: Error document empty. (row 0, col 0)
> [osgEarth]* [TMS] Could not find root TileMap element
>


What should I do instead?

Thank you!

Cheers,
Rodrigo

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75402#75402





_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Chris Hanson

unread,
Jan 7, 2019, 3:25:54 PM1/7/19
to OpenSceneGraph Users
Can you show your exact code and the .earth XML file?

It sounds to me like it failed to open/load the XML file. Is it a file path/permisssions issue?
--
Chris 'Xenon' Hanson, omo sanza lettere. Xe...@AlphaPixel.com http://www.alphapixel.com/
Training • Consulting • Contracting
3D • Scene Graphs (Open Scene Graph/OSG) • OpenGL 2 • OpenGL 3 • OpenGL 4 • GLSL • OpenGL ES 1 • OpenGL ES 2 • OpenCL
Legal/IP • Forensics • Imaging  UAVs • GIS • GPS • osgEarth • Terrain • Telemetry • Cryptography • LIDAR • Embedded • Mobile • iPhone/iPad/iOS • Android
@alphapixel facebook.com/alphapixel (775) 623-PIXL [7495]

Rodrigo Dias

unread,
Jan 7, 2019, 5:22:38 PM1/7/19
to osg-...@lists.openscenegraph.org
Hi Chris,

following the example, I thought I could use directly a PNG instead of a .earth XML. Now I tried a XML.

My source code, main.cpp:


Code:
#include <iostream>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgEarth/ImageLayer>
#include <osgEarth/Map>
#include <osgEarth/MapNode>
#include <osgEarthDrivers/tms/TMSOptions>
#include <osgEarthDrivers/gdal/GDALOptions>

using namespace std;
using namespace osgEarth;
using namespace osgEarth::Drivers;

int main (int argc, char** argv) {
// Create a Map and set it to Geocentric to display a globe
osg::ref_ptr<Map> map = new Map();
cout << 1;

// Add an imagery layer (blue marble from a TMS source)
{
TMSOptions tms;
tms.url() = "br.earth";
osg::ref_ptr<ImageLayer> layer = new ImageLayer( "NASA", tms );
layer->setOpacity(0.5);
printf("\nOpacity: %.2f\n",layer->getOpacity());
map->addLayer( layer );
}
cout << 2 << endl;
}




Compile line:


> g++ main.cpp -lOpenThreads -losg -losgDB -losgUtil -losgViewer -losgEarth -o main
>


The XML file:


> <map name="Brasil" type="projected">
> <image name="br" driver="png">
> <url>br.png</url>
> </image>
> </map>
>


How am I supposed to show you my XML if the tags disappear?

I have a br.png file in the same directory of the program. I don't know if I should specify "br" or "br.png" as the name of the "image" tag, if driver really can contain "png", and if the name of the image should be specified in the "url" tag instead (or both).

Now, when the code runs, it displays:


> 1
> Opacity: 0.50
> [osgEarth]* [TMS] Could not find root TileMap element
> 2
>


Thank you!

Cheers,
Rodrigo

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75405#75405

Chris Hanson

unread,
Jan 7, 2019, 5:52:03 PM1/7/19
to OpenSceneGraph Users
Ok, so if you're adding an image layer programmatically, you don't want to add a .earth XML file.


It should probably look something like

        // Add an imagery layer
        {
                GDALOptions gdal;
                gdal.url() = "br.png";

                osg::ref_ptr<ImageLayer> layer = new ImageLayer( "NASA", tms );
                layer->setOpacity(0.5);
                printf("\nOpacity: %.2f\n",layer->getOpacity());
                map->addLayer( layer );
        }  

The GDAL loader handles almost all local-disk data loading. The TMS loader you were trying to use is for loading data from an Internet Tile Map Server. The GDAL loader loads either elevation or imagery data.

Keep in mind, if you are using br.png, there isn't any positional information in a PNG file to tell osgEarth WHERE on the Earth to place that PNG file. Certain file types like TIFF can have extra data (called GeoTIFF) that specify this positioning. So, consider what you're trying to do here -- it may not give you errors but you may not see br.png placed anywhere useful on your map.

Rodrigo Dias

unread,
Jan 7, 2019, 6:47:18 PM1/7/19
to osg-...@lists.openscenegraph.org
Ok, Chris, I got it.

Is there any way to tell the program where to put the PNG image? Or must I use a georeferenced TIFF?

Other thing, the XML documentation (http://docs.osgearth.org/en/latest/references/earthfile.html#map) explains that I can choose between a geocentric (ellipsoidal) or a projected (flat) map. How can I choose a flat map programmatically? I didn't find anything in the documentation (https://updraft.github.io/osgearth-doc/html/classosgEarth_1_1Map.html), and the default is geocentric.

Thank you!

Cheers,
Rodrigo

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75407#75407

Rodrigo Dias

unread,
Jan 7, 2019, 7:58:23 PM1/7/19
to osg-...@lists.openscenegraph.org
Well, I managed to create a georeferenced texture file in TIFF format. However, since it's about twice the size of the PNG (even compacted with LZW), it would be great if PNGs could be used instead.

I also managed to make the map projected (flat), by adding the following code in the beginning:


Code:
MapOptions mapOpt;
mapOpt.coordSysType() = MapOptions::CSTYPE_PROJECTED;
mapOpt.profile() = ProfileOptions("plate-carre");
osg::ref_ptr<Map> map = new Map(mapOpt);




However, I just can't see the elevation. Is there any "exaggeration" parameter, such as in Google Earth? I couldn't find any.

Thank you!

Cheers,
Rodrigo[/img]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75409#75409

Chris Hanson

unread,
Jan 8, 2019, 3:56:52 AM1/8/19
to OpenSceneGraph Users
How big is the TIFF and the PNG? They use similar compression methods (PNG is ZIP/Deflate and compressed TIFF is usually LZW and can also use ZIP/Deflate) so you ought to be able to get them fairly close in size. What are the total pixel dimensions of the image? Your best result might not be from using a single large, untiled image. Most of the time you will have better performance (but larger file size) by pre-tiling the image into a TileMap Set like a MapBox Tile set (stored as an SQLite database file, usually).

There probably is a trick to apply georeferencing (like a World File) to a PNG file through GDAL, but it's just not usually done or a good idea. This may be a case where you're asking the wrong question. Tell us what you're trying to accomplish in the larger sense so we can make sure you're attacking the correct problem.

As far as Elevation -- have you added an elevation data source layer? The code you referenced adds elevation data from a local file but yours does not. It would look something like this:

// Add an elevationlayer (SRTM from a local GeoTiff file)
{
    GDALOptions gdal;
    gdal.url() = "c:/data/srtm.tif";
    ElevationLayer* layer = new ElevationLayer( "SRTM", gdal );
    map->addElevationLayer( layer );
}

You can also use TileMap Sets hosted either as a file on your local disk, or served up over the Internet from an HTTP Tile Map Server. Pelican Mapping operates the ReadyMap server for this purpose and you can use it at no charge for low-traffic testing and development purposes but it needs to be licensed for production use.

Rodrigo Dias

unread,
Jan 8, 2019, 6:32:04 AM1/8/19
to osg-...@lists.openscenegraph.org
Hi,

Sorry, I didn't post the updated code:


Code:
#include <iostream>
#include <osg/Camera>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>
#include <osgEarth/ImageLayer>
#include <osgEarth/Map>
#include <osgEarth/MapNode>
#include <osgEarthDrivers/gdal/GDALOptions>

using namespace std;
using namespace osg;
using namespace osgEarth;
using namespace osgEarth::Drivers;

int main (int argc, char** argv) {
MapOptions mapOpt;
mapOpt.coordSysType() = MapOptions::CSTYPE_PROJECTED;
mapOpt.profile() = ProfileOptions("plate-carre");
osg::ref_ptr<Map> map = new Map(mapOpt);
{
GDALOptions gdal;
gdal.url() = "br_modified.tif";
osg::ref_ptr<ImageLayer> layer = new ImageLayer( "BR", gdal );
map->addLayer( layer );
}
{
GDALOptions gdal;
gdal.url() = "BRalt.tif";
osg::ref_ptr<ElevationLayer> layer = new ElevationLayer( "SRTM", gdal );
map->addLayer( layer );
}
osg::ref_ptr<MapNode> mapNode = new MapNode( map );
osgViewer::Viewer viewer;
viewer.setSceneData( mapNode.get() );
viewer.setCameraManipulator( new osgGA::TrackballManipulator );
while ( !viewer.done() ) {
viewer.frame();
}
return 0;
}




As you can see, I guess I should be seeing some elevation by now, since my image is a square around Brazil, and it includes a good portion of the Andes mountain range (with higher pixels closer to white, and sea level in black).

The texture file is 4392x4392 pixels (1.6 MB on PNG/4-bit-depth and 2.6 MB on TIFF/LZW/8-bit-depth, the difference seems due to bit depth, and I'm not sure if I can use a 4-bit TIFF, but that's ok by now; I'll also try tiling later). The elevation file is 588x588 pixels (70 kB). Both TIFFs are GeoTIFFs.

What I'm trying to accomplish is this: https://www.youtube.com/watch?v=vVm_qWeB9wg

Thank you!

Cheers,
Rodrigo

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75423#75423

Chris Hanson

unread,
Jan 8, 2019, 6:59:35 AM1/8/19
to OpenSceneGraph Users
If you feed the TIFF LWZ coder the same 4-bit data as the PNG is made form, I would think it would code about as efficiently, even if the data is stored in an 8-bit representation. Forward-dictionary compression systems work on how many unique symbols are found and if you make a 16m color image with only 256 colors, it'll only take 256 symbol table entries to store.

I'm not sure why the TIFF wouldn't be displaying. What is the bit depth of the TIFF? Have you told osgEarth how to scale the elevation from the TIFF file into real world units? If it's an 8-bit TIFF, you are only feeding it up to 256m of elevation which won't look like much for the Andes.

Rodrigo Dias

unread,
Jan 8, 2019, 7:16:00 AM1/8/19
to osg-...@lists.openscenegraph.org

> If you feed the TIFF LWZ coder the same 4-bit data as the PNG is made form, I would think it would code about as efficiently, even if the data is stored in an 8-bit representation.


I used QGIS to convert from PNG to TIFF. The image only has 16 colors, so maybe it's QGIS fault. Later I may try to convert it to a smaller bit depth to save space (considering I want to use one map for each country in the world, that'll make some difference). But that's not a priority now.


> What is the bit depth of the TIFF?


8 bits as well.


> Have you told osgEarth how to scale the elevation from the TIFF file into real world units?


It seems that's exactly what I need, but I don't know how to do it.

Thank you!

Cheers,
Rodrigo

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75427#75427

Rodrigo Dias

unread,
Jan 8, 2019, 9:28:54 PM1/8/19
to osg-...@lists.openscenegraph.org
So, I learned how to put HUD text, and I'm trying to understand the movement of the camera sending the camera's coordinates to this text. However, the three coordinates (heading, pitch and roll) are always 0 or pi, which seems more a rounding error than anything else. It seems the world is moving, instead of the camera, which I guess is the way that TrackballManipulator works. I want to move the camera around, using WASD keys and mouse movement, but still couldn't get it from the examples (like FirstPersonManipulator). I couldn't even manage to put the camera in a proper initial position! (Here's what I've tried so far: http://forum.openscenegraph.org/viewtopic.php?t=17623)

Other point is that, as you can see in the image below, the whole flat world is white, and Brazil is where it's supposed to be (southern and western hemispheres). But I'd like to have the world transparent instead of white, so only Brazil (or any selected country) would be visible.

[img]https://imgur.com/UVEGwuj[/img]

Here's my source code:


Code:
#include <iostream> // cout
#include <osg/Camera>
#include <osgDB/ReadFile>
#include <osgText/Font>
#include <osgText/Text>


#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>
#include <osgEarth/ImageLayer>
#include <osgEarth/Map>
#include <osgEarth/MapNode>
#include <osgEarthDrivers/gdal/GDALOptions>

using namespace std;
using namespace osg;
using namespace osgEarth;
using namespace osgEarth::Drivers;

osg::ref_ptr<osgText::Font> g_font = osgText::readFontFile("fonts/arial.ttf");

osg::Camera* createHUDCamera( double left, double right, double bottom, double top ) {
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
camera->setClearMask( GL_DEPTH_BUFFER_BIT );
camera->setRenderOrder( osg::Camera::POST_RENDER );
camera->setAllowEventFocus( false );
camera->setProjectionMatrix( osg::Matrix::ortho2D(left, right, bottom, top) );
return camera.release();
}

osgText::Text* createText( const osg::Vec3& pos, const std::string& content, float size ) {
osg::ref_ptr<osgText::Text> text = new osgText::Text;
text->setFont( g_font.get() );
text->setCharacterSize( size );
text->setAxisAlignment( osgText::TextBase::XY_PLANE );
text->setPosition( pos );
text->setText( content, osgText::String::ENCODING_UTF8 );
return text.release();
}

Vec3d getHPRfromQuat(osg::Quat quat) {
double qx = quat.x();
double qy = quat.y();
double qz = quat.z();
double qw = quat.w();
double sqx = qx * qx;
double sqy = qy * qy;
double sqz = qz * qz;
double sqw = qw * qw;
double term1 = 2*(qx*qy+qw*qz);
double term2 = sqw+sqx-sqy-sqz;
double term3 = -2*(qx*qz-qw*qy);
double term4 = 2*(qw*qx+qy*qz);
double term5 = sqw - sqx - sqy + sqz;
double heading = atan2(term1, term2);
double pitch = atan2(term4, term5);
double roll = asin(term3);
return Vec3d( heading, pitch, roll );
}

int main (int argc, char** argv) {

// Cria o texto do HUD
osg::ref_ptr<osgText::Text> text1 = createText(osg::Vec3(10, 748, 0),"Heading",10.0f);
osg::ref_ptr<osgText::Text> text2 = createText(osg::Vec3(10, 728, 0),"Pitch",10.0f);
osg::ref_ptr<osgText::Text> text3 = createText(osg::Vec3(10, 708, 0),"Roll",10.0f);

text1->setDataVariance(osg::Object::DYNAMIC); // pra poder mudar o texto depois
text2->setDataVariance(osg::Object::DYNAMIC); // pra poder mudar o texto depois
text3->setDataVariance(osg::Object::DYNAMIC); // pra poder mudar o texto depois

osg::ref_ptr<osg::Geode> textGeode = new osg::Geode;
textGeode->addDrawable( text1 );
textGeode->addDrawable( text2 );
textGeode->addDrawable( text3 );
osg::Camera* camera = createHUDCamera(0, 1024, 0, 768);
camera->addChild( textGeode.get() );
camera->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF );

// Cria um Mapa na opção "projetado" para mostrar num plano (ao invés de num globo)


MapOptions mapOpt;
mapOpt.coordSysType() = MapOptions::CSTYPE_PROJECTED;
mapOpt.profile() = ProfileOptions("plate-carre");
osg::ref_ptr<Map> map = new Map(mapOpt);

// Adiciona uma camada de imagem/textura (vegetação do Brasil num GeoTiff)


{
GDALOptions gdal;
gdal.url() = "br_modified.tif";

//XMIN XMAX YMIN YMAX
//-74 -34.79 -33.84 5.37


osg::ref_ptr<ImageLayer> layer = new ImageLayer( "BR", gdal );

//layer->setOpacity(0.5);


printf("\nOpacity: %.2f\n",layer->getOpacity());
map->addLayer( layer );
}

// Adiciona uma camada de elevação (SRTM de um arquivo GeoTiff)


{
GDALOptions gdal;
gdal.url() = "BRalt.tif";
osg::ref_ptr<ElevationLayer> layer = new ElevationLayer( "SRTM", gdal );
map->addLayer( layer );
}

// Cria um MapNode para renderizar este mapa


osg::ref_ptr<MapNode> mapNode = new MapNode( map );

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

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


viewer.setCameraManipulator( new osgGA::TrackballManipulator );

Vec3d v;
while ( !viewer.done() ) {
v = getHPRfromQuat( viewer.getCamera()->getProjectionMatrix().getRotate() );
text1->setText((L"Heading: " + to_wstring(v.x())).c_str());
text2->setText((L"Pitch: " + to_wstring(v.y())).c_str());
text3->setText((L"Roll: " + to_wstring(v.z())).c_str());
viewer.frame();
}

return 0;
}
// g++ main.cpp -losg -losgDB -losgViewer -losgEarth -losgText -losgGA -o main


Thank you!

Cheers,
Rodrigo

------------------
Read this topic online here:

http://forum.openscenegraph.org/viewtopic.php?p=75432#75432

Glenn Waldron

unread,
Jan 10, 2019, 6:56:59 AM1/10/19
to OpenSceneGraph Users
Rodrigo,
To load a png you need to replace TMSOptions with GDALOptions.

Rodrigo Dias

unread,
Jan 16, 2019, 11:04:12 AM1/16/19
to osg-...@lists.openscenegraph.org
Thank you, Glenn, but this part was already solved.

About sending the camera's coordinates to screen text, I've found a solution elsewhere:


Code:
Vec3f eye;
while ( !viewer.done() ) {
eye = viewer.getCamera()->getInverseViewMatrix().getTrans();
text1->setText((L"Heading: " + to_wstring(eye.x())).c_str());
text2->setText((L"Pitch: " + to_wstring(eye.y())).c_str());
text3->setText((L"Roll: " + to_wstring(eye.z())).c_str());
viewer.frame();
}




or


Code:
Vec3f eye, center, up;
while ( !viewer.done() ) {
viewer.getCamera()->getViewMatrixAsLookAt( eye, center, up );
text1->setText((L"Heading: " + to_wstring(eye.x())).c_str());
text2->setText((L"Pitch: " + to_wstring(eye.y())).c_str());
text3->setText((L"Roll: " + to_wstring(eye.z())).c_str());
viewer.frame();
}




Now the numbers change as I move the scene around using TrackballManipulator. However, the keys don't change any number when I use FirstPersonManipulator. I tried to look at the source code for examples:


> grep -nrw . -e 'FirstPersonManipulator' --include=*.cpp


but this only returns lines from osgGA/FirstPersonManipulator.cpp

How can I know how to use FirstPersonManipulator without a program that uses it?

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=75499#75499

Rodrigo Dias

unread,
May 13, 2020, 5:05:40 PM5/13/20
to OpenSceneGraph Users
Reply all
Reply to author
Forward
0 new messages