Just tested some per-pixel lightning shaders in jME today and thought it might be worth showing.
These are the maps I used:
And this is three screenshots of it in action.
Wow, looks sweet! Congrats! Any chance to make it public ?
can you make a video to show of the effect better?
Cool! You're not just going to tease us with that are you? You're going to post the shaders and a test case aren't you?
Wow… it's quite simple to make those shaders and/or search on the forum and internet for them. (spec/normal are quite popular so they are everywhere).
Here's what I use for terrain:
uniform int n_lights;
varying vec3 vLightVector[gl_MaxLights];
#ifdef FIRST_SPEC
varying vec3 vHalfAngle;
#else
varying vec3 vHalfAngle[gl_MaxLights];
#endif
void main(){
gl_Position = ftransform();
gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
vec3 normal = normalize(gl_Normal);
vec3 binormal;
vec3 c1 = cross(normal, vec3(0.0, 1.0, 0.0));
vec3 c2 = cross(normal, vec3(0.0, 0.0, 1.0));
if(length(c1)>length(c2)){
binormal = c1;
}else{
binormal = c2;
}
vec3 tangent = cross(normal, binormal);
vec3 vNormal = gl_NormalMatrix * normal;
vec3 vBinormal = gl_NormalMatrix * binormal;
vec3 vTangent = gl_NormalMatrix * tangent;
vec3 eye_Vertex = (gl_ModelViewMatrix * gl_Vertex).xyz;
for (int i = 0; i < 4; i++){
if (i < n_lights){
vec3 temp_light_vector = gl_LightSource[i].position.xyz - eye_Vertex;
vLightVector[i].x = dot( temp_light_vector, vTangent );
vLightVector[i].y = dot( temp_light_vector, vBinormal );
vLightVector[i].z = dot( temp_light_vector, vNormal );
#ifndef FIRST_SPEC
vec3 halfTemp = gl_LightSource[i].halfVector.xyz;
vHalfAngle[i].x = dot(halfTemp, vTangent);
vHalfAngle[i].y = dot(halfTemp, vBinormal);
vHalfAngle[i].z = dot(halfTemp, vNormal);
#endif
}
}
#ifdef FIRST_SPEC
vec3 halfTemp = gl_LightSource[i].halfVector.xyz;
vHalfAngle.x = dot(halfTemp, vTangent);
vHalfAngle.y = dot(halfTemp, vBinormal);
vHalfAngle.z = dot(halfTemp, vNormal);
#endif
}
uniform int n_lights;
uniform sampler2D bump_map;
uniform sampler2D base_map;
uniform sampler2D spec_map;
varying vec3 vLightVector[gl_MaxLights];
#ifdef FIRST_SPEC
varying vec3 vHalfAngle;
#else
varying vec3 vHalfAngle[gl_MaxLights];
#endif
void main(void){
vec2 vTexCoord = gl_TexCoord[0].xy;
vec4 base = texture2D( base_map, vTexCoord );
vec3 bump = normalize( ( texture2D( bump_map, vTexCoord ).xyz * 2.0 ) - 1.0 );
vec3 specular = texture2D( spec_map, vTexCoord ).xyz;
#ifdef FIRST_SPEC
float n_dot_h = max(0.0, dot(bump, normalize(vHalfAngle) ) );
vec3 sum_specular = pow(n_dot_h, gl_FrontMaterial.shininess ) * gl_LightSource[0].specular.xyz;;
#else
vec3 sum_specular = vec3(0.0);
#endif
vec3 sum_diffuse = vec3(0.0);
for (int i = 0; i < 4; i++){
if (i < n_lights){
sum_diffuse += max(0.0, dot(bump, normalize( vLightVector[i] )) ) * gl_LightSource[i].diffuse.xyz;;
#ifndef FIRST_SPEC
float n_dot_h = max(0.0, dot(bump, normalize(vHalfAngle[i]) ) );
sum_specular += pow(n_dot_h, gl_FrontMaterial.shininess ) * gl_LightSource[i].specular.xyz;
#endif
}
}
vec3 color0 = (vec3(0.1) + sum_diffuse) * base.xyz + sum_specular * specular;
gl_FragColor = vec4(color0.xyz, base.a);
}
It generates tangent/binormal so it wont work on some meshes. It's quite simple to edit it to get them from vertex attributes though.
Haladria said:
Just tested some per-pixel lightning shaders in jME today and thought it might be worth showing.
plz plz plz ... shaders and testcase :)
I'd love to get something like that going.
thx in advance,
Andy
i'm in need of a spec/normal/diffuse-shader that doesn't ignore the distance to the light source and works with more than just one. is there a simple one out there somewhere?
You can use the one I posted with some small changes. Just loop thru all ( 8 ) lightsources with a for loop and for the point lights adjust the effect from the light with the opengl light attenuation formula:
att = 1.0 / (gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist + gl_LightSource[0].quadraticAttenuation * dist * dist);
there is similar code in the jme TestNormalmap and normalmap.vert/.frag
I've missed that one totally, probably because it was located in loader instead of glsl directory. Seems like the shader is reading the tangent from gl_Color but where is that value set in the test case?
Modified version of the 1 light Parallax shader from jmetest to support pointlight with attenuation and ‘heightmap’ texture:
http://imagebin.org/28719
//attribute vec3 modelTangent;
//attribute vec3 modelBinormal;
varying vec3 viewDirection;
varying vec3 lightDirection;
varying float att;
void main(void)
{
/* Transform vertices and pass on texture coordinates */
gl_Position = ftransform();
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
/* Transform vertex into viewspace */
vec4 vertexViewSpace = gl_ModelViewMatrix * gl_Vertex;
/* Get view and light directions in viewspace */
vec3 localViewDirection = -vertexViewSpace.xyz;
vec3 localLightDist = gl_LightSource[0].position.xyz - vertexViewSpace.xyz;
float dist = length(localLightDist.xyz);
att = 1.0 / (gl_LightSource[0].constantAttenuation + gl_LightSource[0].linearAttenuation * dist + gl_LightSource[0].quadraticAttenuation * dist * dist);
vec3 localLightDirection = normalize(localLightDist);
/* Calculate tangent info - stored in colorbuffer */
vec3 normal = gl_NormalMatrix * gl_Normal;
vec3 tangent = gl_NormalMatrix * (gl_Color.xyz*2.0-1.0);
vec3 binormal = cross( tangent, normal );
/* Transform localViewDirection into texture space */
viewDirection.x = dot( tangent, localViewDirection );
viewDirection.y = dot( binormal, localViewDirection );
viewDirection.z = dot( normal, localViewDirection );
/* Transform localLightDirection into texture space */
lightDirection.x = dot( tangent, localLightDirection );
lightDirection.y = dot( binormal, localLightDirection );
lightDirection.z = dot( normal, localLightDirection );
}
uniform sampler2D baseMap;
uniform sampler2D normalMap;
uniform sampler2D specularMap;
uniform sampler2D heightMap;
varying vec3 viewDirection;
varying vec3 lightDirection;
varying float att;
uniform float heightValue;
void main(void)
{
/* Normalize view and light directions(need per-pixel normalized length) */
vec3 normalizedViewDirection = normalize( viewDirection );
vec3 normalizedLightDirection = normalize( lightDirection );
/* Extract colors from baseMap and specularMap */
// vec4 baseColor = texture2D( baseMap, gl_TexCoord[0].xy );
vec4 specularColor = texture2D( specularMap, gl_TexCoord[0].xy );
vec4 heightColor = texture2D( heightMap, gl_TexCoord[0].xy );
float height = length(heightColor.xyz) * heightValue - heightValue * 0.5;
vec2 newTexcoord = gl_TexCoord[0].xy - normalizedViewDirection.xy * height;
vec4 baseColor = texture2D( baseMap, newTexcoord );
/* Calculate diffuse - Extract and expand normal and calculate dot angle to lightdirection */
vec3 normal = normalize( ( texture2D( normalMap, gl_TexCoord[0].xy ).xyz * 2.0 ) - 1.0 );
float NDotL = dot( normal, normalizedLightDirection );
/* Calculate specular - Calculate reflection vector and dot angle to viewdirection */
vec3 reflection = normalize( ( ( 2.0 * normal ) * NDotL ) - normalizedLightDirection );
float RDotV = max( 0.0, dot( reflection, normalizedViewDirection ) );
/* Sum up lighting models with OpenGL provided light/material properties */
vec4 totalAmbient = ( gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient ) * baseColor;
vec4 totalDiffuse = gl_FrontLightProduct[0].diffuse * max( 0.0, NDotL ) * baseColor;
vec4 totalSpecular = gl_FrontLightProduct[0].specular * specularColor * ( pow( RDotV, gl_FrontMaterial.shininess ) );
/* Set final pixel color as sum of lighting models */
vec4 attMul = vec4(att,att,att,1.0);
gl_FragColor = totalAmbient * attMul + totalDiffuse * attMul + totalSpecular * attMul;
}
Thanks timong! Looks good.