Terrain normal and ElevationPool

classic Classic list List threaded Threaded
14 messages Options
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Terrain normal and ElevationPool

Is there a way to extract out the terrain normal for a given lat/long from an elevation sample using ElevationPool?

I noticed that there is a getNormal() method in the ElevationTexture class but it appears to be inaccessible.

Is there a way to extract it out via a shader using gl_Normal?

As a last resort, I may have to alter the osgEarth source to get the normal but I'd rather not if there is another way to get it.

Any help or suggestions would be appreciated...

Shayne

P.S. in this particular use case, I don't have access to the scenegraph so that is not an option for me..
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Shayne,

ElevationTexture::getNormal is public. An ET may or may not have a normal map though, depending on how it was created. If not you can  call generateNormalMap to make one.

Normals are accessible from a fragment shader in the vp_Normal global vec3 as well.
Glenn Waldron / Pelican Mapping
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Glenn

I did notice that ElevationTexture::getNormal() is public but it is unclear to me how to use it. Are there any examples?

Is the shader approach the better way to go here to get the terrain normal? Will this work for out-of-scenegraph terrain queries using ElevationPool?

-S
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Shayne,

To use it you call getNormal(x, y) in map coordinates. If your map uses lat/long, call it as getNormal(long, lat) where long and lat are in degrees.

Whether you use it in the shader depends of what you are trying to do... what are you trying to do?
Glenn Waldron / Pelican Mapping
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Glenn,

Thanks again for the feedback.

For this particular application, we're loading terrain layers from an earth file for the sole purpose of pinging for terrain elevation (and terrain normal hopefully) information for a given lat/lon position. We're using the ElevationPool class for getting the elevation but we're at a loss on how to get the terrain normal information for the same position.

We do have access to the mapNode on down but we're not doing any rendering so pinging the scenegraph isn't an option for this application. Because of this, am I premature in concluding that using a shader to extract out the normal isn't an option?

Regarding the approach to use the ElevationTexture class, I understand now (thanks to your answer) on how to use the getNormal(...) in that class. What I'm unclear on is how to reference the ElevationTexture class itself. It doesn't appear to be as accessible as the ElevationPool class. Any examples on its usage in the osgEarth source appear to be used internally.

Are there examples on how an application can set it up and use it externally?

Thanks for your help!

-S
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Shayne,

True, there is no easy API for grabbing individual surface normals.

You can call ElevationPool::getTile() to request an elevation tile.

You will need a TileKey for that, and can create one from a point by calling map->getProfile()->createTileKey() with the resolution level you want.

Which level do you want? Profile::getLevelOfDetailForHorizResolution() might help with that, or you can query the ElevationLayer's getDataExtents() property to see what's available.

Once you get the tile, you will need to generate the normals (they are not generated by default since this can be a CPU-intensive operation) by calling generateNormalMap().

Finally, you can call getNormal().

Shaders are only used at render time, so if you're not rendering, they won't help you.

Hope this helps, good luck!
Glenn Waldron / Pelican Mapping
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Glenn,

The information you provided answers a lot of questions for me.

In answer to your question, we're needing the highest resolution available from the source terrain data specified in the earth file.

It looks like there's a way forward (albeit painfully) to get the normal but I am concerned about the need to generate the normalMap each time we grab a tile to get the normal.

Given that our application needs to obtain the elevation and normal at a location as quickly as possible, this might not be acceptable unless we can do some sort of preprocessing beforehand. Creating a normalMap each time a query is being made probably won't work in our case due to lack of performance.

Is there a way to detect if we need to grab a new tile and rebuild the normalMap based on a position change?

I'm starting to think that it might be less expensive to use the ElevationPool class and use a Sobel operator on nearest height neighbors to calculate a normal. Either that or extend the current interface to return an explicit normal along with the elevation at a given location...

-S
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

The EP does has a small L2 cache so you may not have to generate the normal map for every query. It depends how far apart they are.

You can always cache the tiles yourself as well. Check the tilekey's extent to see if a point falls within that tile.

A simpler option might be to sample points around your target point and calculate a normal vector yourself using a simple cross product.
Glenn Waldron / Pelican Mapping
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Thanks Glenn.

I'll take your suggestions into consideration and make a final decision.

Thanks for taking me to school on a lot of this...:)

-S
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

In reply to this post by gwaldron
Glenn,

After considering my options, I've decided to calculate the normal myself (at least for the first pass).

I did have some more questions though that I'm hoping you can answer with regards to the resolution parameter below...

To get the data to calculate the normal, I'm doing the following:

std::vector<osg::Vec4d> points(5);

GeoPoint center(_srs, lon, lat, ALTMODE_ABSOLUTE);
GeoPoint west(_srs, lon - resolution, lat, ALTMODE_ABSOLUTE);
GeoPoint east(_srs, lon + resolution, lat, ALTMODE_ABSOLUTE);
GeoPoint south(_srs, lon, lat - resolution, ALTMODE_ABSOLUTE);
GeoPoint north(_srs, lon, lat + resolution, ALTMODE_ABSOLUTE);

points[0].set(center.x(), center.y(), 0.0, resolution);
points[1].set(west.x(), west.y(), 0.0, resolution);
points[2].set(east.x(), east.y(), 0.0, resolution);
points[3].set(south.x(), south.y(), 0.0, resolution);
points[4].set(north.x(), north.y(), 0.0, resolution);

int samples = mapNode->getMap()->getElevationPool()->sampleMapCoords(points, &workingSet, nullptr);


My question is about the "resolution" value. I know it's supposed to be in the same coord space as the SRS (i.e. lat/lon in this case). Right now, I'm setting it to be:

resolution = 30.0 / 111000.0;

which is mapping meters to degrees. I chose 30 meters because our highest level of DTED we can reference corresponds to DTED level 2 which is a spacing of ~30 meters per elevation post.

Am I on the right track here in the usage of the resolution value in the above calls? Also, what happens if for some areas we don't have DTED level 2 and we resort to DTED level 1 or 0? Will I need to dynamically change the resolution value for the calls above? If so, how would I go about detecting the change during runtime to make the adjustment to the resolution value?

Thanks in advance...

Shayne
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Shayne,

If you call getSample() on your center point, the result will include a resolution value that probably makes sense to use for calculating your normal.


Glenn Waldron / Pelican Mapping
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Okay. Thanks for that feedback.

I had thought about doing both the getSample() and sampleMapCoords() calls but I didn't know if issuing two calls would incur some overhead vs one call.

On a related note, is the ElevationPool() thread-safe? I'm wondering if I need to protect it like the deprecated ElevationQuery() object...

Thanks

Shayne
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Yes, ElevationPool is thread-safe.
Glenn Waldron / Pelican Mapping
2LR 2LR
Reply | Threaded
Open this post in threaded view
|

Re: Terrain normal and ElevationPool

Perfect.

Thanks for letting me know and thanks for taking the time to help.

Shayne