title: Parallax mapping glitch in OpenGL
body: <p><img src="https://i.stack.imgur.com/9JtEH.png" alt="alt text">
  <img src="https://i.stack.imgur.com/VMh7P.png" alt="alt text"></p>
  
  <p>And this is result when I invert the tangent vector right after transferring it to vertex shader:</p>
  
  <p><img src="https://i.stack.imgur.com/GKbX2.jpg" alt="alt text">
  <img src="https://i.stack.imgur.com/6KXLP.png" alt="alt text"></p>
  
  <p><strong>The "shadow" is in the wrong place.</strong></p>
  
  <p>(And it works only when I rotate it through Y axis so the last image seem to present a good parallax mapped cube)</p>
  
  <p><strong>IM SURE IT IS NOT A TANGENT VECTOR OR TEXTURE COORDINATES PROBLEM</strong></p>
  
  <p>Because</p>
  
  <p>I used <strong>exactly the same tangent calculation functions</strong> and <strong>exactly the same cube position, normal and texture coordinate data</strong> as in working demo.
  After all, I exported arrays with position/texcoord/normal/tangent data into a .txt file and I saw what I exactly expected (and what I expected is the same pos/tex/norm data as in working demo, including calculated tangents which I managed to export from working demo).</p>
  
  <p>The next argument is, I copied my shader code to a working demo and <strong>it still works</strong>.
  Other one is, I tried multiple ways to render this cube.
  I tried VBO with glVertexAttribPointer, I tried VBO with saving tangent as other texture coordinate (as in the demo), I tried DisplayList with glVertexAttrib4f. Result is... <strong>EXACTLY THE SAME.</strong></p>
  
  <p>Height map is loading correctly, I tried to set it as a diffuse map and it looked OK.
  glGetError() gives me No Errors and shader compile logs says so.</p>
  
  <p>It is probably something with camera or init states.</p>
  
  <p>Maybe posting an init code will help.</p>
  
  <pre><code>void CDepthBase::OpenGLSet() {
  
      glEnable( GL_TEXTURE_2D );
      glShadeModel( GL_SMOOTH );
      glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
      glClearDepth( 1.0f );
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      glDepthFunc( GL_LEQUAL );
      glEnable(GL_DEPTH_TEST);
  
  
  
      glBlendFunc( GL_ONE, GL_ONE );
      GLfloat ratio;
  
      glViewport(0, 0, ResolutionWidth, ResolutionHeight);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective(45.0f, ResolutionWidth / (float)ResolutionHeight, 0.1f, 900.0f);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
  
      if (GLEW_OK != glewInit()) {
          MBX("Failed to init GLEW.", "Error");
      }
      if (glewIsSupported("GL_ARB_vertex_buffer_object")) {
          VBO_supported = true;
  
  
      } else VBO_supported = false;
  
   glHint( GL_FOG_HINT, GL_DONT_CARE );      
      glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
   glShadeModel(GL_SMOOTH);
  
      glAlphaFunc(GL_ALWAYS, 0);
  }
  </code></pre>
  
  <p>By the way, I'm using GL Extension Wrangler with extensions.</p>
  
  <p>Shader code &amp; log (this exported file contains code which was directly passed to glShaderSource):</p>
  
  <pre><code>Vertex shader was successfully compiled to run on hardware.
  
  
  Fragment shader was successfully compiled to run on hardware.
  
  Fragment shader(s) linked, vertex shader(s) linked. 
  
  
  ------------------------------------------------------------------------------------------
  
  
   varying vec3 lightDir;                                          
   varying vec3 viewDir;
   attribute vec4 tangent;
   void main() 
   { 
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
   gl_TexCoord[0] = gl_MultiTexCoord0;
   vec3 vertexPos = vec3(gl_ModelViewMatrix * gl_Vertex);
   vec3 tn = tangent.xyz;             
   vec3 n = normalize(gl_NormalMatrix * gl_Normal);
   vec3 t = normalize(gl_NormalMatrix * tangent.xyz);
   vec3 b = cross(t, n) * -tangent.w;
   mat3 tbnMatrix = mat3(t.x, b.x, n.x,
                         t.y, b.y, n.y,
                         t.z, b.z, n.z);
   lightDir = (gl_LightSource[0].position.xyz - vertexPos) / 100.0;
   lightDir = tbnMatrix * lightDir;
   viewDir = -vertexPos;
   viewDir = tbnMatrix * viewDir;
   } 
  
  -----------------------------------------------------------------------------------------
   varying vec3 lightDir;                                          
   varying vec3 viewDir;
   uniform sampler2D diffuseMap;
   uniform sampler2D normalMap;
   uniform sampler2D heightMap;
   uniform float scale;
   uniform float bias;
   void main() 
   { 
   vec3 v = normalize(viewDir);
   vec2 TexCoord = gl_TexCoord[0].st;
  {
   float height = texture2D(heightMap, gl_TexCoord[0].st).r;
   height = height * scale + bias;
   TexCoord = gl_TexCoord[0].st + (height * v.xy); 
  }
   vec3 l = lightDir;
   float atten = max(0.0, 1.0 - dot(l, l));
   l = normalize(l);
   vec3 n = normalize(texture2D(normalMap, TexCoord).rgb * 2.0 - 1.0);
   vec3 h = normalize(l + v);
   float nDotL = max(0.0, dot(n, l));
   float nDotH = max(0.0, dot(n, h));
   float power = (nDotL == 0.0) ? 0.0 : pow(nDotH, gl_FrontMaterial.shininess);
   vec4 ambient = gl_FrontLightProduct[0].ambient * atten;
   vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL * atten;
   vec4 specular = gl_FrontLightProduct[0].specular * power * atten;
   vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse + specular;color *= texture2D(diffuseMap,TexCoord);
   gl_FragColor = color ;
   } 
  </code></pre>
  
  <p>Uniforms are working correctly because results are the same if I switch them with constant values.
  Compiling shader:</p>
  
  <pre><code>void __Shader::import(){
      if(imported) __Shader::~__Shader();
  
          v = glCreateShader(GL_VERTEX_SHADER);
          f = glCreateShader(GL_FRAGMENT_SHADER); 
  
  
          glShaderSource(v, 1, (const GLchar **)&amp;vsrc.cstr,NULL);
          glShaderSource(f, 1, (const GLchar **)&amp;fsrc.cstr,NULL);
  
          glCompileShader(v);
          glCompileShader(f);
  
          p = glCreateProgram();
  
          glAttachShader(p,v);
          glAttachShader(p,f);
  
          if(_flags &amp; NORMAL_MAPPING) 
              glBindAttribLocation(p, ATTRIB_TANGENT, "tangent");
  
          glLinkProgram(p);
  
          if(_flags &amp; DIFFUSE_MAPPING) 
              diffuseUni.loc = glGetUniformLocation(p, "diffuseMap");
          if(_flags &amp; NORMAL_MAPPING) 
              normalUni.loc = glGetUniformLocation(p, "normalMap");
          if(_flags &amp; PARALLAX_MAPPING) 
              heightUni.loc = glGetUniformLocation(p, "heightMap");
          if(_flags &amp; SPECULAR_MAPPING) 
              specularUni.loc = glGetUniformLocation(p, "specularMap");
  
          imported = true;
  }
  </code></pre>
  
  <p>Setting attribute in VBO:</p>
  
  <pre><code>    if(tangents.size() &gt; 0){
          buffered |= 3;
          glGenBuffers(1, &amp;VBO_tangent);
          glBindBuffer(GL_ARRAY_BUFFER, VBO_tangent);
          glBufferData(GL_ARRAY_BUFFER, tangents.size()*sizeof(tangent), tangents.get_ptr(), GL_STATIC_DRAW);
      }
  
  // and in draw:
  
  if(buffered &amp; 3) {
  
          glBindBuffer(GL_ARRAY_BUFFER, VBO_tangent);    
          glVertexAttribPointer(__Shader::ATTRIB_TANGENT, 4, GL_FLOAT, GL_FALSE, 0, 0);   
          glEnableVertexAttribArray(__Shader::ATTRIB_TANGENT);  
      }
  </code></pre>
  
  <p>and a small note</p>
  
  <pre><code>for(int i = 0; i &lt; responders.size(); ++i)
  if(strstr(responders[i].idea, "tangent problem"))
  responders[i].please_dont_talk();
  </code></pre>
  
  <p>Just tell me your other ideas about what can be the reason of those bad results.</p>