I’ve been trying for some time to successfully get some bump mapping going on a cubemapped sphere.
I have a procedurally generated height-cubemap. With this I colourize to create a diffuse map.
Now, I’m creating a normalmap based on the code from “Mathematics for 3D Game Programming and Computer Graphics, Third Edition”, which appears to work really well.
The problem I’ve had to date is Tangent-space normal map. I just cannot find a way to generate the normal-map and generate the tangent and binormal on my vertices without any graphical artifacts.
If anyone has a solution for that I’d love to know it.
I’ve basically given up on this for now though. What I’m trying to do now is generate a object-space normal map for my cubemapped sphere. This seems like it would be easier to generate and fool-proof to use. But so far I’m having trouble.
My normal map looks like this:
So I think there’s clearly something wrong in it’s generation. Here’s the code that generates it.
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));
glm::vec3 originalDirection;
if(i == POSITIVE_X)
originalDirection = glm::vec3(textureSize,-y,-x);
else if(i == NEGATIVE_X)
originalDirection = glm::vec3(-textureSize,-x,-y);
else if(i == POSITIVE_Y)
originalDirection = glm::vec3(-x,-textureSize,-y);
else if(i == NEGATIVE_Y)
originalDirection = glm::vec3(-y,textureSize,-x);
else if(i == POSITIVE_Z)
originalDirection = glm::vec3(-y,-x,textureSize);
else if(i == NEGATIVE_Z)
originalDirection = glm::vec3(-y,-x,-textureSize);
glm::vec3 o = originalDirection;
glm::vec3 a = N;
glm::vec3 ax = glm::normalize(o) * (glm::dot(a,glm::normalize(o)));
N = ax;
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)];
}
}
cubeFacesHeight is 6 faces of height values.
What I’m attempting to do is use the value originally given to N, as this is the normal map as though it was the surface of a plane. Then, I’m attempting to apply this to the original direction vector of each point (which is also the normal vector). I think it’s that application, where ax is set that it the problem.
I then implement it in my Fragment shader like so:
#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;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
in vec3 ex_normal;
in vec3 ex_positionCameraSpace;
in vec3 ex_originalPosition;
in vec3 ex_positionWorldSpace;
in vec4 ex_positionLightSpace;
in PointLight ex_light;
/* *********************
Calculates the color when using a point light. Uses shadow map
********************* */
vec3 CalcPointLight(PointLight light, Material mat, vec3 n, vec3 fragPos, vec3 originalPos, vec3 viewDir)
{
/* just lighting stuff that doesn't matter */
vec3 lightDir = normalize(fragPos - light.position);
vec3 reflectDir = normalize(reflect(lightDir, n));
float specularFactor = pow(dot(viewDir,reflectDir), mat.shininess);
if(specularFactor > 0 && diffuseFactor > 0)
specularColor = light.specular * specularFactor * specularMat;
/*more lighting stuff*/
}
vec3 get_normal(vec3 SRT)
{
vec3 map = texture(uMaterial.normal,SRT).rgb * 2.0 - 1.0;
return mat3(transpose(inverse(view * model))) * map;
}
void main(void)
{
vec3 viewDir = normalize(-ex_positionCameraSpace);
vec3 n = get_normal(glm::normalize(ex_originalPosition));
vec3 result = CalcPointLight(ex_light,uMaterial,n,ex_positionCameraSpace, ex_positionWorldSpace,viewDir);
color = vec4(result,1.0);
}
Considering that my Fragment shader works fine without sampling the normal map, and instead using “ex_originalPosition”, I don’t think it’s the problem. I could just use some help in generating the object space normal map.