我的法线贴图有什么问题?我认为这是我的切线

时间:2015-05-25 11:35:24

标签: c++ opengl normals bump-mapping

编辑:你可能想要从"编辑3"因为我已经解决了很多这个

这是我应用于icosphere的普通立方体贴图的屏幕截图:

enter image description here

使用以下代码生成我的立方体贴图icosphere的切线。 m_indicesstd::vectorstd::vectorm_verticesstd::vector<glm::vec3> storedTan(m_vertices.size(),glm::vec3(0,0,0)); // tangents for(int i = 0; i < m_indices.size(); i+=3) { int i1 = m_indices[i]; int i2 = m_indices[i+1]; int i3 = m_indices[i+2]; VertexData v1 = m_vertices[i1]; VertexData v2 = m_vertices[i2]; VertexData v3 = m_vertices[i3]; glm::vec3 p1 = glm::vec3(v1.position[0],v1.position[1],v1.position[2]); glm::vec3 p2 = glm::vec3(v2.position[0],v2.position[1],v2.position[2]); glm::vec3 p3 = glm::vec3(v3.position[0],v3.position[1],v3.position[2]); glm::vec3 t1 = glm::vec3(v1.tcoords[0],v1.tcoords[1],v1.tcoords[2]); glm::vec3 t2 = glm::vec3(v2.tcoords[0],v2.tcoords[1],v2.tcoords[2]); glm::vec3 t3 = glm::vec3(v3.tcoords[0],v3.tcoords[1],v3.tcoords[2]); std::function<glm::vec2(glm::vec3)> get_uv = [=](glm::vec3 STR) { float sc, tc, ma; float x = std::abs(STR.x); float y = std::abs(STR.y); float z = std::abs(STR.z); if(x > y && x > z) { if(STR.x > 0) { sc = -STR.z; tc = -STR.y; ma = STR.x; } else { sc = STR.z; tc = -STR.t; ma = STR.x; } } else if(y > z) { if(STR.y > 0) { sc = STR.x; tc = STR.z; ma = STR.y; } else { sc = STR.x; tc = -STR.z; ma = STR.y; } } else { if(STR.z > 0) { sc = STR.x; tc = -STR.y; ma = STR.z; } else { sc = -STR.x; tc = -STR.y; ma = STR.z; } } return glm::vec2((sc/std::abs(ma) + 1.0) / 2.0,(tc/std::abs(ma) + 1.0) / 2.0); }; glm::vec2 uv1 = get_uv(t1); glm::vec2 uv2 = get_uv(t2); glm::vec2 uv3 = get_uv(t3); glm::vec3 edge1 = p2 - p1; glm::vec3 edge2 = p3 - p1; glm::vec2 tedge1 = uv2 - uv1; glm::vec2 tedge2 = uv3 - uv1; float r = 1.0f / (tedge1.x * tedge2.y - tedge2.x - tedge1.y); glm::vec3 sdir((tedge2.y * edge1.x - tedge1.y * edge2.x) * r, (tedge2.y * edge1.y - tedge1.y * edge2.y) * r, (tedge2.y * edge1.z - tedge1.y * edge2.z) * r); glm::vec3 tdir((tedge1.x * edge2.x - tedge2.x * edge1.x) * r, (tedge1.x * edge2.y - tedge2.x * edge1.y) * r, (tedge1.x * edge2.z - tedge2.x * edge1.z) * r); m_vertices[i1].tangent[0] += sdir.x; m_vertices[i1].tangent[1] += sdir.y; m_vertices[i1].tangent[2] += sdir.z; m_vertices[i2].tangent[0] += sdir.x; m_vertices[i2].tangent[1] += sdir.y; m_vertices[i2].tangent[2] += sdir.z; m_vertices[i3].tangent[0] += sdir.x; m_vertices[i3].tangent[1] += sdir.y; m_vertices[i3].tangent[2] += sdir.z; storedTan[i1] += sdir; storedTan[i2] += sdir; storedTan[i3] += sdir; } for(int i = 0; i < m_vertices.size(); ++i) { glm::vec3 n = glm::vec3(m_vertices[i].normal[0],m_vertices[i].normal[1],m_vertices[i].normal[2]); glm::vec3 t = glm::vec3(m_vertices[i].tangent[0],m_vertices[i].tangent[1],m_vertices[i].tangent[2]); glm::vec3 newT = glm::normalize(t - n * glm::dot(n,t)); m_vertices[i].tangent[0] = newT.x; m_vertices[i].tangent[1] = newT.y; m_vertices[i].tangent[2] = newT.z; m_vertices[i].tangent[3] = (glm::dot(glm::cross(n,t), storedTan[i]) < 0.0f) ? -1.0f : 1.0f; } struct VertexData { GLfloat position[4]; GLfloat normal[3]; GLfloat tcoords[3]; GLfloat tangent[4]; }; tcoords。{/}

position

我的VertexData看起来像BTW:

normal

我知道当前#version 400 layout (location = 0) in vec4 in_position; layout (location = 1) in vec3 in_normal; layout (location = 2) in vec3 in_UV; layout (location = 3) in vec4 in_tangent; struct PointLight { bool active; vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; float constant; float linear; float quadratic; }; uniform mat4 model; uniform mat4 view; uniform mat4 projection; uniform mat4 lightMVP; uniform PointLight uLight; smooth out vec3 ex_UV; out vec3 ex_normal; out vec3 ex_positionCameraSpace; out vec3 ex_originalPosition; out vec3 ex_positionWorldSpace; out vec4 ex_positionLightSpace; out vec3 ex_tangent; out vec3 ex_binormal; out PointLight ex_light; void main() { gl_Position = projection * view * model * in_position; ex_UV = in_UV; ex_normal = mat3(transpose(inverse(view * model))) * in_normal; ex_positionCameraSpace = vec3(view * model * in_position); ex_originalPosition = vec3(in_position.xyz); ex_positionWorldSpace = vec3(model*in_position); ex_positionLightSpace = lightMVP * model * in_position; ex_tangent = mat3(transpose(inverse(view * model))) * in_tangent.xyz; ex_binormal = cross(ex_normal,ex_tangent); // provide the fragment shader with a light in view space rather than world space PointLight p = uLight; p.position = vec3(view * vec4(p.position,1.0)); ex_light = p; } #version 400 layout (location = 0) out vec4 color; struct Material { bool useMaps; samplerCube diffuse; samplerCube specular; samplerCube normal; float shininess; vec4 color1; vec4 color2; }; struct PointLight { bool active; vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; float constant; float linear; float quadratic; }; uniform Material uMaterial; smooth in vec3 ex_UV; in vec3 ex_normal; in vec3 ex_positionCameraSpace; in vec3 ex_originalPosition; in vec3 ex_positionWorldSpace; in vec4 ex_positionLightSpace; in vec3 ex_tangent; in vec3 ex_binormal; in PointLight ex_light; /* ****************** Provides a better lookup into a cubemap ******************* */ vec3 fix_cube_lookup(vec3 v, float cube_size) { float M = max(max(abs(v.x), abs(v.y)), abs(v.z)); float scale = (cube_size - 1) / cube_size; if (abs(v.x) != M) v.x *= scale; if (abs(v.y) != M) v.y *= scale; if (abs(v.z) != M) v.z *= scale; return v; } /* ********************* Calculates the color when using a point light. Uses shadow map ********************* */ vec3 CalcPointLight(PointLight light, Material mat, vec3 normal, vec3 fragPos, vec3 originalPos, vec3 viewDir) { // replace the normal with lookup normal. This is now in tangent space vec3 textureLookup = fix_cube_lookup(normalize(ex_originalPosition),textureSize(mat.normal,0).x); normal = texture(mat.normal,textureLookup).rgb; // the direction the light is in in the light position - fragpos // light dir and view dir are now in tangent space vec3 lightDir = transpose(mat3(ex_tangent,ex_binormal,ex_normal)) * normalize(fragPos - light.position); viewDir = transpose(mat3(ex_tangent,ex_binormal,ex_normal)) * viewDir; // get the diffuse color textureLookup = fix_cube_lookup(normalize(ex_originalPosition),textureSize(mat.diffuse,0).x); vec3 diffuseMat = vec3(0.0); if(mat.useMaps) diffuseMat = texture(mat.diffuse,textureLookup).rgb; else diffuseMat = mat.color1.rgb; // get the specular color textureLookup = fix_cube_lookup(normalize(ex_originalPosition),textureSize(mat.specular,0).x); vec3 specularMat = vec3(0.0); if(mat.useMaps) specularMat = texture(mat.specular,textureLookup).rgb; else specularMat = mat.color2.rgb; // the ambient color is the amount of normal ambient light hitting the diffuse texture vec3 ambientColor = light.ambient * diffuseMat; // Diffuse shading float diffuseFactor = dot(normal, -lightDir); vec3 diffuseColor = vec3(0,0,0); vec3 specularColor = vec3(0,0,0); if(diffuseFactor > 0) diffuseColor = light.diffuse * diffuseFactor * diffuseMat; // Specular shading vec3 reflectDir = normalize(reflect(lightDir, normal)); float specularFactor = pow(dot(viewDir,reflectDir), mat.shininess); if(specularFactor > 0 && diffuseFactor > 0) specularColor = light.specular * specularFactor * specularMat; float lightDistance = length(fragPos - light.position); float attenuation = light.constant + light.linear * lightDistance + light.quadratic * lightDistance * lightDistance; return ambientColor + (diffuseColor + specularColor) / attenuation; } void main(void) { vec3 norm = normalize(ex_normal); vec3 viewDir = normalize(-ex_positionCameraSpace); vec3 result = CalcPointLight(ex_light,uMaterial,norm,ex_positionCameraSpace, ex_positionWorldSpace,viewDir); color = vec4(result,1.0); } <S,T>都没问题(否则您将无法看到上面的屏幕截图)。

然后我的顶点着色器看起来像这样:

<U,V>

最后我的片段着色器看起来像这样:

  major axis
  direction     target                             sc     tc    ma
  ----------    -------------------------------    ---    ---   ---
   +rx          TEXTURE_CUBE_MAP_POSITIVE_X_ARB    -rz    -ry   rx
   -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_ARB    +rz    -ry   rx
   +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_ARB    +rx    +rz   ry
   -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB    +rx    -rz   ry
   +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_ARB    +rx    -ry   rz
   -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB    -rx    -ry   rz

 Using the sc, tc, and ma determined by the major axis direction as
 specified in the table above, an updated (s,t) is calculated as
 follows

    s   =   ( sc/|ma| + 1 ) / 2
    t   =   ( tc/|ma| + 1 ) / 2

 This new (s,t) is used to find a texture value in the determined
 face's 2D texture image using the rules given in sections 3.8.5
 and 3.8.6." ...

据我所知:

  1. 正在正确计算我的切线。
  2. 我的法线贴图看起来像是一张普通的地图。
  3. 我改变光线并查看切线空间的方向以匹配我的法线贴图。
  4. 结果一无所获。即没有任何东西被画到屏幕上。根本不是纯色。因此,背后的一切都是在没有遮挡的情况下绘制的。

    如果我将查找放弃到我的法线贴图中,而只是使用切线矩阵光和视图,我得到以下内容:

    enter image description here

    这是一个后处理镜头光晕,它产生了那些有趣的位和bobs。我认为重要的是来自表面的压倒性眩光,法线似乎有些准确。

    如果我只是用切线矩阵转换光线,我得到:

    enter image description here

    所有这些结合起来告诉我,我不知道我哪里出错了。

    我清楚地知道这是我的切线一代,因为其他部分似乎都遵循我所阅读的每个教程似乎都在说。切线是在考虑立方体图像的情况下生成的。因此,要从立方体贴图通常的3D坐标确定normal = texture(mat.normal,textureLookup).rgb * 2.0 - 1.0; lightDir 2D坐标,我:

    1. 使用最大值来确定
    2. 中的面孔
    3. 使用https://www.opengl.org/registry/specs/ARB/texture_cube_map.txt中的代码确定S,T坐标
    4. 以下是https://www.opengl.org/registry/specs/ARB/texture_cube_map.txt的摘录,我正在谈论。

      viewdir

      修改 我不知道为什么我之前没有,但我已经在几何着色器中输出法线,切线和bitangents来查看它们面对的方式。我使用了this tutorial

      Here they are

      黄色是面法线,绿色是顶点法线。我不确定为什么顶点法线看起来是错误的,它们不会影响任何其他光照,所以它可能只是我的几何着色器中的一个错误。

      切线为红色,Binormals为蓝色。这些似乎(很难说)就像它们彼此垂直一样,这是正确的,但除此之外它们并没有指向统一的方向。这就是我之前的斑驳模式。

      我不知道如何解决这个问题。

      编辑2 我已经发现了显示法线等问题。现在已修复。

      结果,我添加了一些阴影以使其更清晰,每种​​颜色都是不同的立方体脸。

      enter image description here

      我改变的其他内容是查找我的法线贴图。我忘了将范围调整回-1到1(从0到1)。

      for(int i = 0; i < 6; ++i)
      {   
          float scale = 15.0;
          std::deque<glm::vec4> normalMap(textureSize*textureSize);
          for(int x = 0; x < textureSize; ++x)
          {
              for(int y = 0; y < textureSize; ++y)
              {
                  // center point
                  int i11 = utils::math::get_1d_array_index_from_2d(x,y,textureSize);
                  float v11 = cubeFacesHeight[i][i11].r;
      
                  // to the left
                  int i01 = utils::math::get_1d_array_index_from_2d(std::max(x-1,0),y,textureSize);
                  float v01 = cubeFacesHeight[i][i01].r;
      
                  // to the right
                  int i21 = utils::math::get_1d_array_index_from_2d(std::min(x+1,textureSize-1),y,textureSize);
                  float v21 = cubeFacesHeight[i][i21].r;
      
                  // to the top
                  int i10 = utils::math::get_1d_array_index_from_2d(x,std::max(y-1,0),textureSize);
                  float v10 = cubeFacesHeight[i][i10].r;
      
                  // and now the bottom
                  int i12 = utils::math::get_1d_array_index_from_2d(x,std::min(y+1,textureSize-1),textureSize);
                  float v12 = cubeFacesHeight[i][i12].r;
      
                  glm::vec3 S = glm::vec3(1, 0, scale * v21 - scale * v01);
                  glm::vec3 T = glm::vec3(0, 1, scale * v12 - scale * v10);
      
                  glm::vec3 N = (glm::vec3(-S.z,-T.z,1) / std::sqrt(S.z*S.z + T.z*T.z + 1));
      
                  N.x = (N.x+1.0)/2.0;
                  N.y = (N.y+1.0)/2.0;
                  N.z = (N.z+1.0)/2.0;
                  normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = glm::vec4(N.x,N.y,N.z,v11);
              }
          }
          for(int x = 0; x < textureSize; ++x)
          {
              for(int y = 0; y < textureSize; ++y)
              {
                  cubeFacesHeight[i][utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)];
              }
          }
      }
      

      这并不能解决我的问题。

      令人困惑的是,当我尝试使用纹理中的法线时,我不会得到任何渲染效果。什么都没有进入深度缓冲区。我已经检查并仔细检查了可以从着色器访问纹理(因此原始屏幕截图显示了应用于球体的纹理)。

      因为即使我的Tangents和Binormals指向每一个方向;我仍然希望展示一些东西,即使它是错的。但即使环境色也没有通过。 (即使我单独留下cubeFacesHeightstd::array,也会发生这种情况。如果我只是忽略顶点法线并查找纹理。我会失去环境色......)

      编辑3:最后一个问题

      通常情况下,部分问题与您认为错误的地方无关。我的问题是我用不同的纹理覆盖了我的法线贴图的绑定。

      所以,有了这个,我现在可以看到我的颜色来了。用我漂亮的性感凹凸贴图。

      然而,立方体贴图的接缝处现在存在问题。我不确定是否因为正在计算切线或者是因为生成法线贴图的方式。我的法线贴图是从每张脸的高度贴图中独立生成的。

      这可以解释我认为的一些接缝效果,我将修改它以对这些边缘上的相邻面进行采样,看看会发生什么。

      我仍然认为产生的切线也会对这些接缝产生不利影响。我的想法是,它们将在接缝处指向相反的方向。

      截图: normal map seams

      编辑4 在从EDIT1进行测试的同时,我使用了一个非常低的多边形网格作为我的icosphere。所以我的细分很少。

      我想看看我的不完美的法线贴图球体看起来有多少多边形。这立即揭示了这个问题:

      dang it...

      如果不清楚,从左边开始写到是我的老朋友,接缝,但在下面,看起来是三角边缘。

      所以在完成上述所有操作之后,我想我已经回到原来不正确的切线问题了。

      仍在寻找任何阅读此内容的人的帮助。

      编辑4 好吧,那很快。这个网站http://www.geeks3d.com/20130122/normal-mapping-without-precomputed-tangent-space-vectors/给了我另一种创建切线的方法。虽然代码看起来与我在CPU上做的有些相似,但它并没有导致那些随机定向的切线从EDIT 3中产生这些边缘。

      我现在非常接近。我仍然有接缝,这种产生切线的其他方法似乎增加了他们的&#34;缝隙&#34;

      enter image description here

      编辑5 我现在尝试修改我的普通地图生成。之前的代码是这样的:

      6

      std::dequeglm::vec4for(int i = 0; i < 6; ++i) { // 0 is negative X // 1 is positive X // 2 is negative Y // 3 is positive Y // 4 is negative Z // 5 is positive Z // +X: right -Z (left), left +Z (right), top -Y (right), bottom +Y (right) // -X: right +Z (left), left -Z (right), top -Y (left), bottom +Y (left) // -Z: right -X (left), left +X (right), top -Y (bottom), bottom +Y (top) // +Z: right +X (left), left -X (right), top -Y (top), bottom +Y (bottom) // -Y: right +X (top), left -X (top), top +Z (top), bottom -Z (top) // +Y: right +X (bottom), left -X (bottom), top -Z (bottom), bottom +Z (bottom) //+Z is towards, -Z is distance const int NEGATIVE_X = 0; const int NEGATIVE_Y = 2; const int NEGATIVE_Z = 4; const int POSITIVE_X = 1; const int POSITIVE_Y = 3; const int POSITIVE_Z = 5; float scale = 15.0; std::deque<glm::vec4> normalMap(textureSize*textureSize); for(int x = 0; x < textureSize; ++x) { for(int y = 0; y < textureSize; ++y) { // center point int i11 = utils::math::get_1d_array_index_from_2d(x,y,textureSize); float v11 = cubeFacesHeight[i][i11].r; // to the left int i01 = utils::math::get_1d_array_index_from_2d(std::max(x-1,0),y,textureSize); float v01 = cubeFacesHeight[i][i01].r; if(x-1 < 0) { if(i == NEGATIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize); v01 = cubeFacesHeight[NEGATIVE_Z][i01].r; } else if(i == POSITIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize); v01 = cubeFacesHeight[POSITIVE_Z][i01].r; } else if(i == NEGATIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize); v01 = cubeFacesHeight[POSITIVE_X][i01].r; } else if(i == POSITIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize); v01 = cubeFacesHeight[NEGATIVE_X][i01].r; } else if(i == NEGATIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(y,0,textureSize); v01 = cubeFacesHeight[NEGATIVE_X][i01].r; } else if(i == POSITIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(y,textureSize-1,textureSize); v01 = cubeFacesHeight[NEGATIVE_X][i01].r; } } // to the right int i21 = utils::math::get_1d_array_index_from_2d(std::min(x+1,textureSize-1),y,textureSize); float v21 = cubeFacesHeight[i][i21].r; if(x+1 > textureSize-1) { if(i == NEGATIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize); v01 = cubeFacesHeight[POSITIVE_Z][i01].r; } else if(i == POSITIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize); v01 = cubeFacesHeight[NEGATIVE_Z][i01].r; } else if(i == NEGATIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize); v01 = cubeFacesHeight[NEGATIVE_X][i01].r; } else if(i == POSITIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize); v01 = cubeFacesHeight[POSITIVE_X][i01].r; } else if(i == NEGATIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(y,0,textureSize); v01 = cubeFacesHeight[POSITIVE_X][i01].r; } else if(i == POSITIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(y,textureSize-1,textureSize); v01 = cubeFacesHeight[POSITIVE_X][i01].r; } } // to the top int i10 = utils::math::get_1d_array_index_from_2d(x,std::max(y-1,0),textureSize); float v10 = cubeFacesHeight[i][i10].r; if(y-1 < 0) { if(i == NEGATIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(0,x,textureSize); v01 = cubeFacesHeight[NEGATIVE_Y][i01].r; } else if(i == POSITIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,x,textureSize); v01 = cubeFacesHeight[NEGATIVE_Y][i01].r; } else if(i == NEGATIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize); v01 = cubeFacesHeight[NEGATIVE_Y][i01].r; } else if(i == POSITIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize); v01 = cubeFacesHeight[NEGATIVE_Y][i01].r; } else if(i == NEGATIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize); v01 = cubeFacesHeight[POSITIVE_Z][i01].r; } else if(i == POSITIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize); v01 = cubeFacesHeight[NEGATIVE_Z][i01].r; } } // and now the bottom int i12 = utils::math::get_1d_array_index_from_2d(x,std::min(y+1,textureSize-1),textureSize); float v12 = cubeFacesHeight[i][i12].r; if(y+1 > textureSize-1) { if(i == NEGATIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(0,x,textureSize); v01 = cubeFacesHeight[POSITIVE_Y][i01].r; } else if(i == POSITIVE_X) { i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,x,textureSize); v01 = cubeFacesHeight[POSITIVE_Y][i01].r; } else if(i == NEGATIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize); v01 = cubeFacesHeight[POSITIVE_Y][i01].r; } else if(i == POSITIVE_Z) { i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize); v01 = cubeFacesHeight[POSITIVE_Y][i01].r; } else if(i == NEGATIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize); v01 = cubeFacesHeight[NEGATIVE_Z][i01].r; } else if(i == POSITIVE_Y) { i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize); v01 = cubeFacesHeight[POSITIVE_Z][i01].r; } } glm::vec3 S = glm::vec3(1, 0, scale * v21 - scale * v01); glm::vec3 T = glm::vec3(0, 1, scale * v12 - scale * v10); glm::vec3 N = (glm::vec3(-S.z,-T.z,1) / std::sqrt(S.z*S.z + T.z*T.z + 1)); N.x = (N.x+1.0)/2.0; N.y = (N.y+1.0)/2.0; N.z = (N.z+1.0)/2.0; normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = glm::vec4(N.x,N.y,N.z,v11); } } for(int x = 0; x < textureSize; ++x) { for(int y = 0; y < textureSize; ++y) { cubeFacesHeight[i][utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)]; } } } {{1}}的{​​{1}}。或者,我的立方体贴图的六个方面。面部的颜色是灰度的,我不会因为不重要的原因而使用花车。

      我现在将其更改为以下内容,警告,这是丑陋且漫长的。

      {{1}}

      所以我现在有点出血&#34;进入相邻的立方体面以在生成法线贴图时对其进行采样。这实际上增加了接缝外观。

      hmmmm

      但这种提出了它自己的问题。例如......&#34;为什么在地狱中影响会增加?&#34;你可以看到它现在是一种斜面效应。

      所以,我非常确定我在&#34;流血&#34;进入下一个。这让我回到切线不正确的地方。

      即使我完全混淆了立方体面,它也不会产生斜面效果,这将是完全不稳定的。例如,即使在完全平坦的部分,即将正常地图生成放入下一个面部也没有效果,我仍然看到一个巨大的斜面。

      dang it more

      这让我觉得如果之前的切线是正确的,那么正常的地图排序&#34;匹配&#34;切线方向?我不知道。

      快速修改 我注意到我在原始地图生成期间有效地对我的脸部边缘进行了两次采样。如果我删除这个双重采样并且仅使用0作为附加,我最终会看到那些相同的大接缝。我不确定这意味着什么...

      另一个快速修改 这张图片展示了我认为非常有用的东西。 enter image description here

      我可以在这里看到两个不同的面孔是指向&#34;在相反的方向。这是我的片段切线生成。

      所以我回到我的切线是一个问题。

3 个答案:

答案 0 :(得分:1)

法线贴图最适合最初创建法线贴图的法线矢量矩阵

我认为你的问题与你的切线在表面上的非均匀对齐有关。 UV映射通常是第一个看到这样的问题的地方。并且,使用2D图像绘制球体非常容易(查看所有各种地球投影拓扑,您将看到我的意思)。在某些时候,你会得到拉伸,边缘或剪切,并且很可能是上述所有的组合。通常使用UV贴图,重点是选择在表面上隐藏这些效果的位置。通常选择行星的极点。 我想看的一个地方是重新调整你的切线和副法线,这样他们就可以共享一个共同的全局定位,即。 tanget = north,binormal = east,法线朝外(海拔高度)。 你的切线和副法线的不均匀性在正常映射问题中有时出现的伪像中起直接作用,因为如果法线贴图是在假设所有的情况下烘焙的话,它们可以扭曲法线贴图在该位置的效果。切线和副法线是均匀定向的。

本质上,通过对切线和副法线的隐含理解来烘焙/创建法线贴图。如果,当重新应用法线贴图时,曲面的切线和副法线与最初创建法线贴图的隐式理解不对齐,那么您将获得光照和着色错误。

益处或正交法向量矩阵

这样做的好处是切线和副法向量通常用于查找2D纹理坐标。如果你的矩阵是非正交的,那么你就会冒着在倾斜角度下听到,旋转或精度损失的风险。

定义统一的正交法向量矩阵

您可以在不同的波形中接近正常/切线/正常计算,以确保两个因素:

  1. 均匀的物体方向,即...所有指向相同的相对方向
  2. 正交向量,将限制纹理查找剪切
  3. 这将通过两次旋转和一次移动来变换预定义的正交矢量矩阵。为了便于解释,我不会将这三个矩阵运算折叠成一个矩阵,但是你可能需要在代码中这样做。

    首先,从已定义的向量矩阵

    开始

    vec3 = [1, 0, 0, 0, 1, 0, 0, 0, 1]; enter image description here

    其次,在对象空间而不是世界空间

    中执行这些操作

    否则,您必须将该对象转换回世界中心,并将其旋转回原点方向,然后应用正常变换,然后将对象发送回其工作位置和方向

    第三,创建从vtx [n]到对象中心

    的向量

    此向量将告诉您在两个方向上旋转法向量矩阵的程度:

    • 纵向旋转
    • 纬度旋转

    enter image description here

    第四,旋转法向量矩阵以对齐

    enter image description here

    最后,将法线向量矩阵移动距离

    enter image description here

    冲洗并重复

    enter image description here

    如果您需要保持非均匀的非正交UV

    您可以根据不协调的UV布局创建法线贴图,以便使布局生效,因此适当地应用自身而不会产生影响。但是你的法线贴图必须是从这种天生的不协调性中创造出来的,这样它才能优雅地应用于那些紫外线。

    边缘像素插值?

    第三,看看法线贴图的边缘如何遵循立方体贴图的形状,我想知道你如何为法线贴图插入边缘像素。

    立方体贴图的GLSL纹理查找?

    另外,我可能只是找不到你的答案部分,但你是否考虑过使用GLSL立方体图查找功能? gvec4 texture( gsamplerCube sampler, vec3 P, [float bias]);

答案 1 :(得分:0)

这里我是我在评论中提到的插图:

Normal Illustration

如您所见,红线是生成的法线,基座的每个顶点都有两条。这会导致照明问题,因为每个三角形的面都处于不同的方向。当我第一次看到这个时,我不得不在黄线所代表的每个顶点上取两个法线的平均值来修复光照计算。

至于你从立方体得到的图像 - 凹凸贴图,这可能是你如何生成顶点来定义球体以及如何应用纹理坐标。如果没有看到整个解决方案或项目并使用它,我无法直接告诉我。问题可能甚至不涉及你的切线,但可能在你的纹理映射中导致包裹效果。

这不是您问题的直接答案,而是需要注意的建议,因为有很多不同的方法可以实现这些类型的着色器和渲染。

答案 2 :(得分:0)

我花了很长时间才知道如何计算切线空间。 也许我最终得到它的方式可以提供帮助。

你有三个顶点v0,v1,v2。每个都有一个位置,普通和紫外线。让我们计算v0的切线空间。 z轴为v0.normal。我们需要计算x和y轴。

三角形上的任何点都可以表示为v0.pos +(v1.pos-v0.pos)* t +(v2.pos-v0.pos)* s。任何纹理坐标都可以表示为v0.uv +(v1.uv - v0.uv)* t +(v2.uv - v0.uv)* s。

在切线空间中,我们需要v1.uv - v0.uv =(1,0)和v2.uv-v0.uv =(0,1)。 我们可以解决这个问题!对于这两种情况!这就是我们的切线和副法线的s和t。只需将它们插回到位置方程式中,您就可以获得uv =(0,1)和uv =(1,0)的位置。减去v0.pos,你有x和y轴!也标准化他们。

那就是v0的切线空间。 3x3矩阵。它不一定是正交的。但那没关系。您还可以使用该顶点为每个三角形计算每个顶点的此矩阵。只是平均他们。

渲染时对每个顶点矩阵进行插值,并按像素对它们进行标准化。

测试的一个好方法是只渲染z列 - 它应该是正常的。

对于光照,从光中减去插值位置,并通过&#34;切线矩阵&#34;对其进行变换。现在你的光线处于切线空间,其中(0,0,1)朝向光线,法线贴图指向直线。