Steep Parallax Mapping

Hey everyone, I implemented lately Steep Parallax mapping for the lighting material.



Standard parallax mapping looks fine as long as the parallax height is not too high and as long as you don’t look at it from a steep angle.

Steep parallax mapping addresses those two issues.

here is a video to understand the difference

http://www.youtube.com/watch?v=d4PBw35mU2E



At the beginning of the video it's standard parallax, the rocks that are near the camera are fine but distant rocks are very flat. Also when raising the height there is quickly some glitches at the base of the rocks that make it look weird.
Then switching to Steep parallax. As you can see rocks look more like 3D objects, and the height can be pushed a lot more giving a real relief impression.
This impression does not fade at steep angles.

Note that the ground is a grid and not a quad. Parallax mapping on a big quad does not work well because the camera direction is computed to each vertex. so when you are near the center and very close to the surface, the computed camera direction is wrong.

Of course there are some draw backs, it's a lot more fps greedy than the classic parallax mapping especially at hi resolutions. it's not that noticeable in the video because it's low res, and fraps is eating his share of fps.

So use it wisely, sometimes standard parallax is enough, especially when you look at a surface at high angle.

To enable it you have to set the SteepParallax boolean parameter to true on the lighting material.
You can also now tweak the parallax height by setting the ParallaxHeight float parameter, the default is 0.05.

On a side note, you can now use normal and parallax maps packed together. Parallax map is a grey scale map that can be stored in one 8 bits channel. using a complete texture (at least 3 8bits channels) is a waste of memory.
you can now store the parallax map in the alpha channel of the normal map, you can do that in any good image editor. This was already implemented in the shader, but there was no way for the user to specify that data were stored that way.
if you use such a map be sure to set the PackedNormalParallax boolean parameter to true in the material.
10 Likes

The floor! IT’S ALIVE! :smiley:



Very nice. :slight_smile:

Wow cool :wink:

Does the soil needs to be pre-subdivided? The results looks like the unigine floors http://www.youtube.com/watch?v=9F6zSgtRnkE.

oh snap thats sweet

stomrage said:
Does the soil needs to be pre-subdivided? The results looks like the unigine floors http://www.youtube.com/watch?v=9F6zSgtRnkE.

I needs to be moderately subdivided, in this example it's 32 x 32 grid, but i think a 16 x 16 could be enough. Also things could be done to make it work on a quad, but it would be slower.
It would fit better in a deferred rendering process
Uningine use hardware tesselation, it one step further parallax mapping, the meshes are tesselated on the GPU on the fly and the reliefs is rendered using a displacement map (really like it's done fro the terrain system).
They use it for the dragon though, maybe the floor is made using parallax yes... I guess it's cheaper than hardware tesselation.

Edit : No looking at their web site http://unigine.com/press-releases/091022-heaven_benchmark/ it's really full hardware tesselation
1 Like

16 x 16 I think it’s really a small subdivision in view of the final effect. Tesselation seems to be hard to implement. But the results is just awesome. The parallax mapping needs less performance than the tessellation. Indeed, i download the unigine benchmark and my computer seems to be in trouble… I forgot, thank you for this great material.

Are there some assets missing?


WARNUNG: Cannot locate Models/WaterTest/WaterTest.material for model Models/WaterTest/WaterTest.mesh.xml
21.08.2011 20:31:22 com.jme3.app.Application handleError
SCHWERWIEGEND: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
com.jme3.asset.AssetNotFoundException: BaseWhite.material
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:236)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:281)
at com.jme3.scene.plugins.ogre.MeshLoader.applyMaterial(MeshLoader.java:219)
at com.jme3.scene.plugins.ogre.MeshLoader.startSubMesh(MeshLoader.java:278)
at com.jme3.scene.plugins.ogre.MeshLoader.startElement(MeshLoader.java:616)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at com.jme3.scene.plugins.ogre.MeshLoader.load(MeshLoader.java:830)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:240)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:281)
at jme3test.material.TestParallax.setupFloor(TestParallax.java:85)
at jme3test.material.TestParallax.simpleInitApp(TestParallax.java:118)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:230)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:124)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:200)
at java.lang.Thread.run(Unknown Source)

To be honest , I couldn’t get the difference.

From my readings the two terms mix up, and in the ends, it seams to be the same.

In the first link, they have a self shadowing feature, but he mapping algorithm is pretty much the same.

@nehon you are really cool!!! That’s amazing!!!



I red an article about parallax on blendernation.

Poassibly it will be useful in som e kind: http://www.blendernation.com/2011/08/08/parallax-mapping-with-nodes-in-realtime/

mifth said:
@nehon you are really cool!!!! That's amazing!!!

lol thank you :p

btw, if you want to integrate this in your light shader, look at the parallax.glsllib, it contains 2 methods one for steep one for classic. they return the offset texture coordinates, so I guess you could integrate it with almost no effort.
2 Likes

Thank you!!! I’ll integrate it!

well done nehon, at last now jme has correct parallax maps.



It would be nice to do the following :


  1. if distance from camera < 2 meters use steep parallax maps.
  2. else use simple parallax maps.



    (avoids artifacts, performance issues)



    I may try it on my game, when i have time.
tralala said:
well done nehon, at last now jme has correct parallax maps.

It would be nice to do the following :

1) if distance from camera < 2 meters use steep parallax maps.
2) else use simple parallax maps.

(avoids artifacts, performance issues)

I may try it on my game, when i have time.

well the switch would be very obvious and glitchy, there is already an optimization according to distance from the cam.
I'm still looking on how to optimize it a bit more so that from a distance the perf would be the same...
1 Like

and what about optimize?



the one from survivor(maybe from here: http://www.ogre3d.org/forums/viewtopic.php?f=11&t=42706&start=0)

http://code.google.com/p/survivor-jme/downloads/list



looks fine, but it would need some image sampling filter / mipmap or somthin to looking more smooth.



@nehon: Could you just implement this with some predefined image sampling filter?

Or is there a way in jme to set image sampling?

I don’t get what you mean by “image sampling filter”

1 Like

I think he means interpolation for the image map values.

1 Like

yes yes, interpolation :slight_smile:



maybe i do somethin wrong, i think i used diffrent parallax map or somethin, but btw i get a good output until low angle:



screen from SceneComposer

http://desmond.imageshack.us/Himg607/scaled.php?server=607&filename=lowangle.gif&res=medium



i used light material with diffuse and parallax.



and i cant run JME TestParallax becouse my graphic is crap:

extension 'GL_EXT_gpu_shader4' is not supported


so i cant compare. What could i do wrong? and if JmeTest need 'GL_EXT_gpu_shader4', then why my test dont need if i only use light MaterialDef.

That’s just a warning. The shader should fallback gracefully:

[java]

#extension GL_EXT_gpu_shader4 : enable

#extension GL_ATI_shader_texture_lod : enable



float getHeightSample(const in vec2 texCoord)

{

#if defined(PARALLAXMAP)

return texture2D(m_ParallaxMap, texCoord).r;

#elif defined(NORMALMAP_PARALLAX)

return texture2D(m_NormalMap, texCoord).a;

#endif

}



#ifdef GL_ATI_shader_texture_lod

float getHeightSample(const in vec2 texCoord, const in float lod)

{

#if defined(PARALLAXMAP)

return texture2DLod(m_ParallaxMap, texCoord, lod).r;

#elif defined(NORMALMAP_PARALLAX)

return texture2DLod(m_NormalMap, texCoord, lod).a;

#endif

}

#endif



#ifdef GL_EXT_gpu_shader4

float getHeightSample(const in vec2 texCoord, const in vec2 dx, const in vec2 dy)

{

#if defined(PARALLAXMAP)

return texture2DGrad(m_ParallaxMap, texCoord, dx, dy).r;

#elif defined(NORMALMAP_PARALLAX)

return texture2DGrad(m_NormalMap, texCoord, dy, dy).a;

#endif

}

#endif



float getHeightSampleEx(const in vec2 texCoord)

{

#if defined(USE_TEXTURE2D_GRAD) && defined(GL_EXT_gpu_shader4)

return getHeightSample(texCoord, dx, dy);

#elif defined(USE_TEXTURE2D_LOD) && defined(GL_ATI_shader_texture_lod)

return getHeightSample(texCoord, fMipLevel);

#else

return getHeightSample(texCoord);

#endif

}

[/java]



Also make sure to checkout the latest version from SVN. I’m a bit lazy in making download packages lately.



The issue in your image is a fixed bug.

1 Like

i was not using nightly(i forgot about it), but updating to nightly work(jme testcase work perfectly) :wink:



Thank you, and sorry for a simple problem. I should think about update, before write posts…



edit:

i know Terrain system is based on alphamaps, but there should be way to easy implement parallax for some of terrain textures(via SDK terrain editor and in code terrainLighting). is it possible?



but nvm, its just a idea