使用LibGDX正常映射GLSL

时间:2015-04-23 14:06:28

标签: opengl libgdx glsl opengl-es-2.0 shader

我尝试使用LibGDX实现法线贴图。所以当我在顶点着色器中计算漫反射和镜面反射颜色时,我得到了一些积极的结果(至少我是这么认为的)。

顶点着色器:

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);           
}

片段着色器:

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);             
}

结果: Correct result

如您所见,结果已正确呈现。镜面光斑的行为类似于许多例子。但我需要在片段着色器中实现镜面反射颜色以获得更令人印象深刻的画面。所以我从here找到了例子,现在我试图让它起作用。

顶点着色器:

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);  
}

片段着色器:

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);
}    

结果:

Wrong result

镜面反射是错误的。我认为这是因为错误的矩阵计算。如果这是真的,为什么第一批着色器工作正常? 如何在LibGDX中获取model-view矩阵,normal矩阵和其他矩阵?

 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);

所以,我的问题是最后几个着色器出了什么问题?

1 个答案:

答案 0 :(得分:5)

问题出在我的模型(网格)中。经过一段时间的挖掘后,我发现我的网格没有tangentsbinormals。之所以发生这种情况是因为我使用Blender 2.58无法将模型导出到FBX并使用切线空间。幸运的是,他们在Blender 2.71及更高版本中修复了这个错误。因此,在导出模型时,应勾选Tangent Space参数并选择版本FBX 7.4 binary。为确保您的网格包含切线和副正规,您可以使用html5.1 nightly工具将fbx文件转换为g3dj格式,而不是默认g3db,方法是使用以下附加选项:

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

然后在Notepad等某个程序中打开它,检查属性是否包含TANGENTBINORMAL

"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,

只有一件事我不明白,为什么lamberFactor使用错误的切线属性(实际上,没有它)?很可能,漫反射颜色计算错误,但在我的例子中(在球体上),它看起来非常令人满意。我希望它会帮助别人。

修改

顺便说一句,要获得正常的&模型 - 视图矩阵,我使用以下代码:

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