Jump to content
  • Advertisement
Sign in to follow this  
rXpSwiss

OpenGL OpenGL Bump Map -- Texture artifacts ?

This topic is 1503 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,
 
I am learning OpenGL (and learning the math behind it) and I'm making a simple OBJ viewer, nothing fancy.
I have diffuse, specular and ambient light/texture working fine and now I am implementing the bump mapping.
I based my code on what I learned with the OpenGL 4.3 Redbook and "Mathematics for 3D game programming and computer graphics" book.
 
There is probably something I didn't understand correctly, I just hope you will be able to help me :)
 
Anyway this is the result I get (from a free asset used just for testing -- the results are fine in blender) :
2SkhN.png
 
As you can see there is some artifacts but it must be coming from my tangent space.
 
PS : Yes, this model is not just a plane.
 
This is the diffuse texture and the bump map :
JAsxb.jpg
 
UhYd0.png
Fragment shader code :
 
    void main() {
     vec3 normalDirection = normalize(tangenteSpace*(texture2D( bump_tex, f_texcoord ).rgb*2.0 - 1.0));
     //vec3 normalDirection = normalize(mat3(invTransp)*vertNormal);
     vec3 viewDirection = tangenteSpace*normalize(vec3(invView * vec4(0.0, 0.0, 0.0, 1.0) - position));
    
     float attenuation = 1.0;//none
     vec3 vertToLightSource = vec3(light.position - position*light.position.w);
     float distance = length(vertToLightSource);
     attenuation = mix(1.0,1.0/(light.constantAttenuation +
     light.linearAttenuation *distance +
     light.quadraticAttenuation*distance*distance),light.position.w);
     vec3 lightDirection = tangenteSpace*(vertToLightSource/distance);
    
     //spotlight if spotCutoff <= 90
     float clampedCosine = max(0.0, dot(-lightDirection, normalize(light.spotDirection)));
     float tempMix = mix(attenuation * pow(clampedCosine, light.spotExponent),0.0,clampedCosine < cos(light.spotCutoff * 3.14159 / 180.0));//if outside of spotlight nothing
     attenuation = mix(attenuation,tempMix,light.spotCutoff <= 90.0);
    
     //should there be any attenuation ?
     attenuation = mix(attenuation,1.0,light.position.w);
    
     //------------------------------ ambiant light
     vec3 ambientLight = vec3(ambientScene)*vec3(mat.Ka);
    
     //------------------------------ specular light
     //get the reflection
     vec4 specularMapPixel = texture2D(spec_tex, f_texcoord).rgba;
     vec3 specularColor = specularMapPixel.rgb;
     float shininess = specularMapPixel.a;
     vec3 specularReflection = mix(
     attenuation * vec3(light.specular) * vec3(mat.Ks)* pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)),mat.Ns*shininess) *specularColor.rgb,
       vec3(0.0, 0.0, 0.0),
       dot(normalDirection, lightDirection) < 0.0
       );
     
     vec3 diffuseReflection = attenuation*
     vec3(light.diffuse)*vec3(mat.Kd)
     *max(0.0,dot(normalDirection,lightDirection));
    
     vec4 Color = vec4(vec4(specularReflection,1.0) + vec4(ambientLight,1)*texture2D(amb_tex, f_texcoord) + vec4(diffuseReflection,1.0)*texture2D(dif_tex, f_texcoord));
    
     FragColor = Color;
    }
 
Vertex Shader Code :
 
    void main()
    {
        //comnpute tangent space
     tangenteSpace[0] = mat3(mv)*normalize(tangent.xyz);
     tangenteSpace[2] = mat3(mv)*normalize(vertNormal);
     tangenteSpace[1] = mat3(mv)*normalize(cross(tangenteSpace[0],tangenteSpace[2])*tangent.w);
     tangenteSpace = transpose(tangenteSpace);


     //position in world space
     position = m * vertCoord;
        f_texcoord = vec2(texCoord);
     
        gl_Position = mvp * vertCoord;
    }

 

Share this post


Link to post
Share on other sites
Advertisement

I'd say that it isn't the bump map what you need - I think that your shader code expects a normal map (which can be derived from the bump map). Typically 3d modelling softwares can work on both (normal map or height map). 

 

You can either use some filter in the shader to produce the surface normal or use an offline tool to convert the height map into a normal map.

 

Cheers!

 

[edit] this image shows the difference between height map and a normal map : http://www.3dkingdoms.com/CW3D/Doc/displacement-maps.jpg

Edited by kauna

Share this post


Link to post
Share on other sites

Thank you about that I used a software to generate a nice normal I really got the 2 confuses smile.png

But now I see why there is so much issues, it seems that only the diffuse texture (the first loaded into the shader) is active. By that I mean that I tried to apply the other textures as a diffuse texture and I always saw the same results : The "normal" diffuse texture.

 

I made some change recently and without noticing it I put the glActiveTexture ABOVE the glBindTexture. I hope that is my problem.

 

Edit : now only the spec texture is used. Weird.

Edited by rXpSwiss

Share this post


Link to post
Share on other sites

Can you post your code for binding the textures and setting the active texture? Have you specified which texture unit each of the sampler2D uniforms should use?

Share this post


Link to post
Share on other sites

Sure I can do that.

void Model::draw(glm::mat4 view, glm::mat4 projection)
{

	//texture diffuse
	if (_mtl->getDiffuseTextureMap())
	{
		glBindTexture(GL_TEXTURE_2D, _difTextureID);
		glActiveTexture(GL_TEXTURE0);
		GLuint myTexture = glGetUniformLocation(_shaderProgramID, "dif_tex");
		glUniform1i(myTexture, 0);
	}

	//texture ambient
	if (_mtl->getAmbientTextureMap())
	{
		glBindTexture(GL_TEXTURE_2D, _ambTextureID);
		glActiveTexture(GL_TEXTURE1);
		GLuint myTexture = glGetUniformLocation(_shaderProgramID, "amb_tex");
		glUniform1i(myTexture, 1);
	}

	//texture specular
	if (_mtl->getSpecularTextureMap())
	{
		glBindTexture(GL_TEXTURE_2D, _specTextureID);
		glActiveTexture(GL_TEXTURE2);
		GLuint myTexture = glGetUniformLocation(_shaderProgramID, "spec_tex");
		glUniform1i(myTexture, 2);
	}

	//texture normal
	if (_mtl->getBumpTextureMap())
	{
		glBindTexture(GL_TEXTURE_2D, _bumpTextureID);
		glActiveTexture(GL_TEXTURE3);
		GLuint myTexture = glGetUniformLocation(_shaderProgramID, "bump_tex");
		glUniform1i(myTexture, 3);
	}

	//model
	_modelMat = _translateMat * _scaleMat * _rotateMat * _modelMat;
	glm::mat4 mv = view * _modelMat;
	glm::mat4 mvp = projection * view * _modelMat ;
	glBindBuffer(GL_ARRAY_BUFFER, _vboID);

	GLuint mID = glGetUniformLocation(_shaderProgramID, "m");
	glUniformMatrix4fv(mID, 1, GL_FALSE, &_modelMat[0][0]);

	GLuint mvID = glGetUniformLocation(_shaderProgramID, "mv");
	glUniformMatrix4fv(mvID, 1, GL_FALSE, &mv[0][0]);

	GLuint mvpID = glGetUniformLocation(_shaderProgramID, "mvp");
	glUniformMatrix4fv(mvpID, 1,GL_FALSE, &mvp[0][0]);

	GLuint itID = glGetUniformLocation(_shaderProgramID, "invTransp");
	glUniformMatrix4fv(itID, 1, GL_FALSE, &glm::transpose(glm::inverse(_modelMat))[0][0]);

	GLuint ivID = glGetUniformLocation(_shaderProgramID, "invView");
	glUniformMatrix4fv(ivID, 1, GL_FALSE, &glm::inverse(view)[0][0]);

	//send material info
	GLuint matID = glGetUniformLocation(_shaderProgramID, "mat.Kd");
	glUniform3fv(matID, 1, &_mtl->getDiffuseColor()[0]);

	matID = glGetUniformLocation(_shaderProgramID, "mat.Ka");
	glUniform3fv(matID, 1, &_mtl->getAmbientColor()[0]);

	matID = glGetUniformLocation(_shaderProgramID, "mat.Ks");
	glUniform3fv(matID, 1, &_mtl->getSpecularColor()[0]);

	matID = glGetUniformLocation(_shaderProgramID, "mat.Ns");
	glUniform1f(matID, _mtl->getSpecularCoeff());

	glDrawArrays(GL_TRIANGLES, 0, _vertices.size());

	//reset transform matrix
	_rotateMat = glm::mat4(1.0f);
	_translateMat = glm::mat4(1.0f);
	_scaleMat = glm::mat4(1.0f);

}
void Model::loadIntoBuffer(GLuint shaderProgramID)
{
	float defaultColor[4] = { 0.5, 0.5, 0.5, 1 };
	_shaderProgramID = shaderProgramID;
	//setup element array buffer
	glGenBuffers(1, &_vboID);
	glBindBuffer(GL_ARRAY_BUFFER, _vboID);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex)*_vertices.size(), &_vertices.front(), GL_STATIC_DRAW);

	//pass to shaders -- better to be continious
	_coordID = glGetAttribLocation(_shaderProgramID, "vertCoord");
	glEnableVertexAttribArray(_coordID);
	glVertexAttribPointer(_coordID, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), BUFFER_OFFSET(0));

	_normID = glGetAttribLocation(_shaderProgramID, "vertNormal");
	glEnableVertexAttribArray(_normID);
	glVertexAttribPointer(_normID, 3, GL_FLOAT, GL_TRUE, sizeof(vertex), BUFFER_OFFSET(sizeof(glm::vec4)));

	_texCoordID = glGetAttribLocation(_shaderProgramID, "texCoord");
	glEnableVertexAttribArray(_texCoordID);
	glVertexAttribPointer(_texCoordID, 3, GL_FLOAT, GL_TRUE, sizeof(vertex), BUFFER_OFFSET(sizeof(glm::vec4)+sizeof(glm::vec3)));

	_spaceParamID = glGetAttribLocation(_shaderProgramID, "tangents");
	glEnableVertexAttribArray(_spaceParamID);
	glVertexAttribPointer(_spaceParamID, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), BUFFER_OFFSET(sizeof(glm::vec4) + sizeof(glm::vec3) * 2));

	//texture diffuse
	if (_mtl->getDiffuseTextureMap())
	{
		glGenTextures(1, &_difTextureID);
		glBindTexture(GL_TEXTURE_2D, _difTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			_mtl->getDiffuseTextureMap()->header.width,
			_mtl->getDiffuseTextureMap()->header.height,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			&_mtl->getDiffuseTextureMap()->data.parsedImageData.front()
			);
	}
	else
	{
		glGenTextures(1, &_difTextureID);
		glBindTexture(GL_TEXTURE_2D, _difTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			1,
			1,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			defaultColor
			);
	}

	//texture ambient
	if (_mtl->getAmbientTextureMap())
	{
		glGenTextures(1, &_ambTextureID);
		glBindTexture(GL_TEXTURE_2D, _ambTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			_mtl->getAmbientTextureMap()->header.width,
			_mtl->getAmbientTextureMap()->header.height,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			&_mtl->getAmbientTextureMap()->data.parsedImageData.front()
			);
	}
	else
	{
		glGenTextures(1, &_ambTextureID);
		glBindTexture(GL_TEXTURE_2D, _ambTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			1,
			1,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			defaultColor
			);
	}

	//texture specular
	if (_mtl->getSpecularTextureMap())
	{
		glGenTextures(1, &_specTextureID);
		glBindTexture(GL_TEXTURE_2D, _specTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			_mtl->getSpecularTextureMap()->header.width,
			_mtl->getSpecularTextureMap()->header.height,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			&_mtl->getSpecularTextureMap()->data.parsedImageData.front()
			);

	}
	else
	{
		glGenTextures(1, &_specTextureID);
		glBindTexture(GL_TEXTURE_2D, _specTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			1,
			1,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			defaultColor
			);
	}

	//texture bump map
	if (_mtl->getBumpTextureMap())
	{
		glGenTextures(1, &_bumpTextureID);
		glBindTexture(GL_TEXTURE_2D, _bumpTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			_mtl->getBumpTextureMap()->header.width,
			_mtl->getBumpTextureMap()->header.height,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			&_mtl->getBumpTextureMap()->data.parsedImageData.front()
			);
	}
	else
	{
		glGenTextures(1, &_bumpTextureID);
		glBindTexture(GL_TEXTURE_2D, _bumpTextureID);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexImage2D(
			GL_TEXTURE_2D,
			0,
			GL_RGBA8,
			1,
			1,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			defaultColor
			);
	}

}
Edited by rXpSwiss

Share this post


Link to post
Share on other sites

So there's two problems I can see here:

  1. glActiveTexture should come before glBindTexture. OpenGL is a massive state machine and calling glBindTexture will bind the texture to the currently active texture unit. If you call glActiveTexture after glBindTexture, it will affect the next call to glBindTexture.
  2. Your texture parameter for GL_TEXTURE_MAG_FILTER is invalid. I'm guessing you meant to set GL_TEXTURE_MIN_FILTER to GL_NEAREST_MIPMAP_LINEAR and GL_TEXTURE_MAG_FILTER to GL_LINEAR. The mipmap filters are valid only for min(ification).
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

 

Share this post


Link to post
Share on other sites

I checked every operation with GLgetError and I saw the error with GL_TEXTURE_MAG/MIN_FILTER it was a really bad copy paste from me.

But I didn't find the glActiveTexture because OpenGL doesn't say it is an error because it is correct state-wise but just doesn't do what I want...

Anyway, thank you a lot smile.png 

Do you have any link on the machine state for texture etc. ?

 

Now I just need to reenable my bump mapping and see if it works.

 

I am almost there, there must be something not working with my lightDirection in tangentSpace because everything seems correct except the specular lightning cannot be seen anymore.

 

EKONvcf.png

 

I think I fixed it :)

 

XIcqBn5.png

Edited by rXpSwiss

Share this post


Link to post
Share on other sites

White & black dots can be the result of math that produces errors. 99% of the cases are sqrt(negative number) and ~zero-length vectors.

Flickering is usually uninitialized variables.

Completely white/black is usually missing/empty texture, or missing/uninitialized uniforms etc.

 

 

Check your inputs for errors.

Transfer normal and tangent to pixel shader (interpolated) and show their magnitudes. color = length(vector);

white = good, black = bad

 

Eventually you will find the issue. It helps alot to know what values certain things should have. For example, directional vectors (normal, tangent, binormal) should all be length == 1 (white).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!