Author Topic: Normal Mapping with Bones  (Read 10425 times)

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Normal Mapping with Bones
« on: December 07, 2013, 08:23:31 am »
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?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #1 on: December 07, 2013, 08:52:16 am »
Why should it break? On Android everything is compiled anyway and Bones works just fine with it.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #2 on: December 07, 2013, 06:43:49 pm »
All I know is that it does on my test.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #3 on: December 07, 2013, 06:51:54 pm »
That's a bit vague...you have compile it by using compile(true); and maybe a touch() after calling animate.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #4 on: December 07, 2013, 11:02:18 pm »
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.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #5 on: December 07, 2013, 11:52:36 pm »
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.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #6 on: December 09, 2013, 08:02:32 am »
You can try to disable the normal map in the former case by doing a call to

Code: [Select]
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

Code: [Select]
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.

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #7 on: December 09, 2013, 04:47:16 pm »
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.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #8 on: December 09, 2013, 08:08:11 pm »
Can you post the shaders that you are currently using?

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #9 on: December 09, 2013, 08:14:45 pm »
Sure. They're in the wiki:

Code: [Select]
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);
}

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #10 on: December 10, 2013, 07:42:47 am »
Try this vertex shader instead (make sure to assign it before calling build()):

Code: [Select]
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:

Code: [Select]
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.
« Last Edit: December 10, 2013, 07:45:59 am by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #11 on: December 10, 2013, 08:09:48 am »
It's completely black with this one.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #12 on: December 10, 2013, 08:12:36 am »
Are you sure that you did this:

Quote
make sure to assign it before calling build()

???

Offline AGP

  • quad
  • ******
  • Posts: 1726
    • View Profile
Re: Normal Mapping with Bones
« Reply #13 on: December 10, 2013, 08:22:40 am »
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:

Code: [Select]
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:
« Last Edit: December 10, 2013, 08:27:58 am by AGP »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Normal Mapping with Bones
« Reply #14 on: December 10, 2013, 08:30:32 am »
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.