Normal Maps / Parallex Maps questions

Hi i have some questions :


  1. jme engine features claims that it can use “Parallax Map”, i didnt see any code / example. How to do that ?


  2. Is there a way to increase the strength/Height of Normal Maps ? My normal maps seem kinda flat, e.g when i apply them to a model it will seem like an additional texture being applied on top of existing texture, no extra height (maybe 0.1 extra height if you look from far away and with a lot of imagination). I tried it increase the image height with extrernal program but i didnt see any improvement.



    I dont know if lights is the problem, I have 2 lights (so that everything is more visible).

    [java]

    DirectionalLight sun = new DirectionalLight();

    sun.setDirection(new Vector3f(1, 0, -2).normalizeLocal());

    sun.setColor(ColorRGBA.White);

    rootNode.addLight(sun);



    AmbientLight al = new AmbientLight();

    al.setColor(ColorRGBA.White.mult(1.5f));

    rootNode.addLight(al);[/java]

Did you generate tangents?

yes i did

Just like you set the normal map with NormalMap you can set the parallax map with ParallaxMap. Though I only found out much much later that you can apparently use the alpha channel of the normal map for depth.



And just to make sure there is no confusion, you know that normal maps and parallax maps are only simulating bumps, right. The geometry is still flat. A normal map allows for dynamic shadows on the texture and a bump map displaces the texture coordinates to make things look bumpy as you move around. You probably know all that but we’d go around and around if you didn’t so I like to be sure. :slight_smile:



The JME test data includes some textures that have related normal and bump maps. They definitely work and are definitely dramatic if everything is setup right. Testing your code with them may rule out some number of issues.



…and yeah, you definitely need tangent vectors.

And with an ambient light 1.5 times greater than white… I’m surprised you see colors at all. :slight_smile:



What material are you using?

If i only used 1 light everything would be black (no colors) and only some positions would be really dark with colors.



i used neotexture lava material + normal map.



[java]Material emptyTile = new Material(assetManager, “Common/MatDefs/Light/Lighting.j3md”);

Texture emptyTexture = assetManager.loadTexture(“Textures/lava1.png”);

emptyTile.setTexture(“DiffuseMap”, emptyTexture);

Texture emptyTextureNormal = assetManager.loadTexture(“Textures/lava1_normal.png”);

emptyTile.setTexture(“NormalMap”, emptyTextureNormal);[/java]



Neotexture

My Texture



See the diffrence? mine is completely flat, forget that i said with imagination it has some height, it doesnt have no matter what. Its like i opened photoshop and appended the normal map to the diffusion map.

here how it looks if i only use the ambient light :



ambient only light

tralala said:
If i only used 1 light everything would be black (no colors) and only some positions would be really dark with colors.


That's a problem. Perhaps the light is pointing in the wrong direction? I seem to remember something about it working backwards or so.

It's ok to have an ambient light but setting it so high makes the normal map useless, I think. What happens when you set ambient to white * 0.2 or so?

The normal map will _only_ affect the lighting. A normal pointing towards the light will be brighter, pointing away will be darker... and a high ambient will wash it all out by maximize the light.

For bumps that look 3D as you move around you have to use the parallax map.
tralala said:
[java]
sun.setDirection(new Vector3f(1, 0, -2).normalizeLocal());
[/java]

Your sunlight has no y component and your quad seems to be laying flat in the x,z. If that's true then the sun will provide almost no light at all.
Also, ambient light is applied during the first real light pass... if you only have ambient then I'm surprised it rendered anything at all since Lighting.j3md will require at least one real non-ambient light.

Point Light


I used a point light and ambient light now instead of DirectionalLight.

[java]
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(0.2f));
rootNode.addLight(al);

Vector3f lightPosition = new Vector3f(0,2,0);
PointLight playerLight = new PointLight();
playerLight.setRadius(10);
rootNode.addLight(playerLight);

//...

public void simpleUpdate(float tpf)
{
playerLight.setPosition(player.localToWorld(lightPosition,null));
}
[/java]

Maybe quads cant have normal maps ? should i try with a box ?

Pretty sure that Quads can have normal maps. DirectionalLights can definitely light things up… the key is that the light must point to the quad and I’m not sure that yours was… but since I haven’t seen the quad setup I don’t know.



Can you upload your texture, normal map, and parallax map to something like imgur.com and link them here?



Also, can we see more of your code to help diagnose what’s wrong? For example, are you using a JME quad or your own mesh? Is it setup right, tangents generated, etc…



You know, trying a box couldn’t hurt… maybe the quad has no normals. At the very least, you’d be able to see which side your light was pointing. So try a Box and a DirectionalLight again.

I just double-checked the source… Quads definitely have normals. But trying a Box will help debug your lighting problems since then you can see which side is lit and adjust accordingly.

i tested it more and here is my finds :

In neotexture if i set the parallax map to nothing the lava material will become completely flat like it happens in jme. So that means that either jme has a bug in reading parallex maps or it requires a special flag to activate it.



Here is my complete code :

[java]import com.jme3.app.SimpleApplication;

import com.jme3.light.PointLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Sphere;

import com.jme3.util.TangentBinormalGenerator;



public class TestNormalMapping extends SimpleApplication

{

float angle = FastMath.HALF_PI;

PointLight pl;

Spatial lightMdl;



public static void main(String[] args)

{

TestNormalMapping app = new TestNormalMapping();

app.start();

}



@Override

public void simpleInitApp()

{

flyCam.setMoveSpeed(20);

Box box = new Box(Vector3f.ZERO,2, 2, 2);

TangentBinormalGenerator.generate(box);



Geometry boxGeom = new Geometry(“Lava”, box);

Material mat = new Material(assetManager, “Common/MatDefs/Light/Lighting.j3md”);

mat.setTexture(“DiffuseMap”, assetManager.loadTexture(“Textures/lava_diffuse.png”));

mat.setTexture(“NormalMap”, assetManager.loadTexture(“Textures/lava_normal.png”));

mat.setTexture(“SpecularMap”, assetManager.loadTexture(“Textures/lava_specular.png”));

mat.setTexture(“ParallaxMap”, assetManager.loadTexture(“Textures/lava_parallax.png”));

TangentBinormalGenerator.generate(boxGeom);



boxGeom.setMaterial(mat);

rootNode.attachChild(boxGeom);



lightMdl = new Geometry(“Light”, new Sphere(10, 10, 0.1f));

lightMdl.setMaterial(assetManager.loadMaterial(“Common/Materials/RedColor.j3m”));

rootNode.attachChild(lightMdl);



pl = new PointLight();

pl.setColor(ColorRGBA.White);

pl.setPosition(new Vector3f(0f, 0f, 4f));

rootNode.addLight(pl);

}



@Override

public void simpleUpdate(float tpf)

{

angle += tpf * 0.25f;

angle %= FastMath.TWO_PI;



pl.setPosition(new Vector3f(FastMath.cos(angle) * 4f, 0.5f, FastMath.sin(angle) * 4f));

lightMdl.setLocalTranslation(pl.getPosition());

}

}[/java]



The textures are those produced from neotexture lava example :

lava_diffuse.png

lava_normal.png

lava_parallax.png

lava_specular.png



I repeat jme completely ignores my parallax map, thats why it has no height.

Do i have to mess with one of the following parameters :

VTangent, Minnaert, WardIso, LATC,VertexLighting,UseVertexColor, LowQuality, HighQuality ?



thank you

Ok… I ran your code with the attached files.



Normal mapping is definitely working as I was able to see nice highlights as the red light goes around.



I switched to using a directional light so that I could see better without having to wait for the light to come around…



[java]

DirectionalLight sun = new DirectionalLight();

Vector3f lightDir=new Vector3f(-0.37352666f, -0.50444174f, -0.7784704f);

sun.setDirection(lightDir);

sun.setColor(new ColorRGBA(1.5f,1.5f,1.5f,1.0f));

rootNode.addLight(sun);

[/java]



Parallax is “working” but it’s backwards in one or more directions. Even the JME test apps exhibit this behavior and it makes the parallax look really odd if you are even able to notice it at all. You can see it distort and stretch the pixels at the edge of the faces… but there are also cases where I see it stretch the wrong lava flow.



I have my own copy of Lighting.j3md that I use and I ended up flipping the sign of some things to make it work right.



If you get adventurous, there is a section in JME’s Lighting.frag that looks like this:



[java]

#if defined(PARALLAXMAP) || defined(NORMALMAP_PARALLAX)

float h;

#ifdef PARALLAXMAP

h = texture2D(m_ParallaxMap, texCoord).r;

#else

h = texture2D(m_NormalMap, texCoord).a;

#endif

float heightScale = 0.05;

float heightBias = heightScale * -0.5;

vec3 normView = normalize(vViewDir);

h = (h * heightScale + heightBias) * normView.z;

newTexCoord = texCoord + (h * -normView.xy);

#else

newTexCoord = texCoord;

#endif

[/java]



I changed mine to:

[java]

#if defined(PARALLAXMAP) || defined(NORMALMAP_PARALLAX)

float h;

#ifdef PARALLAXMAP

h = texture2D(m_ParallaxMap, texCoord).r;

#else

h = texture2D(m_NormalMap, texCoord).a;

#endif

float heightScale = 0.05;

float heightBias = heightScale * -0.5;

vec3 normView = normalize(vViewDir);

h = (h * heightScale + heightBias) * normView.z;

normView.y = -normView.y;

newTexCoord = texCoord + (h * normView.xy);

#else

newTexCoord = texCoord;

#endif

[/java]



If you make your own lighting material by copying… then you can also mess with the scale if the effect isn’t dramatic enough. Though it’s already dramatic enough to cause really strange distortions for big height changes (when it’s working in the right direction).

1 Like

Your normal map does not have large details, which is why you aren’t seeing them. Only the variation between the minuscule bumps on the rocks are in the map; I’m not seeing variation in the color between the lava and rocks. A normal map with significant height variation would look like this:







Also, shadow and proper lighting helps show the normal map better.

wow at last you fixed it !!! now it looks exactly as it should.

thank you pspeed.



Which means that i think your lighting shader >>>>>>> jme’s shader.



Now i will need to declare the Strength variable to the shader to be able to change it from the code, (more customizable).

Glad it worked for you! :slight_smile:

I didn’t see this post earlier.

The problem in inverting the y component of the normal map, is as likely to work on any normal map as not inverting it.

There are many softwares that generate normal maps out there and all of them have different convention, 3ds max generate normal maps with inverted red channel compared to blender for example.

We could add some uniforms to toggle invert red, green, blue channels to fit any possible need but that’s 3 more uniform in an already quite bloated shader.



Making your own lighting shader is a fine solution for warriors like Paul, that can merge change with the trunk version, but i wouldn’t recommend it if you are not experienced with glsl.



Another easy solution is to open the normal map in photoshop/Gimp and invert the green channel (in your particular case).

Maybe we can add tools to jMP’s Texture Editor to check / take care of that.

I have no problem converting my normal map with photoshop to match jme format. The problem is that jme has float heightScale = 0.05; and doesnt allow users to set their own height. To fix this i have to create my “own” lighting shader.However making my own lighting shader isnt a solution because:

  1. everytime i update jme, the code will break and i will have to rewrite it.
  2. the solution in this thread no longer works for the current lighting.frag that has spotlights as it looks “flat” even if you change heightScale.
  3. i can use the old lighting.frag that has the heightScale however lights dont work correctly.