OK...I'm really new to shaders and I've been working on this for about a week.
The goal: a shader that will handle up to 5 lights, normal mapping, passing the object texture offset (numbers across and down, not the actual offsets) in R and G of the object color, passing the ambient light level in the B parameter, and the object's alpha in A.
I think I've got it, but I'd love someone who knows this stuff to take a look.
Here's the vertex shader:
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
attribute vec3 tangent;
attribute vec3 binormal;
varying vec2 uvVarying;
varying vec3 normalVarying;
varying vec3 posVarying;
varying vec3 vLightP;
varying vec3 vLightP2;
varying vec3 vLightP3;
varying vec3 vLightP4;
varying vec3 vLightP5;
uniform vec4 uvBounds0;
uniform mat4 agk_World;
uniform mat4 agk_ViewProj;
uniform mat3 agk_WorldNormal;
uniform vec3 vPLightPos;
uniform vec3 vPLightPos2;
uniform vec3 vPLightPos3;
uniform vec3 vPLightPos4;
uniform vec3 vPLightPos5;
void main()
{
vec4 pos = agk_World * vec4(position,1);
gl_Position = agk_ViewProj * pos;
vec3 norm = agk_WorldNormal * normal;
posVarying = pos.xyz;
normalVarying = norm;
uvVarying = uv * uvBounds0.xy + uvBounds0.zw;
mat3 TBNMatrix = mat3(tangent, binormal, norm); //changed normal to norm
vLightP = vPLightPos.xyz - position;
vLightP *= TBNMatrix;
vLightP2 = vPLightPos2.xyz - position;
vLightP2 *= TBNMatrix;
vLightP3 = vPLightPos3.xyz - position;
vLightP3 *= TBNMatrix;
vLightP4 = vPLightPos4.xyz - position;
vLightP4 *= TBNMatrix;
vLightP5 = vPLightPos5.xyz - position;
vLightP5 *= TBNMatrix;
}
and here's the pixel shader:
uniform sampler2D texture0;
uniform sampler2D texture1;
varying vec2 uvVarying;
varying vec3 normalVarying;
varying vec3 posVarying;
varying vec3 vLightP;
uniform vec4 vPLightColor;
varying vec3 vLightP2;
uniform vec4 vPLightColor2;
varying vec3 vLightP3;
uniform vec4 vPLightColor3;
varying vec3 vLightP4;
uniform vec4 vPLightColor4;
varying vec3 vLightP5;
uniform vec4 vPLightColor5;
uniform vec4 Resolution;
uniform float texSize;
uniform float subtexSize;
uniform vec4 agk_ObjColor; //r = tex x, g = tex y, b = brightness, a = alpha
vec4 hsv_to_rgb(float h, float s, float v, float a)
{
float c = v * s;
h = mod((h * 6.0), 6.0);
float x = c * (1.0 - abs(mod(h, 2.0) - 1.0));
vec4 color;
if (0.0 <= h && h < 1.0) {
color = vec4(c, x, 0.0, a);
} else if (1.0 <= h && h < 2.0) {
color = vec4(x, c, 0.0, a);
} else if (2.0 <= h && h < 3.0) {
color = vec4(0.0, c, x, a);
} else if (3.0 <= h && h < 4.0) {
color = vec4(0.0, x, c, a);
} else if (4.0 <= h && h < 5.0) {
color = vec4(x, 0.0, c, a);
} else if (5.0 <= h && h < 6.0) {
color = vec4(c, 0.0, x, a);
} else {
color = vec4(0.0, 0.0, 0.0, a);
}
color.rgb += v - c;
return color;
}
vec3 light(vec3 vTLightPos,vec4 vTLightColor,vec2 uvOut)
{
vec3 normal = texture2D(texture1, uvOut.xy).rgb;
vec3 LDIR=normalize(vTLightPos);
normal = normal * 2.0 - 1.0;
vec3 NDIR=normalize(normal);
float intensity = dot(normalize(vTLightPos),normal);
intensity = clamp(intensity,0.0,1.0);
return vTLightColor.rgb * max(dot(NDIR, LDIR), 0.0) * intensity;
}
void main()
{
vec2 uvOut = uvVarying * (subtexSize-1.0)/(texSize-1.0); //scale the existing UVs to texSize width and height
uvOut.x = uvOut.x + 255.0*agk_ObjColor.r * (subtexSize/texSize);
uvOut.y = uvOut.y + 255.0*agk_ObjColor.g * (subtexSize/texSize);
vec4 diffuse = texture2D(texture0, uvOut.xy);
vec3 PLight = vec3(agk_ObjColor.b, agk_ObjColor.b, agk_ObjColor.b) + light(vLightP, vPLightColor, uvOut) + light(vLightP2,vPLightColor2,uvOut) + light(vLightP3,vPLightColor3,uvOut) + light(vLightP4,vPLightColor4,uvOut) + light(vLightP5,vPLightColor5,uvOut);
gl_FragColor = diffuse * vec4(PLight, agk_ObjColor.a);
}
Cobbled together and modified from about 1,000 examples here and on the internet. I also use a few "undocumented" things from agk...I just assumed that there'd be a tangent and binormal vector available...and my example seems to indicate that they do exist but I haven't seen any documentation.
I know the attenuation is cheap, but I've been focused hard on correct normal mapping and the 5 light problem.
Here's some agk code to set the shader up:
// the size of each item in the texture atlas
SetShaderConstantByName(shader1,"subtexSize",128,0,0,0)
// the size of the SQUARE texture atlas
SetShaderConstantByName(shader1,"texSize",2048,0,0,0)
// window width and height
SetShaderConstantByName(shader1,"Resolution",width,height,0,0)
// one light position and color
SetShaderConstantByName(shader1,"vPLightPos", lightx, 3,lightz,0)
SetShaderConstantByName(shader1,"vPLightColor",0.8,0.8,0.8,1.0)
// 2nd light position and color
SetShaderConstantByName(shader1,"vPLightPos2", 4, 0,0,0)
SetShaderConstantByName(shader1,"vPLightColor2",0.8,0.0,0.0,0.3)
Oh...and the hsv to rgb code is there as, after I get some validation that this really is normal mapping correctly, I'll be using the object R channel for the texture number and deriving the offsets from that while converting the G to the H part of HSV so I can do some really basic object coloring.
Would appreciate it if anyone that really knows this stuff could check it out to validate that it's really doing normal mapping. And...any comment from the AppGameKit devs as to parameters available to shaders would be great too!
Born. Currently living.