Normal Mapping with Bones

Started by AGP, December 07, 2013, 08:23:31 AM

Previous topic - Next topic

AGP

The NormalMapping example on the wiki requires you to compile your model. But bones breaks with compiled models. So how do I go about applying a normal map to a bones-animated model?

EgonOlsen

Why should it break? On Android everything is compiled anyway and Bones works just fine with it.

AGP

All I know is that it does on my test.

EgonOlsen

That's a bit vague...you have compile it by using compile(true); and maybe a touch() after calling animate.

AGP

OK, compile(true) worked for me. Now, consider the following screenshot:


Two questions: in order for me to enable/disable the normal mapping (for comparison purposes and performance settings), I need to remove the normal map from its TextureInfo in order to avoid the blueishness seen on the left Batman. How do I go about doing that? And the second question: why is that white line on the normal-mapped Batman's chest? Surely that's not an issue of the map itself as that line doesn't show in 3ds max.

AGP

And a follow-up to the second question: how do I set a specular map? I expect that this would solve the problem, but simply adding a map after the normal map to TextureInfo didn't help at all.

EgonOlsen

You can try to disable the normal map in the former case by doing a call to

normalMap.setEnabled(false);

About the white line: That's an artifact of the way in which "my" normal mapping shader handles tangent vectors. It creates them in the shader, which isn't really accurate and fails in some cases. jPCT can calculate proper tangent vectors for you and feed them into the shader if the shader provides an attribute like

attribute vec4 tangent;

You have to modify the shader to use that instead of the calculated value of source. Have a look at the shaders in the HelloShader example to see what to do.

AGP

Disabling the texture worked, thanks. What about a specular map so that Batman doesn't look so metallic?

And help me out with the shader, man. I've barely even ever looked at one before.

EgonOlsen

Can you post the shaders that you are currently using?

AGP

Sure. They're in the wiki:


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

varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoord;

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

// jPCT doesn't provide the tangent vector...compute it (this isn't 100% accurate...)

vec3 c1 = cross(gl_Normal, vec3(0.0, 0.0, 1.0));
vec3 c2 = cross(gl_Normal, vec3(0.0, 1.0, 0.0));

vec3 vTangent=c1;
if (length(c2)>length(vTangent)) {
vTangent=c2;
}

vTangent = normalize(vTangent);

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

EgonOlsen

#10
Try this vertex shader instead (make sure to assign it before calling build()):


attribute vec4 tangent;

varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoord;

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

vec3 n = normalize(gl_NormalMatrix * gl_Normal);
vec3 t = normalize(gl_NormalMatrix * tangent.xyz);
vec3 b = tangent.w * 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);
}


About a specular map: Not sure if that is what you are looking for and the shader doesn't support one anyway. I would try to play around with the final color term in the fragment shader:


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


See if you can make the shininess less prominent. If you start to use shaders, you have to get a basic understanding of what they do and how they work or you won't get far. Fiddling around with that term is a good starting point IMHO.

AGP

It's completely black with this one.

EgonOlsen

Are you sure that you did this:

Quote
make sure to assign it before calling build()

???

AGP

#13
Yup, I assigned it before build() (I hadn't even called build() at all before you mentioned it, just now, believe or not; but now I'm calling it after assigning the shader). This is my light code, for whatever it's worth:


light = new Light(theWorld);
SimpleVector position = new SimpleVector(batman.model.get(0).getTransformedCenter());
position.x += 60f;
position.y -= 40f;
position.z -= 60f;
light.setPosition(position);
light.setIntensity(185, 185, 145);
light.setDiscardDistance(-1f);
light.setAttenuation(light.getAttenuation()*1.5f);


And this is how it looks:

EgonOlsen

The only thing that has changed in that shader is the use of the tangent vectors attribute instead of the internal calculation. The rest is 100% the same thing and in addition, the result is equal to the example shader in the HelloShader example that comes with jPCT. So this shader is fine, if the tangent vectors are. And they should be if the engine detects that the shader needs them. Maybe there's some hidden build() in your code...try to force tangent vector calculations by calling Object3D.calcTangentVectors() on the model.