Normal mapping GLSL using LibGDX

一世执手 提交于 2020-02-23 09:30:47

问题


I try to implement normal mapping using LibGDX. So I got some positive results when I calculate diffuse and specular color in vertex shader (at least I think so).

Vertex shader:

attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;    

varying vec2 v_texCoord;
varying float v_diffuse;
varying vec3 v_specular;
varying vec3 v_lightVec;

uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;

const vec3 lightVector = vec3(0.0,0.0,-1.0);

void main()
{
  // Output the unmodified vertex position. 
  gl_Position = u_projTrans * u_worldTrans * a_position;

  mat3 normalMatrix = mat3(u_matViewInverseTranspose);
  // compute the transformed normal
  vec3 n = normalize(normalMatrix * a_normal);

  // compute the light vector pointing toward the sun, in model coordinates
  // x,y compose the longitude and z the (seasonal) lattitude of the nadir point.
  //vec3 lightVec = normalize(vec3(u_matViewInverseTranspose * vec4(u_lightVec, 1.0)));
  vec3 lightVec = normalize(normalMatrix * lightVector);

  // Calculate a diffuse light intensity
  //v_diffuse = dot(lightVec, n);
  v_diffuse = clamp(dot(n, lightVec), 0.0, 1.0);

  vec4 ecPosition = u_matModelView * a_position;
  // compute the reflection vector
  vec3 reflectVec = reflect(-lightVec, n);
  // compute a unit vector in direction of viewing position
  vec3 viewVec    = normalize(vec3(-ecPosition));

  // Calculate specular light intensity, scale down and apply a tint. 
  float specIntensity = pow(max(dot(reflectVec, viewVec), 0.0), 8.0);       
  v_specular            = specIntensity  * 
                        //gloss color
                        vec3(1.,.7,.3) * 
                        //gloss intensity
                        .7;     

  v_texCoord.y = 1.-a_texCoord0.y;
  v_texCoord.x = a_texCoord0.x; 

  vec3 lightDir = normalize(lightVector - u_matModelView * a_position);

  vec3 tangent=a_tangent;
  vec3 t = normalize(normalMatrix * tangent);
  vec3 b = cross (n, t);    

  vec3 v;
  v.x = dot (lightDir, t);
  v.y = dot (lightDir, b);
  v.z = dot (lightDir, n);  

  v_lightVec = normalize (v);           
}

Fragment shader:

precision mediump float;

varying vec2 v_texCoord;
varying float v_diffuse;
varying vec3 v_specular;
varying vec3 v_lightVec;

uniform sampler2D u_texture;
uniform sampler2D u_normalMap;

void main()
{   
  vec3 ground = texture2D(u_texture, v_texCoord).rgb;

  vec3 normal  = normalize(2.0 * texture2D (u_normalMap, v_texCoord).rgb - 1.0);
  float lamberFactor = max (dot (normal, v_lightVec), 0.0);   

  vec3 color = ( ground.rgb * v_diffuse * lamberFactor + v_specular);

  gl_FragColor = vec4 (color, 1.0);             
}

Result:

As you can see the result is rendered correctly. Specular spot behaves like from many examples. But I need to implement specular color in fragment shader to get more impressive picture. So I found example from here and now I'm trying to make it works.

Vertex shader:

attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec3 a_normal;
attribute vec3 a_tangent; 

varying vec2 v_texCoord;   
varying vec3 v_lightVec;
varying vec3 v_eyeVec;  //Added

uniform mat4 u_worldTrans;
uniform mat4 u_projTrans;
uniform mat4 u_matViewInverseTranspose;
uniform mat4 u_matModelView;

const vec3 lightVector = vec3(0.0,0.0,-1.0);

void main()
{
  // Output the unmodified vertex position. 
  gl_Position = u_projTrans * u_worldTrans * a_position;

  mat3 normalMatrix = mat3(u_matViewInverseTranspose);
  // compute the transformed normal
  vec3 n = normalize(normalMatrix * a_normal);

  v_texCoord.y = 1.-a_texCoord0.y;
  v_texCoord.x = a_texCoord0.x; 

  vec3 lightDir = normalize(lightVector - u_matModelView * a_position);

  vec3 tangent=a_tangent;
  vec3 t = normalize(normalMatrix * tangent);
  vec3 b = cross (n, t);    

  vec3 v;
  v.x = dot (lightDir, t);
  v.y = dot (lightDir, b);
  v.z = dot (lightDir, n);  

  v_lightVec = normalize (v);

  //Added
  vec3 ecPosition = u_matModelView * a_position;  

  vec3 tmp = vec3(-ecPosition);
  v_eyeVec.x = dot(tmp, t);
  v_eyeVec.y = dot(tmp, b);
  v_eyeVec.z = dot(tmp, n);
  v_eyeVec = normalize (v_eyeVec);  
}

Fragment shader:

precision mediump float;

varying vec2 v_texCoord;
varying vec3 v_lightVec;
varying vec3 v_eyeVec; 

uniform sampler2D u_texture;
uniform sampler2D u_normalMap;

void main()
{   
  vec3 ground = texture2D(u_texture, v_texCoord).rgb;       
  vec3 normal  = normalize(2.0 * texture2D (u_normalMap, v_texCoord).rgb - 1.0);

  //Added
  float distSqr = dot(v_lightVec, v_lightVec);
  float att = clamp(1.0 - .25 * sqrt(distSqr), 0.0, 1.0);
  vec3 lVec = v_lightVec * inversesqrt(distSqr);

  vec3 vVec = normalize(v_eyeVec);  
  vec3 bump = normalize( texture2D(u_normalMap, v_texCoord).xyz * 2.0 - 1.0);

  float diffuse = max( dot(lVec, bump), 0.0 );

  vec3 specular = pow(clamp(dot(reflect(-lVec, bump), v_eyeVec), 0.0, 1.0), 8.0 ) *
                        //gloss color
                        vec3(1.,.7,.3) * 
                        //gloss intensity
                        .7; 

  vec3 color = ( ground.rgb * diffuse + specular) * att;          
  gl_FragColor = vec4 (color, 1.0);
}    

Result:

Specular spot is wrong. I thought it happens because of wrong matrix calculation. If it's true why do first couple of shaders work correctly? How do I get model-view matrix, normal matrix and others in LibGDX?

 viewInvTraMatrix.set(camera.view);     
 viewInvTraMatrix.mul(renderable.worldTransform);
 //model-view matrix
 program.setUniformMatrix("u_matModelView", viewInvTraMatrix);
 viewInvTraMatrix.inv(); //inverse
 viewInvTraMatrix.tra(); //transpose
 //normal matrix
 program.setUniformMatrix("u_matViewInverseTranspose", viewInvTraMatrix);

 //other matrix
 program.setUniformMatrix("u_worldTrans", renderable.worldTransform);
 program.setUniformMatrix("u_projTrans", camera.combined);

So, my question is what is wrong in the last couple of shaders?


回答1:


The problem was in my model(mesh). After some time of digging I found out that my mesh doesn't have tangents and binormals. It happend because I used Blender 2.58 which cannot export model to FBX with tangent space. Fortunately, they fixed this bug in Blender 2.71 and later. So, when you export your model, you should tick Tangent Space parameter and choose version FBX 7.4 binary. To ensure that your mesh contains tangents and binormals, you can use fbx-converter tool to convert your fbx file to g3dj format instead of default g3db by using additional option like below:

fbx-converter.exe -o g3dj yourModel.fbx yourConvertedModel.g3dj

Then open it in some program like Notepad and check that attributes contain TANGENT and BINORMAL

"version": [  0,   1], 
"id": "", 
"meshes": [
    {
        "attributes": ["POSITION", "NORMAL", "TANGENT", "BINORMAL", "TEXCOORD0"], 
        "vertices": [
             0.257400,  58.707802, -0.257400,  0.000000,  1.000000, -0.000000,  0.941742,

Only one thing I don't understand, why does lamberFactor work with wrong tangent attribute(actually, without it)? Most likely, diffuse color is wrong calculated, but in my example(on sphere) it looks pretty satisfactorily. I hope it will help somebody else.

EDIT

By the way, to get a normal & a model-view matrices, I use the following code:

myMatrix.set(camera.view);  
myMatrix.mul(renderable.worldTransform);
program.setUniformMatrix(u_matModelView, myMatrix); //pass model-view matrix
myMatrix.inv();
myMatrix.tra();
program.setUniformMatrix(u_matNormal, myMatrix); //pass normal matrix


来源:https://stackoverflow.com/questions/29825918/normal-mapping-glsl-using-libgdx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!