2013-11-29 5 views
1

Я пытаюсь реализовать отображение рельефа на кубе с использованием OpenGL и GLSL. Однако, когда я поворачиваю свой куб вокруг, появляются только квадрат с правой стороны и правый квадрат (т. Е. В отрицательном x и положительном направлении x), остальные четыре стороны куба (сверху, снизу, спереди, сзади) являются черными. Ниже приведен пример:Bump Mapping в OpenGL и GLSL

enter image description here

Мой класс сетка состоит из indexList и vertexList (класс вершинных содержит х, Y, Z, и т.д.). Я использую this простую модель cube.ply, которая содержит s, t текстурных координат. Заимствования из this example, рассчитать касательные векторы следующим образом:

void Mesh::computeTangents() { 

     for (size_t i = 0; i < m_indexList.size(); i += 3) { 

      Vertex v1 = m_vertexList[m_indexList[i]]; 
      Vertex v2 = m_vertexList[m_indexList[i+1]]; 
      Vertex v3 = m_vertexList[m_indexList[i+2]]; 

      glm::vec3 pos1 = glm::vec3(v1.getX(), v1.getY(), v1.getZ()); 
      glm::vec3 pos2 = glm::vec3(v2.getX(), v2.getY(), v2.getZ()); 
      glm::vec3 pos3 = glm::vec3(v3.getX(), v3.getY(), v3.getZ()); 
      glm::vec2 tex1 = glm::vec2(v1.getS(), v1.getT()); 
      glm::vec2 tex2 = glm::vec2(v2.getS(), v2.getT()); 
      glm::vec2 tex3 = glm::vec2(v3.getS(), v3.getT()); 

      glm::vec3 edge1 = glm::normalize(pos2 - pos1); 
      glm::vec3 edge2 = glm::normalize(pos3 - pos1); 

      glm::vec2 texEdge1 = glm::normalize(tex2 - tex1); 
      glm::vec2 texEdge2 = glm::normalize(tex3 - tex1); 

      float det = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x); 

      glm::vec3 tangent; 

      if(fabsf(det) < 1e-6f) { 
       tangent.x = 1.0; 
       tangent.y = 0.0; 
       tangent.z = 0.0; 
      } 
      else { 
       det = 1.0/det; 

       tangent.x = (texEdge2.y * edge1.x - texEdge1.y * edge2.x) * det; 
       tangent.y = (texEdge2.y * edge1.y - texEdge1.y * edge2.y) * det; 
       tangent.z = (texEdge2.y * edge1.z - texEdge1.y * edge2.z) * det; 

       glm::normalize(tangent); 
      } 

      m_vertexList[m_indexList[i]].setTanX(tangent.x); 
      m_vertexList[m_indexList[i]].setTanY(tangent.y); 
      m_vertexList[m_indexList[i]].setTanZ(tangent.z); 
      m_vertexList[m_indexList[i+1]].setTanX(tangent.x); 
      m_vertexList[m_indexList[i+1]].setTanY(tangent.y); 
      m_vertexList[m_indexList[i+1]].setTanZ(tangent.z); 
      m_vertexList[m_indexList[i+2]].setTanX(tangent.x); 
      m_vertexList[m_indexList[i+2]].setTanY(tangent.y); 
      m_vertexList[m_indexList[i+2]].setTanZ(tangent.z); 
     } 
    } 

Если я выводить значения касательного вектора для каждого треугольника, я получаю эти значения:
1, 0, 0
1, 0, 0
0, 0, -1
0, 0, -1
0, 0, 1
0, 0, 1
-1, 0, 0
-1, 0, 0,
1, 0, 0
1, 0, 0
1, 0, 0
1, 0, 0

Если это правильно, то проблема, скорее всего, в затенении. Мой шейдер выглядит следующим образом (в основном взято из книги):

верт:

attribute vec4 vertexPosition; 
attribute vec3 vertexNormal; 
attribute vec2 vertexTexture; 
attribute vec3 vertexTangent; 

varying vec2 texCoord; 
varying vec3 viewDirection; 
varying vec3 lightDirection; 

uniform vec3 diffuseColor; 
uniform float shininess; 
uniform vec4 lightPosition; 

uniform mat4 modelViewMatrix; 
uniform mat4 normalMatrix; 
uniform mat4 MVP; // modelview projection 

void main() { 
    vec4 eyePosition = modelViewMatrix * vertexPosition; 
    vec3 N = normalize(vec3(normalMatrix * vec4(vertexNormal, 1.0))); 
    vec3 T = normalize(vec3(normalMatrix * vec4(vertexTangent, 1.0))); 
    vec3 B = normalize(cross(N, T)); 

    vec3 v; 
    v.x = dot(lightPosition.xyz, T); 
    v.y = dot(lightPosition.xyz, B); 
    v.z = dot(lightPosition.xyz, N); 
    lightDirection = normalize(v); 

    v.x = dot(eyePosition.xyz, T); 
    v.y = dot(eyePosition.xyz, B); 
    v.z = dot(eyePosition.xyz, N); 
    viewDirection = normalize(v); 

    texCoord = vertexTexture; 
    gl_Position = MVP * vertexPosition; 
} 

Frag:

varying vec2 texCoord; 
varying vec3 viewDirection; 
varying vec3 lightDirection; 

uniform vec3 diffuseColor; 
uniform float shininess; 

void main() { 

    float bumpDensity = 16.0; 
    float bumpSize = 0.15; 

    vec2 c = bumpDensity * texCoord; 
    vec2 p = fract(c) - vec2(0.5); 

    float d, f; 
    d = dot(p, p); 
    f = 1.0/sqrt(d + 1.0); 

    if (d >= bumpSize) { 
     p = vec2(0.0); 
     f = 1.0; 
    } 

    vec3 normalDelta = vec3(p.x, p.y, 1.0) * f; 
    vec3 litColor = diffuseColor * max(dot(normalDelta, lightDirection), 0.0); 
    vec3 reflectDir = reflect(lightDirection, normalDelta); 
    float spec = max(dot(viewDirection, reflectDir), 0.0); 
    spec *= shininess; 
    litColor = min(litColor + spec, vec3(1.0)); 
    gl_FragColor = vec4(litColor, 1.0); 
} 

Edit: Изменен фон более четко видеть черное лицо. Кроме того, я неправильно заметил, какие лица на самом деле появлялись раньше.

Редактировать 2: Я обнаружил, что значение max (dot (normalDelta, lightDirection), 0.0) в шейдере фрагмента возвращает 0 для этих лиц. Тем не менее, я до сих пор не знаю, почему.

Редактировать 3: Проблема оказалась в том, что я передавал неправильный индекс касательных векторов в классе вершин. То есть, у меня было 10 в этой строке вместо 9:

glVertexAttribPointer(v3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(float) * 9)); 

ответ

1

Ладно, так что проблема в том, что любое лицо с нормальным на плоскости хг не отображается правильно, то есть те, которые являются рендеринг - это нормали по оси Y (верхняя и нижняя грани).

И ваш список касательных:

1, 0, 0 
1, 0, 0 
0, 0, -1 
0, 0, -1 
0, 0, 1 
0, 0, 1 
-1, 0, 0 
-1, 0, 0 
1, 0, 0 
1, 0, 0 
1, 0, 0 
1, 0, 0 

ли все либо вдоль оси х или г осей. Так что я предполагаю, может происходить в том, что ваши нормалей и касательных указывают на одних и тех же (или противоположных) направлениях, и в этом случае эта строка в вашем вершинного шейдера:

vec3 B = normalize(cross(N, T)); 

собирается привести vec3 (0,0, 0,0, 0.0), что не может быть нормировано.

Моя рекомендация состоит в том, чтобы попытаться вручную дать касание оси x и z вдоль оси y, если это имеет значение. Если это помогает, то вы знаете, что проблема связана с вашим вычислением касательных.

Если это не помогает, вы можете устранить неисправность, выведя значения из шейдера фрагмента в виде цветов на экране. Попробуйте отобразить viewDirection, lightDirection, normalDelta, reflectDir и все, что вы можете придумать, чтобы увидеть, какая переменная вызывает черноту.

Бонус: Переключить цвет glClear в нечто, отличное от черного? Так что это не похоже на лицо, плавающее в пространстве.

+0

Спасибо за советы. На самом деле, посмотрев на него снова, я неправильно увидел, какие лица на самом деле появляются. Оказывается, это левое лицо и правое лицо, которые появляются. Кроме того, я дважды проверил касательные значения, как вы предполагали, и я считаю, что они верны. Для каждого треугольника я вручную проверял волфрам альфа для нормального X-касательного вектора, и в каждом случае он дает правильный бинагентный вектор, который делает полную систему координат. Итак, я предполагаю (и надеюсь), я могу сузить проблему в шейдере. – Aaron

+0

Check my Edit 3. Хотя нецелесообразно публиковать весь мой код (который может содержать такие ошибки, как я заметил), ваши предложения помогли мне отладить и проверить все, что связано с касательными векторами. Благодаря! – Aaron