[Solved] Wrong normals without a normal map?

Before I untangle my code and create a test case I just wanted a quick check if someone recognize this and can tell me if my expectations are wrong.



I’m on jME nightly, create a terrain (in code) and texture it using a splat map and 4 textures (TerrainLighting material). Two of those textures have normal maps, two don’t. Here is an excerpt of the code showing two textures (the other are the same type of code), it is basically the hello terrain-tutorial:



[java]

/** Add the blue layer /

Texture blue = assetManager.loadTexture(

“Textures/carbondioxide.png”);

blue.setWrap(WrapMode.Repeat);

mat_terrain.setTexture(“DiffuseMap_2”, blue);

mat_terrain.setFloat(“DiffuseMap_2_scale”, 1f / 16f);

Texture blueNorm = assetManager.loadTexture(

“Textures/waterice.png”);

mat_terrain.setTexture(“NormalMap_2”, blueNorm);



/
* Add the alpha layer */

Texture alpha = assetManager.loadTexture(

“Textures/anorthosite.png”);

alpha.setWrap(WrapMode.Repeat);

mat_terrain.setTexture(“DiffuseMap_3”, alpha);

mat_terrain.setFloat(“DiffuseMap_3_scale”, 1f / 16f);



mat_terrain.setBoolean(“useTriPlanarMapping”, true);

[/java]



The strange thing is that the last texture going into the alpha channel gets darker when facing the directional light. Like this picture:



http://imgur.com/glyeK



But if I add a single line to set the normal map (even reusing the one from the material above) like so:

[java]mat_terrain.setTexture(“NormalMap_3”, blueNorm);[/java]



It looks right:



<a href="http://imgur.com/qN7S7>http://imgur.com/qN7S7



Is this expected and if I use normal maps all channels should have one?

Does this happen if you turn off tri-planar mapping? This definitely isn’t an intended feature, but I haven’t noticed it do it before.

I can’t launch any of the tests right now without my computer restarting, thank you ATI drivers. So I gotta dig for a previous driver that worked. Might take me a little bit.

@Sploreg said:
Does this happen if you turn off tri-planar mapping? This definitely isn't an intended feature, but I haven't noticed it do it before.
I can't launch any of the tests right now without my computer restarting, thank you ATI drivers. So I gotta dig for a previous driver that worked. Might take me a little bit.


Don't rush it, I need a day or so to make a test case and when I do I usually find out that I did something stupid. So save yourself the trouble and wait for a test case :)

Sure a test case could help, I would have something to test from then and to compare screenshots. Of course when my drivers are working again. I’m trying video driver #3 now… f u ATI

Yeah I’ve heard … that about ATI before. Anyway, It is always useful writing a test case because I found out what was wrong and it was my fault. The normal maps were inverted when I exported them from NeoTexture, I think maybe one of the channels needs to be inverted.

I didn’t see it at first because I didn’t look close enough. But it looks like the splat-channels are separated and nothing is “left over” from some other channels normal maps. They can be set separately as expected. So the only error to report is “User error” :slight_smile:



While testing I found out that also the normal maps in the jME test-data are inverted.







The grey area is a grey image diffuse map without normal map. The green area is a green diffuse image and it also has the test-data “Textures/Terrain/splat/road_normal.png” as a normal map which causes the lighting to be bright on the wrong side of the ridge.



Don’t know what to make of that, if the shader is off or if NeoTexture does it wrong.

@Sploreg said:
I'm trying video driver #3 now... f u ATI


This is why I've ditched ATI years ago. I used to be a fan, but... let's just not go there. Blacklisted.
@madjack said:
This is why I've ditched ATI years ago. I used to be a fan, but... let's just not go there. Blacklisted.


They are good for testing cards that break easily. :)

Inverted how? Tangent-space normal maps don’t really invert, they have a range of 0…1.

EDIT: I take that back, I guess the image could be inverted. But I don’t see that in the normal maps that come with jme. I also don’t see the inverted light that is showing up in your screenshot. I’m not ruling out there being a problem though.

Yes it seems pretty strange that I’d be the only one to see that the maps were inverted, it seems more likely that it is just me having some weird code or setup. I’ll have to look into what it is I actually do. But if anyone is interested here is the test case I used.

[java]package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.light.AmbientLight;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Node;

import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.terrain.geomipmap.TerrainQuad;

import com.jme3.terrain.heightmap.AbstractHeightMap;

import com.jme3.terrain.heightmap.ImageBasedHeightMap;

import com.jme3.texture.Image;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import com.jme3.texture.Texture2D;

import com.jme3.texture.plugins.AWTLoader;

import java.awt.image.BufferedImage;



/**

  • test
  • @author normenhansen

    /

    public class Main extends SimpleApplication {



    private TerrainQuad terrain;

    private Material mat_terrain;

    private Vector3f lightDirection;

    private DirectionalLight sun;



    public static void main(String[] args) {

    Main app = new Main();

    app.start();

    }



    @Override

    public void simpleInitApp() {

    flyCam.setMoveSpeed(150);

    Texture dirtNormal = assetManager.loadTexture(

    "Textures/Terrain/splat/road_normal.png");

    dirtNormal.setWrap(WrapMode.Repeat);



    /
    * 1. Create terrain material and load four textures into it. /

    mat_terrain = new Material(assetManager,

    "Common/MatDefs/Terrain/TerrainLighting.j3md");



    /
    * 1.1) Add ALPHA map (for red-blue-green coded splat textures) /

    AWTLoader awtLoader = new AWTLoader();

    Image alphaTextureImage = awtLoader.load(createFromRGBAValue(), true);

    Texture alphaTexture = new Texture2D(alphaTextureImage);

    mat_terrain.setTexture("AlphaMap", alphaTexture);



    /
    * 1.2) Add the red layer (Tex1). /

    Texture redLayer = assetManager.loadTexture(

    "Textures/red.png");

    redLayer.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture("DiffuseMap", redLayer);

    mat_terrain.setFloat("DiffuseMap_0_scale", 16f);



    /
    * 1.3) Add the green layer (Tex2) /

    Texture greenLayer = assetManager.loadTexture(

    "Textures/green.png");

    greenLayer.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture("DiffuseMap_1", greenLayer);

    mat_terrain.setFloat("DiffuseMap_1_scale", 128f);

    mat_terrain.setTexture("NormalMap_1", dirtNormal);



    /
    * 1.4) Add the blue layer (Tex3) /

    Texture blueLayer = assetManager.loadTexture(

    "Textures/blue.png");

    blueLayer.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture("DiffuseMap_2", blueLayer);

    mat_terrain.setFloat("DiffuseMap_2_scale", 16f);





    /
    * Add the alpha layer /

    Texture greyLayer = assetManager.loadTexture(

    "Textures/grey.png");

    greyLayer.setWrap(WrapMode.Repeat);

    mat_terrain.setTexture("DiffuseMap_3", greyLayer);

    mat_terrain.setFloat("DiffuseMap_3_scale", 16f);



    /
    * 2. Create the height map /

    AbstractHeightMap heightmap = null;

    Texture heightMapImage = assetManager.loadTexture(

    "Textures/Terrain/splat/mountains512.png");

    heightmap = new ImageBasedHeightMap(heightMapImage.getImage());

    heightmap.load();



    /
    * 3. We have prepared material and heightmap.
  • Now we create the actual terrain:
  • 3.1) Create a TerrainQuad and name it "my terrain".
  • 3.2) A good value for terrain tiles is 64x64 – so we supply 64+1=65.
  • 3.3) We prepared a heightmap of size 512x512 – so we supply 512+1=513.
  • 3.4) As LOD step scale we supply Vector3f(1,1,1).
  • 3.5) We supply the prepared heightmap itself.

    /

    int patchSize = 65;

    terrain = new TerrainQuad("my terrain", patchSize, 513, heightmap.getHeightMap());



    /
    * 4. We give the terrain its material, position & scale it, and attach it. /

    terrain.setMaterial(mat_terrain);

    terrain.setLocalTranslation(0, -100, 0);

    terrain.setLocalScale(2f, 1f, 2f);

    rootNode.attachChild(terrain);



    /
    * 5. The LOD (level of detail) depends on were the camera is: */

    TerrainLodControl control = new TerrainLodControl(terrain, getCamera());

    terrain.addControl(control);



    setupLight(rootNode);



    }



    private void setupLight(Node rootNode) {

    lightDirection = new Vector3f(1, -1, 0).normalizeLocal();

    sun = new DirectionalLight();

    sun.setDirection(lightDirection);

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

    rootNode.addLight(sun);

    AmbientLight ambientLight = new AmbientLight();

    ambientLight.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f));

    rootNode.addLight(ambientLight);

    }



    @Override

    public void simpleUpdate(float tpf) {

    //TODO: add update code

    }



    @Override

    public void simpleRender(RenderManager rm) {

    //TODO: add render code

    }



    protected BufferedImage createFromRGBAValue() {

    BufferedImage image = new BufferedImage(512, 512, BufferedImage.TYPE_INT_ARGB);

    for (int x = 0; x < 255; x++) {

    for (int y = 0; y < 255; y++) {



    setPixel(255, 0, 0, 0, image, x, y);

    setPixel(0, 255, 0, 0, image, x + 255, y);

    setPixel(0, 0, 255, 0, image, x, y + 255);

    setPixel(0, 0, 0, 255, image, x + 255, y + 255);

    }

    }

    return image;

    }



    private void setPixel(int alpha, int red, int green, int blue, BufferedImage image, int x, int y) {

    int rgb = ((alpha << 24) & 0xff000000)

    | ((red << 16) & 0x00ff0000)

    | ((green << 8) & 0x0000ff00)

    | (blue & 0x000000ff);



    image.setRGB(x, y, rgb);

    }

    }[/java]

Haha, I like what the forum smilie function does in line 155 :stuck_out_tongue:

Yea it is pretty 8)

Ok well going through all of this I did fix a long-outstanding bug where if you didn’t have a normal map at the base texture layer but had normal maps above it, you would get blackened sections. That should all behave better now.

1 Like
@Sploreg said:
Ok well going through all of this I did fix a long-outstanding bug where if you didn't have a normal map at the base texture layer but had normal maps above it, you would get blackened sections. That should all behave better now.


Sweet :) I tried around a lot but none of my ramblings lead anywhere, it had nothing to do with the color channels in the normal map. But this could very well fix it, the blackened sections sounds exactly like the problem I had, thanks :D