Normal Mapping

Started by Calipe, September 15, 2013, 09:28:18 PM

Previous topic - Next topic

Calipe

Hi, I'm currently in the process of applying a normal map to an Object3D and followed the tutorial at: http://www.jpct.net/wiki/index.php/Shaders, and also the post regarding using shaders at: http://www.jpct.net/forum2/index.php/topic,2153.msg15838/topicseen.html#msg15838. However, I have a few questions.

I don't know how to send the color texture and normal texture to the fragment shader for processing. I have tried to implement the solution given in the aforementioned links but it doesn't seem to help. I know I'm missing a few parts but the documentation for JPCT-AE regarding shaders is quite limited.

I would like to thank anyone who can help me and maybe after this problem is solved I can help to write a more detailed tutorial on using Shaders with JPCT-AE as I feel this is a very important topic. Anyway, this so far is the only real problem I have had with JPCT-AE and think it's a really good 3D engine for Android.

Thanks!

Below you will find the code and the screenshots explaining my particular situation.

I load the 3D object with the following code:


InputStream totemOBJFile = mActivity.getResources().getAssets().open("totemLowPolyFixed.obj");

// Totem's texture files
InputStream totemTextureFile = mActivity.getResources().getAssets().open("TOTEM_Textura.jpg");
InputStream totemNormalFile = mActivity.getResources().getAssets().open("totem_normal.jpg");

textureManager.addTexture("totem_material", new Texture(totemTextureFile));
textureManager.addTexture("totem_normal.jpg", new Texture(totemNormalFile));

totem = Object3D.mergeAll(Loader.loadOBJ(totemOBJFile, null, scale));

TextureInfo ti=new TextureInfo(TextureManager.getInstance().getTextureID("totem_material"));
ti.add(TextureManager.getInstance().getTextureID("totem_normal.jpg"), TextureInfo.MODE_MODULATE);
   
totem.setTexture(ti);
   
totem.build();
totem.compile();
totem.setSpecularLighting(true);
totem.strip();

world.addObject(totem);

SimpleVector sv = new SimpleVector();
sv.set(totem.getTransformedCenter());
sv.y = -150;
sv.z = 0;
sun.setPosition(sv);

cam = world.getCamera();
cam.setPosition(0f, -150f, 0f);
cam.lookAt(totem.getTransformedCenter());

String vertex = null;
String fragment = null;
// Load the vertex and fragment shaders
try {
vertex = Loader.loadTextFile(mActivity.getResources().getAssets().open("glsl/normalmapping/vertexshader.glsl"));
fragment = Loader.loadTextFile(mActivity.getResources().getAssets().open("glsl/normalmapping/fragmentshader.glsl"));
GLSLShader shader=new GLSLShader(vertex, fragment);
shader.setStaticUniform("textureMap", 0);
shader.setStaticUniform("normalMap", 1);
shader.setStaticUniform("invRadius", 0.0005f);
totem.setShader(shader);
} catch (IOException e) {
e.printStackTrace();
}

MemoryHelper.compact();


The vertex shader:

uniform mat4 modelViewMatrix;
uniform mat4 modelViewProjectionMatrix;

uniform vec4 additionalColor;
uniform vec4 ambientColor;

uniform vec3 lightPositions[8];

attribute vec4 position;
attribute vec3 normal;
attribute vec4 tangent;
attribute vec2 texture0;

varying vec3 lightVec[2];
varying vec3 eyeVec;
varying vec2 texCoord;

void main(void)
{
texCoord = texture0.xy;

vec3 n = normalize(modelViewMatrix * vec4(normal,0.0)).xyz;
vec3 t = normalize(modelViewMatrix * vec4(tangent.xyz, 0.0)).xyz;

vec3 b = tangent.w*cross(n, t);

vec3 vVertex = vec3(modelViewMatrix * position);
vec3 tmpVec = lightPositions[0].xyz - vVertex;

vec3 lv;
vec3 ev;

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

lightVec[0]=lv;

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

gl_Position = modelViewProjectionMatrix * position;
}


The fragment shader:


precision mediump float;

varying vec3 lightVec[2];
varying vec3 eyeVec;
varying vec2 texCoord;

uniform sampler2D textureMap;
uniform sampler2D normalMap;

uniform vec3 diffuseColors[8];
uniform vec3 specularColors[8];

uniform vec4 ambientColor;

uniform float invRadius;

void main ()
{
vec4 vAmbient = ambientColor;
vec3 vVec = normalize(eyeVec);

vec2 newTexCoord = texCoord;

vec4 base = texture2D(textureMap, newTexCoord);
vec3 bump = normalize(texture2D(normalMap, newTexCoord).xyz * 2.0 - 1.0);

float distSqr = dot(lightVec[0], lightVec[0]);
float att = clamp(1.0 - invRadius * sqrt(distSqr), 0.0, 1.0);
vec3 lVec = lightVec[0] * inversesqrt(distSqr);

float diffuse = max(dot(lVec, bump), 0.0);
vec4 vDiffuse = vec4(diffuseColors[0],0) * diffuse;

float specular = pow(clamp(dot(reflect(-lVec, bump), vVec), 0.0, 1.0), 0.85);
vec4 vSpecular = vec4(specularColors[0],0) * specular;

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


The object without shaders:



The object with shaders:


Calipe

Ok guys, I was able to figure it out after looking at the HelloShader example that comes with JPCT-AE. As it turns out, it's quite easy to work with Shaders inside the engine...coming up with interesting shaders that do what they are intended to do is another story.

Anyway, here is the screenshot of the model with normal mapping applied to it.