我尝试使用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);
}
结果:
如您所见,结果已正确呈现。镜面光斑的行为类似于许多例子。但我需要在片段着色器中实现镜面反射颜色以获得更令人印象深刻的画面。所以我从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);
}
结果:
镜面反射是错误的。我认为这是因为错误的矩阵计算。如果这是真的,为什么第一批着色器工作正常?
如何在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);
所以,我的问题是最后几个着色器出了什么问题?
答案 0 :(得分:5)
问题出在我的模型(网格)中。经过一段时间的挖掘后,我发现我的网格没有tangents
和binormals
。之所以发生这种情况是因为我使用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
等某个程序中打开它,检查属性是否包含TANGENT
和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,
只有一件事我不明白,为什么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