4

Summary

I'm trying to apply a displacement map (Height map) to a rather simple object (Hexagonal plane) and I'm having some unexpected results. I am using grayscale and as such, I was under the impression my height map should only be affecting the Z values of my mesh. However, the displacement map I've created stretches the mesh across the X and Y planes. Furthermore, it doesn't seem to use the UV mapping I've created that all other textures are successfully applied to.

Model and UV Map

Here are reference images of my hexagonal mesh and its corresponding UV map in Blender.

Hexagonal Model and UV Map

Diffuse and Displacement Textures

These are the diffuse and displacement map textures I am applying to my mesh through Three.JS.

Hexagonal Diffuse and Displacement Textures

Renders

When I render the plane without a displacement map, you can see that the hexagonal plane stays within the lines. However, when I add the displacement map it clearly affects the X and Y positions of the vertices rather than affecting only the Z, expanding the plane well over the lines.

Hexagonal Plane Renders -- With & Without Displacement Map

Code

Here's the relevant Three.js code:

    // Textures
    var diffuseTexture = THREE.ImageUtils.loadTexture('diffuse.png', null, loaded);
    var displacementTexture = THREE.ImageUtils.loadTexture('displacement.png', null, loaded);
    
    // Terrain Uniform
    var terrainShader = THREE.ShaderTerrain["terrain"];
    var uniformsTerrain = THREE.UniformsUtils.clone(terrainShader.uniforms);
    
  //uniformsTerrain["tNormal"].value = null;
  //uniformsTerrain["uNormalScale"].value = 1;
    
    uniformsTerrain["tDisplacement"].value = displacementTexture;
    uniformsTerrain["uDisplacementScale"].value = 1;
    
    uniformsTerrain[ "tDiffuse1" ].value = diffuseTexture;
  //uniformsTerrain[ "tDetail" ].value = null;
    uniformsTerrain[ "enableDiffuse1" ].value = true;
  //uniformsTerrain[ "enableDiffuse2" ].value = true;
  //uniformsTerrain[ "enableSpecular" ].value = true;

  //uniformsTerrain[ "uDiffuseColor" ].value.setHex(0xcccccc);
  //uniformsTerrain[ "uSpecularColor" ].value.setHex(0xff0000);
  //uniformsTerrain[ "uAmbientColor" ].value.setHex(0x0000cc);

  //uniformsTerrain[ "uShininess" ].value = 3;
  //uniformsTerrain[ "uRepeatOverlay" ].value.set(6, 6);
    
    // Terrain Material
    var material = new THREE.ShaderMaterial({
        uniforms:uniformsTerrain,
        vertexShader:terrainShader.vertexShader,
        fragmentShader:terrainShader.fragmentShader,
        lights:true,
        fog:true
    });
    
    // Load Tile
    var loader = new THREE.JSONLoader();
    loader.load('models/hextile.js', function(g) {
      //g.computeFaceNormals();
      //g.computeVertexNormals();
        g.computeTangents();
        g.materials[0] = material;
        
        tile = new THREE.Mesh(g, new THREE.MeshFaceMaterial());
        scene.add(tile);
    });

Hypothesis

I'm currently juggling three possibilities as to why this could be going wrong:

  1. The UV map is not applying to my displacement map.
  2. I've made the displacement map incorrectly.
  3. I've missed a crucial step in the process that would lock the displacement to Z-only.

And of course, secret option #4 which is none of the above and I just really have no idea what I'm doing. Or any mixture of the aforementioned.

Live Example

You can view a live example here.

If anybody with more knowledge on the subject could guide me I'd be very grateful!

Edit 1: As per suggestion, I've commented out computeFaceNormals() and computeVertexNormals(). While it did make a slight improvement, the mesh is still being warped.

Community
  • 1
  • 1
rrowland
  • 2,512
  • 2
  • 13
  • 31

2 Answers2

4

In your terrain material, set wireframe = true, and you will be able to see what is happening.

Your code and textures are basically fine. The problem occurs when you compute vertex normals in the loader callback function.

The computed vertex normals for the outer ring of your geometry point somewhat outward. This is most likely because in computeVertexNormals() they are computed by averaging the face normals of each neighboring face, and the face normals of the "sides" of your model (the black part) are averaged into the vertex normal calculation for those vertices that make up the outer ring of the "cap".

As a result, the outer ring of the "cap" expands outward under the displacement map.

EDIT: Sure enough, straight from your model, the vertex normals of the outer ring point outward. The vertex normals for the inner rings are all parallel. Perhaps Blender is using the same logic to generate vertex normals as computeVertexNormals() does.

vertex normals

WestLangley
  • 92,014
  • 9
  • 230
  • 236
  • I've set the wireframe, which was helpful for troubleshooting. I actually commented out `computeFaceNormals` and `computeVertexNormals` but the warping still seems to be occurring. You can verify at the [same link](https://dl.dropbox.com/u/108094925/Stack%20Overflow/Displacement%20Map/tile.html) (It has been updated). Perhaps these computations are happening elsewhere by default? – rrowland Oct 03 '12 at 20:42
  • 1
    This was a fairly deltaild answer to your original question. You have now changed the code, and the question.... Your model has normals already, so it's most likely using those, since you have commented out the normal calculation. Just learn how to set your vertex normals the way you want them. The rest of your code looks fine to me. :-) – WestLangley Oct 03 '12 at 20:59
  • It was a fairly detailed answer and I appreciate it. The only changes I made were the ones you suggested, and I made them to show that they did not actually solve the problem. I have perfectly flat plane in Blender and if the normals are being generated incorrectly I have no idea how or why. If you could help me reach the solution (Displacement displaying as intended) by perhaps updating your answer to include resources pertaining to the proper generation of vertex normals I'd really appreciate it and could consider this a complete answer. – rrowland Oct 03 '12 at 21:33
  • 2
    rrowland just search for every vertex with a zindex of 0.538017 in your model and give them vertexnormals of 0,0,1 – Gero3 Oct 03 '12 at 21:48
  • @Gero3 Thank you for chiming in. I owe you one. – WestLangley Oct 03 '12 at 22:07
  • 1
    @rrowland You ask good questions -- that I why I put in the effort to investigate it for you. But with all due respect, it is not right to add new questions after the fact. Please make a new post if you need more help. (I have not used Blender, so I can't help you with that.) – WestLangley Oct 03 '12 at 22:10
  • Thank you for further clarifying with your answer. I went through some Blender tutorials and found the normal display option which illustrated the same misdirected normals as your beautiful visualization does. I was able to resolve the issue by creating an extremely thin layer around the outside layer of planes using a subdivide and excluding it from the UV map, straightening the normals. Thank you for the assistance and I hope I didn't offend you! I would not have been able to resolve this without your detailed answer. – rrowland Oct 04 '12 at 01:19
1

The problem is how your object is constructed becuase the displacement happens along the normal vector.

the code is here.

https://github.com/mrdoob/three.js/blob/master/examples/js/ShaderTerrain.js#L348-350

"vec3 dv = texture2D( tDisplacement, uvBase ).xyz;",

This takes a the rgb vector of the displacement texture.

"float df = uDisplacementScale * dv.x + uDisplacementBias;",

this takes only red value of the vector becuase uDisplacementScale is normally 1.0 and uDisplacementBias is 0.0.

"vec3 displacedPosition = normal * df + position;",

This displaces the postion along the normal vector.

so to solve you either update the normals or the shader.

Gero3
  • 2,747
  • 1
  • 20
  • 17
  • I'd like to stick to standards and use the provided shader rather than customizing my own if possible. Would you be able to recommend a method of supplying my own normals or fixing those that are generated? – rrowland Oct 03 '12 at 20:45