0
\$\begingroup\$

I am using Assimp to import 3d models, and FreeImage to parse textures.

The problem I am having is that the normal maps are actually red rather than blue when I try to render them as normal diffuse textures.

enter image description here

When I open the images in a image-viewing program they do indeed show up as blue.

Heres when I create the texture;

OpenGLTexture::OpenGLTexture(const std::vector<uint8_t>& textureData, uint32_t textureWidth, uint32_t textureHeight, TextureType textureType, Logger& logger) : mLogger(logger), mTextureID(gNextTextureID++), mTextureType(textureType)
{
    glGenTextures(1, &mTexture);
    CHECK_GL_ERROR(mLogger);

    glBindTexture(GL_TEXTURE_2D, mTexture);
    CHECK_GL_ERROR(mLogger);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, glTextureFormat, GL_UNSIGNED_BYTE, &textureData[0]);
    CHECK_GL_ERROR(mLogger);

    glGenerateMipmap(GL_TEXTURE_2D);
    CHECK_GL_ERROR(mLogger);

    glBindTexture(GL_TEXTURE_2D, 0);
    CHECK_GL_ERROR(mLogger);
}

Here is my fragment shader. You can see I just commented out the normal-map parsing and treated the normal map texture as the diffuse texture to display it and illustrate the problem. As for the rest of the code it interacts as expected with the diffuse textures so I dont see a obvious problem there.

"#version 330                                                                                                       \n \
                                                                                                                    \n \
layout(std140) uniform;                                                                                             \n \
                                                                                                                    \n \
const int MAX_LIGHTS = 8;                                                                                           \n \
                                                                                                                    \n \
struct Light                                                                                                        \n \
{                                                                                                                   \n \
    vec4  mLightColor;                                                                                              \n \
    vec4  mLightPosition;                                                                                           \n \
    vec4  mLightDirection;                                                                                          \n \
                                                                                                                    \n \
    int   mLightType;                                                                                               \n \
    float mLightIntensity;                                                                                          \n \
    float mLightRadius;                                                                                             \n \
    float mMaxDistance;                                                                                             \n \
};                                                                                                                  \n \
                                                                                                                    \n \
uniform UnifLighting                                                                                                \n \
{                                                                                                                   \n \
    vec4  mGamma;                                                                                                   \n \
    vec3  mViewDirection;                                                                                           \n \
    int   mNumLights;                                                                                               \n \
                                                                                                                    \n \
    Light mLights[MAX_LIGHTS];                                                                                      \n \
} Lighting;                                                                                                         \n \
                                                                                                                    \n \
uniform UnifMaterial                                                                                                \n \
{                                                                                                                   \n \
    vec4  mDiffuseColor;                                                                                            \n \
    vec4  mAmbientColor;                                                                                            \n \
    vec4  mSpecularColor;                                                                                           \n \
    vec4  mEmissiveColor;                                                                                           \n \
                                                                                                                    \n \
    bool  mHasDiffuseTexture;                                                                                       \n \
    bool  mHasNormalTexture;                                                                                        \n \
    bool  mLightingEnabled;                                                                                         \n \
    float mSpecularShininess;                                                                                       \n \
} Material;                                                                                                         \n \
                                                                                                                    \n \
uniform sampler2D unifDiffuseTexture;                                                                               \n \
uniform sampler2D unifNormalTexture;                                                                                \n \
                                                                                                                    \n \
in vec3 frag_position;                                                                                              \n \
in vec3 frag_normal;                                                                                                \n \
in vec2 frag_texcoord;                                                                                              \n \
in vec3 frag_tangent;                                                                                               \n \
in vec3 frag_bitangent;                                                                                             \n \
                                                                                                                    \n \
out vec4 finalColor;                                                                                      "  
                                                                                                          "         \n \
                                                                                                                    \n \
void CalcGaussianSpecular(in vec3 dirToLight, in vec3 normal, out float gaussianTerm)                                               \n \
{                                                                                                                   \n \
    vec3 viewDirection = normalize(Lighting.mViewDirection);                                                        \n \
    vec3 halfAngle     = normalize(dirToLight + viewDirection);                                                     \n \
                                                                                                                    \n \
    float angleNormalHalf = acos(dot(halfAngle, normalize(normal)));                                           \n \
    float exponent        = angleNormalHalf / Material.mSpecularShininess;                                          \n \
    exponent              = -(exponent * exponent);                                                                 \n \
                                                                                                                    \n \
    gaussianTerm = exp(exponent);                                                                                   \n \
}                                                                                                                   \n \
                                                                                                                    \n \
vec4 CalculateLighting(in Light light, in vec4 diffuseTexture, in vec3 normal)                                                      \n \
{                                                                                                                   \n \
    if (light.mLightType == 1)          // point light                                                              \n \
    {                                                                                                               \n \
        vec3 positionDiff = light.mLightPosition.xyz - frag_position;                                                   \n \
        float dist        = max(length(positionDiff) - light.mLightRadius, 0);                                          \n \
                                                                                                                        \n \
        float attenuation = 1 / ((dist/light.mLightRadius + 1) * (dist/light.mLightRadius + 1));                        \n \
        attenuation       = max((attenuation - light.mMaxDistance) / (1 - light.mMaxDistance), 0);                      \n \
                                                                                                                        \n \
        vec3 dirToLight   = normalize(positionDiff);                                                                    \n \
        float angleNormal = clamp(dot(normalize(normal), dirToLight), 0, 1);                                       \n \
                                                                                                                        \n \
        float gaussianTerm = 0.0;                                                                                                         \n \
        if (angleNormal > 0.0)                                                                                                            \n \
            CalcGaussianSpecular(dirToLight, normal, gaussianTerm);                                                                               \n \
                                                                                                                                            \n \
        return diffuseTexture * (attenuation * angleNormal  * Material.mDiffuseColor  * light.mLightIntensity * light.mLightColor) +      \n \
                                (attenuation * gaussianTerm * Material.mSpecularColor * light.mLightIntensity * light.mLightColor);       \n \
    }                                                                                                                                     \n \
    else if (light.mLightType == 2)     // directional light                                                                              \n \
    {                                                                                                                                     \n \
        vec3 dirToLight   = normalize(light.mLightDirection.xyz);                                                                         \n \
        float angleNormal = clamp(dot(normalize(normal), dirToLight), 0, 1);                                                         \n \
                                                                                                                        \n \
        float gaussianTerm = 0.0;                                                                                       \n \
        if (angleNormal > 0.0)                                                                                          \n \
            CalcGaussianSpecular(dirToLight, normal, gaussianTerm);                                                             \n \
                                                                                                                        \n \
        return diffuseTexture * (angleNormal  * Material.mDiffuseColor  * light.mLightIntensity * light.mLightColor) +  \n \
                                (gaussianTerm * Material.mSpecularColor * light.mLightIntensity * light.mLightColor);   \n \
    }                                                                                                                   \n \
    else if (light.mLightType == 4)     // ambient light                                                            \n \
        return diffuseTexture * Material.mAmbientColor * light.mLightIntensity * light.mLightColor;                 \n \
    else                                                                                                            \n \
        return vec4(0.0);                                                                                           \n \
}                                                                                                                   \n \
                                                                                                                    \n \
void main()                                                                                                         \n \
{                                                                                                                   \n \
    vec4 diffuseTexture = vec4(1.0);                                                                                \n \
    if (Material.mHasDiffuseTexture)                                                                                \n \
        diffuseTexture = texture(unifDiffuseTexture, frag_texcoord);                                                \n \
                                                                                                                    \n \
    vec3 normal = frag_normal;                                                                                        \n \
    if (Material.mHasNormalTexture)                                                                                 \n \
    {                                                                                                               \n \
        diffuseTexture = vec4(normalize(texture(unifNormalTexture, frag_texcoord).xyz * 2.0 - 1.0), 1.0);  \n \
       // vec3 normalTangentSpace  = normalize(texture(unifNormalTexture, frag_texcoord).xyz * 2.0 - 1.0);            \n \
        //mat3 tangentToWorldSpace = mat3(normalize(frag_tangent), normalize(frag_bitangent), normalize(frag_normal)); \n \
                                                                                                                        \n \
       // normal = tangentToWorldSpace * normalTangentSpace;                                                              \n \
    }                                                                                                                   \n \
                                                                                                                    \n \
    if (Material.mLightingEnabled)                                                                                  \n \
    {                                                                                                               \n \
        vec4 accumLighting = vec4(0.0);                                                                             \n \
                                                                                                                    \n \
        for (int lightIndex = 0; lightIndex < Lighting.mNumLights; lightIndex++)                                    \n \
            accumLighting += Material.mEmissiveColor * diffuseTexture +                                             \n \
                                CalculateLighting(Lighting.mLights[lightIndex], diffuseTexture, normal);                       \n \
                                                                                                                    \n \
        finalColor = pow(accumLighting, Lighting.mGamma);                                                           \n \
    }                                                                                                               \n \
    else {                                                                                                          \n \
        finalColor = pow(diffuseTexture, Lighting.mGamma);                                                          \n \
    }                                                                                                               \n \
}                                                                                                                   \n";

Why is this? does normal-map textures need some sort of special treatment in opengl?

\$\endgroup\$
  • \$\begingroup\$ btw the image doesn't look like it contains any textures to me. Neither normal maps nor other textures. it seems plain color. check if you are actually loading the texture correctly. \$\endgroup\$ – concept3d Nov 3 '13 at 1:18
7
\$\begingroup\$

The bitmaps might be getting loaded in BGRA format instead of RGBA. Windows .bmp files are always stored in BGRA order, for example. If that's the case, you just need to tell OpenGL so, by passing GL_BGRA instead of GL_RGBA in your glTexImage2D call.

\$\endgroup\$
  • \$\begingroup\$ The normal map is stored in a .dds file - FreeImage reports colorcoding as FIC_RGBALPHA aswell \$\endgroup\$ – KaiserJohaan Nov 3 '13 at 10:47
2
\$\begingroup\$

If you just want to view the normal map as any image-viewer would, you should remove the transformation from [0,1] to [-1,1] done by texture(...).xyz * 2 - 1.0 and also skip the normalization. Try using the texture like this:

diffuseTexture = vec4(texture(unifNormalTexture, frag_texcoord).xyz, 1.0);

If you aren't already aware of it, that transformation is done with normal maps, because normal vectors can of course contain negative entries, but you don't want to store negative values in the texture files. Therefore, normal vectors are mapped to a range of [0,1] for storage, and have to be remapped to the original range when used for lighting calculations.
I suspect that, by doing transformation to the [-1,1] range, in your case the green and/or blue color channels are mapped to negative values and are therefore considered 0 by the fragment shader output. Only the red channel remains visible, which would explain the red texture you see.
To make things worse, the normalization will produce a unit vector, further distorting the color of the texture, e.g. some vector like (0.4,-0.3,0.0) should be normalized to (0.8,-0.6,0.0), further increasing the intensity of the red channel while the green channel is still clipped to 0 and you end up with a rather bright red color.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.