C++ 什么';我的法线映射有什么问题?我想是';这是我的切线

C++ 什么';我的法线映射有什么问题?我想是';这是我的切线,c++,opengl,normals,bump-mapping,C++,Opengl,Normals,Bump Mapping,编辑:你可能想从“编辑3”开始,因为我已经解决了很多问题 下面是我应用于icosphere的普通立方体贴图的屏幕截图: 使用以下代码生成立方体贴图icosphere的切线m_索引在std::vector中,将索引转换为std::vector中的m_顶点 std::vector<glm::vec3> storedTan(m_vertices.size(),glm::vec3(0,0,0)); // tangents for(int i = 0; i < m_indices.s

编辑:你可能想从“编辑3”开始,因为我已经解决了很多问题

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

使用以下代码生成立方体贴图icosphere的切线
m_索引
std::vector
中,将索引转换为
std::vector
中的
m_顶点

std::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;
}
我知道当前的
t单词
位置
正常
都很好(否则您将看不到上面的屏幕截图)

然后,我的顶点着色器如下所示:

#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);
}
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)];
        }
    }
}
最后,我的片段着色器如下所示:

#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);
}
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)];
        }
    }
}
据我所知:

  • 我的切线计算正确
  • 我的法线贴图看起来像法线贴图
  • 我正在将灯光和视图方向更改为切线空间以匹配法线贴图
  • 结果什么都没有。也就是说,屏幕上没有任何内容。根本不是纯色。就像后面的一切都是画出来的,没有遮挡

    如果在法线贴图中放弃查找,而只使用切线矩阵灯光和视图,则会得到以下结果:

    这上面有一个后处理镜头光斑,它产生了那些有趣的片段和bob。我认为最重要的是,从表面上看,法线似乎有点精确,这是压倒性的眩光

    如果我通过切线矩阵变换灯光,我得到:

    所有这些都告诉我,我不知道哪里出了问题

    我有一个线索,这是我的切线生成,因为其他部分似乎遵循我读过的每一个教程似乎说。切线是在考虑立方体贴图的图标球体的情况下生成的。因此,要从立方体映射通常的三维坐标确定
    二维坐标,I:

  • 使用最大值确定我所在的面
  • 使用中的代码确定S,T坐标
  • 这是我所说的一段摘录

      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." ...
    
    编辑 我不知道为什么以前没有,但我已经在几何体着色器中输出法线、切线和双切线,以查看它们面对的方式。我用过

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

    切线为红色,副法线为蓝色。这些看起来(很难说)像是彼此的前腱,这是正确的,但除此之外,它们没有指向一致的方向。这就是我以前的斑驳图案

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

    编辑2 我已经解决了显示法线等的问题。现在这个问题已经解决了

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

    我改变的另一件事是查找到我的法线贴图。我忘记将范围调整回-1到1(从0到1)

    这并不能解决我的问题

    令人困惑的是,当我尝试使用纹理中的法线时,我没有得到任何渲染。深度缓冲区中没有任何内容。我已经检查并再次检查纹理是否可以从着色器访问(因此显示应用于球体的纹理的原始屏幕截图)

    因为即使我的切线和副法线指向各个方向;我仍然期待着一些东西被展示出来,即使它是错的。但即使是环境色也无法通过。(即使我不使用我的
    lightDir
    viewdir
    也会发生这种情况。如果我忽略顶点法线并查找纹理,我将丢失环境光颜色)

    编辑3:最后一个问题

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

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

    然而,现在立方体贴图的接缝处出现了一个问题。我不确定这是因为切线的计算还是因为法线贴图的生成方式。我的法线贴图是从每个面的高度贴图独立生成的

    这将解释一些接缝的影响,我想,我将修改它,对这些边上的相邻面进行采样,看看会发生什么

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

    截图:

    编辑4 从EDIT1开始测试时,我使用了一个非常非常低的多边形网格作为我的icosphere。所以我有最小的分部

    我想看看我不太完美的法线贴图球体在有很多多边形的情况下是什么样子的。这立刻暴露了这个问题:

    如果不清楚的话,从左边开始写的是我的老朋友seam,但下面是看起来像三角形的边

    所以在完成了以上所有工作之后,我想我回到了我最初的问题,即切线不正确

    仍在寻求阅读本文的人的帮助

    编辑4 嗯,那很快。这个网站给了我另一种创建切线的方法。虽然代码似乎有点类似于我在CPU上所做的,但它不会产生那些随机定向的切线,而这些切线是从Edit3生成的边

    我现在很接近了。我仍然有接缝,这种生成切线的其他方法似乎增加了它们的“接缝”

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

    #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);
    }
    
    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)];
            }
        }
    }
    
    所以我现在对广告有点“流血”