title: Parralax mapping does not work correctly using OpenGL and GLSL
body: <p>I try to implement parralax mapping in my 3D engine using OpenGL and GLSL API but the display is not correct. To learn and apply the complexity of a such technique I was inspired by the following PDF tutorial (page 16, 17 and 18):</p>
  
  <p><a href="https://www.opengl.org/sdk/docs/tutorials/TyphoonLabs/Chapter_4.pdf" rel="nofollow noreferrer">https://www.opengl.org/sdk/docs/tutorials/TyphoonLabs/Chapter_4.pdf</a></p>
  
  <p>To produce a very basic parralax effect (without any lighting effect) I need to use 2 textures:</p>
  
  <pre><code>- 1 diffuse (color) texture (BPP: 24 -&gt; RGB - format: JPEG)
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/IilC7.jpg" alt="enter image description here"></p>
  
  <pre><code>- 1 displacement (height/grayscale) texture (BPP: 24 -&gt; RGB - format: JPEG)
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/H2qY9.jpg" alt="enter image description here"></p>
  
  <p>I used the famous and very usefull software 'CrazyBump' to generate my displacement map. Plus this software can display a 3D view of what the parralax mapping will look like in an external 3D application like mine.</p>
  
  <p>In a first time, Here's the display from 'CrazyBump' (CrazyBump use lighting effect but it's not important here):</p>
  
  <p><img src="https://i.stack.imgur.com/nGsvg.png" alt="enter image description here"></p>
  
  <p>As you can see the parralax effect is correctly rendered.</p>
  
  <p>And now here's the rendering in my scene (using the same displacement texture generated by 'CrazyBump' and without luminosity. All I want to see is the fake deformation of the surface like above).</p>
  
  <p><img src="https://i.stack.imgur.com/Fgwx1.png" alt="enter image description here"></p>
  
  <p>As you can see, the display is not the same and of course not correct.</p>
  
  <p>To try producing the same effect I apply the course in the PDF file I talked about at the beginning of my post.</p>
  
  <p>For informations, I have already implemented 'normmal mapping' technique previously for my engine (so the tangent and bitangent vectors are correct!).</p>
  
  <p>To execute my shader program I need the position of the camera in world space and matrices (ModelViewProj, ModelMatrix and NormalMatrix).</p>
  
  <p>Here's the client C++ code I use:</p>
  
  <pre><code>glm::mat4 modelViewMatrix = pRenderBatch-&gt;GetModelViewMatrix();
  
  glm::mat3 normalMatrix = glm::mat3(glm::vec3(modelViewMatrix[0]),
      glm::vec3(modelViewMatrix[1]), glm::vec3(modelViewMatrix[2]));
  
  this-&gt;SetUniform("ModelViewProjMatrix", pRenderBatch-&gt;GetModelViewProjMatrix());
  this-&gt;SetUniform("ModelViewMatrix", modelViewMatrix);
  this-&gt;SetUniform("NormalMatrix", normalMatrix);
  
  //Bound on channel 0
  glActiveTexture(GL_TEXTURE0);
  this-&gt;m_pTextureManager.PushAndBindTexture(
      pMaterial-&gt;GetDiffuseTexture());
  {
      this-&gt;SetUniform("DiffuseSampler", 0);
  }
  //Bound on channel 1
  glActiveTexture(GL_TEXTURE1);
      this-&gt;m_pTextureManager.PushAndBindTexture(
          pMaterial-&gt;GetDisplacementTexture());
  {
      this-&gt;SetUniform("HeightSampler", 1);
  }
  </code></pre>
  
  <p>The Vertex Shader:</p>
  
  <pre><code>#version 440
  
  /*
  ** Vertex attributes.
  */
  layout (location = 0) in vec4 VertexPosition;
  layout (location = 1) in vec2 VertexTexture;
  layout (location = 2) in vec3 VertexNormal;
  layout (location = 3) in vec3 VertexTangent;
  layout (location = 4) in vec3 VertexBitangent;
  
  /*
  ** Uniform matrices.
  */
  uniform mat4 ModelViewProjMatrix;
  uniform mat4 ModelViewMatrix;
  uniform mat3 NormalMatrix;
  
  //Outputs
  out vec2 TexCoords;
  out vec3 viewDir_TS;
  
  /*
  ** Vertex shader entry point.
  */
  void main(void)
  {
      //Texture coordinates
      TexCoords = VertexTexture;
  
      //Vertex position in world space
      vec3 Position_CS = vec3(ModelViewMatrix * VertexPosition);
      //Vertex normal in world space
      vec3 Normal_CS = NormalMatrix * VertexNormal;
      //Vertex tangent in world space
      vec3 Tangent_CS = NormalMatrix * VertexTangent;
      //Vertex bitangent in world space
      vec3 Bitangent_CS = NormalMatrix * VertexBitangent;
  
      //View vector in world space
      vec3 viewDir_CS = -Position_CS;
  
      //TBN matrix
      mat3 TBN =  mat3(
          Tangent_CS.x, Bitangent_CS.x, Normal_CS.x,
          Tangent_CS.y, Bitangent_CS.y, Normal_CS.y,
          Tangent_CS.z, Bitangent_CS.z, Normal_CS.z);
  
      //2 others ways to compute view vector in tangent space
  
          //mat3 TBN = transpose(mat3(Tangent_CS, Bitangent_CS, Normal_CS));
  
          /*viewDir_TS = vec3(
              dot(viewDir_CS, Tangent_CS),
              dot(viewDir_CS, Bitangent_CS),
              dot(viewDir_CS, Normal_CS)
          );*/
  
      //View vector converted in tangent space (not normalized)
      viewDir_TS = TBN * viewDir_CS;
  
      gl_Position = ModelViewProjMatrix * VertexPosition;
  }
  </code></pre>
  
  <p>And finally the Fragment Shader:</p>
  
  <pre><code>#version 440
  
  layout (location = 0) out vec4 FragColor;
  
  //Texture coordinates
  in vec2 TexCoords;
  
  //View (camera) vector in tangent space
  in vec3 viewDir_TS;
  
  //Diffuse texture sampler
  uniform sampler2D DiffuseSampler;
  //Displacement texture sampler
  //(height map/grayscale map)
  uniform sampler2D HeightSampler;
  
  /*
  ** Fragment shader entry point
  */
  void main(void)
  {
      //Parralax intensity {scale(s), bias(b)}
      vec2 ScaleBias = vec2(0.04f, 0.02f);
  
      //Height(h) range [0;1] (float) recovered from height map (HeightSampler)
      float Height = texture2D(HeightSampler, TexCoords.st).r; 
  
      //Height scaled and biased according to the formula: hsb = h · s + b
      float HSB = Height * ScaleBias.x + ScaleBias.y;
  
      //View vector in tangent space normalized
      vec3 viewDirNorm_TS = normalize(viewDir_TS);
  
      //Computes texture offset according to the formula: Tn = To + (hsb · V{x, y}) 
      vec2 textOffset = TexCoords + (viewDirNorm_TS.xy * HSB);
  
      //Computes final diffuse texture color using parralax offset
      FragColor = texture2D(DiffuseSampler, textOffset);
  }
  </code></pre>
  
  <p>I tried to modify the scale and bias values without any success: the displays is still not correct.</p>
  
  <p>I thought my displacement texture was not correctly loaded but it's not the case (for information I use the NVIDIA NSight degugger).</p>
  
  <p><img src="https://i.stack.imgur.com/cgy6D.png" alt="enter image description here"></p>
  
  <p>If I load my displacement map the following manner (GL_LUMINANCE):</p>
  
  <pre><code>glTexImage2D(this-&gt;m_Target, 0, GL_LUMINANCE,
      this-&gt;m_PixelData.GetWidth(), this-&gt;m_PixelData.GetHeight(),
              0, GL_BGR, GL_UNSIGNED_BYTE, OFFSET_BUFFER(0));
  </code></pre>
  
  <p>The pixel buffer begins by:</p>
  
  <p><img src="https://i.stack.imgur.com/iKmqe.png" alt="enter image description here"></p>
  
  <p>And if I load my displacement map the following manner (GL_RGB):</p>
  
  <p>glTexImage2D(this->m_Target, 0, GL_RGB,
          this->m_PixelData.GetWidth(), this->m_PixelData.GetHeight(),
                  0, GL_BGR, GL_UNSIGNED_BYTE, OFFSET_BUFFER(0));</p>
  
  <p>The pixel buffer begins by:</p>
  
  <p><img src="https://i.stack.imgur.com/gQ8iV.png" alt="enter image description here"></p>
  
  <p>In these two cases we have grayscale pixels.</p>
  
  <p>So my problem does not seem to comes from the texture loaded in memory. Maybe there is a problem with the matrices or a problem of space. I'm really lost.</p>
  
  <p>Does anyone can help me, please ?</p>
  
  <p>Thanks so much in adavance for your help!</p>