Libgdx使用“法线贴图”纹理为3D中的着色器

时间:2014-03-19 15:44:13

标签: opengl 3d libgdx shader normals

在阅读有关GLSL的this Tutorial以及如何使用“法线贴图”从简单的石墙中创建如此强大的动态Texture之后,我对Shader的强大力量印象深刻秒。
由于我对Shader和3D很新,我想知道如何将这种Shader应用到我的wip 3D游戏中。所以我正在寻找更多的教程,我找到了this,这让我对Shader及其逻辑有了更多的了解。但我不知道我是否真的理解它,所以我在这里问 我想做什么:我有一些基本的Wall,由简单的纹理立方体组成。 Texture与我链接的第一个教程大致相同。我有Normal Map Texture,也就像在教程中一样,我希望为那些Texture添加相同的效果,但正如我所说的那样是3D。
因此,据我所知,我不需要改变任何东西,而是Normal Map。我必须知道块的面,Texture将其法线乘以面法线(例如左面的Vector3(-1,0,0))旋转它(例如,Y-Axis绕着Face旋转90°。这个假设是正确的还是我走错了路? 如果我是对的,而不是使用Normal Map Texture,还有一种方法可以获得导入的g3db Model的每个“像素”(点)的正常吗?

1 个答案:

答案 0 :(得分:1)

您可以使用您想要的着色器作为输入,但texure是每个片段修改的常见输入。

Uniform Buffer vs Texture Performances considerations

具有切线空间信息(每个像素坐标系)的经典法线贴图技术可以被其他技术(例如凹凸贴图)甚至您自己的实现覆盖。请注意,必须预先计算用于法线或凹凸贴图的切线矢量(Tangent,Binormal,Normal)并将其添加到顶点属性中。您可以使用脏技巧在顶点着色器中计算它们,但这会导致一些故障。

您的示例仅使用片段着色器,因此您确定缺少某些内容以使其在3d场景中工作。

为了在3d中工作,你需要实现一个顶点着色器,它将处理每个顶点法线(here is a implementation):

 [Vertex_Shader]

varying vec3 lightVec; 
varying vec3 eyeVec;
varying vec2 texCoord;
attribute vec3 vTangent; 


void main(void)
{
    gl_Position = ftransform();
    texCoord = gl_MultiTexCoord0.xy;

    vec3 n = normalize(gl_NormalMatrix * gl_Normal);
    vec3 t = normalize(gl_NormalMatrix * vTangent);
    vec3 b = cross(n, t);

    vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
    vec3 tmpVec = gl_LightSource[0].position.xyz - vVertex;

    lightVec.x = dot(tmpVec, t);
    lightVec.y = dot(tmpVec, b);
    lightVec.z = dot(tmpVec, n);

    tmpVec = -vVertex;
    eyeVec.x = dot(tmpVec, t);
    eyeVec.y = dot(tmpVec, b);
    eyeVec.z = dot(tmpVec, n);
}

[Pixel_Shader]

varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoord;
uniform sampler2D colorMap;
uniform sampler2D normalMap;
uniform float invRadius;

void main (void)
{
    float distSqr = dot(lightVec, lightVec);
    float att = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0);
    vec3 lVec = lightVec * inversesqrt(distSqr);

    vec3 vVec = normalize(eyeVec);

    vec4 base = texture2D(colorMap, texCoord);

    vec3 bump = normalize( texture2D(normalMap, texCoord).xyz * 2.0 - 1.0);

    vec4 vAmbient = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;

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

    vec4 vDiffuse = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * 
                    diffuse;    

    float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 
                     gl_FrontMaterial.shininess );

    vec4 vSpecular = gl_LightSource[0].specular * gl_FrontMaterial.specular * 
                     specular;  

    gl_FragColor = ( vAmbient*base + 
                     vDiffuse*base + 
                     vSpecular) * att;
}

如果你不将它们添加到你的顶点属性中,你可以使用脏技巧来获得切线

vec3 c1 = cross( gl_Normal, vec3( 0, 0, 1 ) );
vec3 c2 = cross( gl_Normal, vec3( 0, 1, 0 ) );

if( length( c1 ) > length( c2 ) ) tangent = normalize( c1 );
else tangent = normalize( c2 );