varying vec2 texCoord; varying vec3 vNormal; varying vec3 eyePos; uniform float emission; uniform vec3 ambientColor; uniform vec3 specularColor; uniform vec3 diffuseColor; uniform float hardness; uniform float mistEnable; uniform float mistStart; uniform float mistDistance; uniform float mistIntensity; uniform float mistType; uniform vec3 mistColor; #define maxLights 16 uniform int lightCount; uniform int lightType[maxLights]; uniform vec3 lightColor[maxLights]; uniform vec3 lightPosition[maxLights]; uniform vec3 lightOrientation[maxLights]; uniform float lightDistance[maxLights]; uniform float lightSpotsize[maxLights]; uniform float lightSpotblend[maxLights]; #define SPOT 0 #define SUN 1 #define POINT 2 #define NORMAL 2 #define HEMI 3 #define M_PI 3.14159265358979323846 // ########################################Functions######################################## float exp_blender(float f) { return pow(2.71828182846, f); } float linearrgb_to_srgb(float c) { if(c < 0.0031308) return (c < 0.0) ? 0.0: c * 12.92; else return 1.055 * pow(c, 1.0/2.4) - 0.055; } float srgb_to_linearrgb(float c) { if(c < 0.04045) return (c < 0.0) ? 0.0: c * (1.0 / 12.92); else return pow((c + 0.055)*(1.0/1.055), 2.4); } vec3 linearrgb_to_srgb(vec3 col_from) { vec3 col_to; col_to.r = linearrgb_to_srgb(col_from.r); col_to.g = linearrgb_to_srgb(col_from.g); col_to.b = linearrgb_to_srgb(col_from.b); return col_to; } vec3 srgb_to_linearrgb(vec3 col_from) { vec3 col_to; col_to.r = srgb_to_linearrgb(col_from.r); col_to.g = srgb_to_linearrgb(col_from.g); col_to.b = srgb_to_linearrgb(col_from.b); return col_to; } float shade_hemi_spec(vec3 N, vec3 H, float hard) { float NdotH = dot(N, H) * 0.5 + 0.5; float specfac = pow(max(NdotH, 0.0), hard); return specfac; } float shade_phong_spec(vec3 N, vec3 H, vec3 L, vec3 E, float hard) { float rslt = max(dot(H, N), 0.0); float specfac = pow(rslt, hard); return specfac; } float shade_cooktorr_spec(vec3 H, vec3 N, vec3 E) { float specfac; float NdotH = dot(N, H); if(NdotH < 0.0) { specfac = 0.0; } else { float maxNdotE = max(dot(N, E), 0.0); specfac = pow(NdotH, hardness); specfac = specfac / (0.1 + maxNdotE); } return specfac; } float shade_blinn_spec(vec3 N, vec3 H, vec3 L, vec3 E, float refrac, float spec_power) { float specfac; if(refrac < 1.0) { specfac = 0.0; } else if(spec_power == 0.0) { specfac = 0.0; } else { if(spec_power<100.0) spec_power= sqrt(1.0/spec_power); else spec_power= 10.0/spec_power; float NdotH = dot(N, H); if(NdotH < 0.0) { specfac = 0.0; } else { float maxNdotE = max(dot(N, E), 0.01); float NdotL = dot(N, L); if(NdotL <= 0.01) { specfac = 0.0; } else { float maxEdotH = max(dot(E, H), 0.01); float a = 1.0; float b = (2.0 * NdotH * maxNdotE) / maxEdotH; float c = (2.0 * NdotH * NdotL) / maxEdotH; float g = 0.0; if(a < b && a < c) g = a; else if(b < a && b < c) g = b; else if(c < a && c < b) g = c; float p = sqrt(((refrac * refrac)+(maxEdotH*maxEdotH)-1.0)); float f = (((p-maxEdotH)*(p-maxEdotH))/((p+maxEdotH)*(p+maxEdotH)))*(1.0+((((maxEdotH*(p+maxEdotH))-1.0)*((maxEdotH*(p+maxEdotH))-1.0))/(((maxEdotH*(p-maxEdotH))+1.0)*((maxEdotH*(p-maxEdotH))+1.0)))); float ang = acos(NdotH); specfac = max(f*g*exp_blender((-(ang*ang)/(2.0*spec_power*spec_power))), 0.0); } } } return specfac; } float shade_wardiso_spec(vec3 N, vec3 H, vec3 E, vec3 L, float rms) { float maxNdotH = max(dot(N, H), 0.001); float maxNdotE = max(dot(N, E), 0.001); float maxNdotL = max(dot(N, L), 0.001); float angle = tan(acos(maxNdotH)); float alpha = max(rms, 0.001); float specfac= maxNdotL * (1.0/(4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle)/(alpha * alpha))/(sqrt(maxNdotE * maxNdotL))); return specfac; } float shade_toon_spec(vec3 N, vec3 H, float size, float tsmooth) { float specfac; float rslt; float NdotH = dot(N, H); float ang = acos(NdotH); if(ang < size) rslt = 1.0; else if(ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0; else rslt = 1.0 - ((ang - size)/tsmooth); specfac = rslt; return specfac; } vec3 shade_mist_blend(vec3 co, float enable, float miststa, float mistdist, float misttype, float intensity, vec3 col1, vec3 col2) { float mist = 0.0; if(enable == 1.0) { float fac, zcor; zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2]; fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0); if(misttype == 0.0) fac *= fac; else if(misttype == 1.0); else fac = sqrt(fac); mist = 1.0 - (1.0 - fac) * (1.0 - intensity); } float mixFac = clamp(mist, 0.0, 1.0); vec3 result = mix(col1, col2, mixFac); return result; } vec3 getLighting(vec3 normal, vec3 eyePos, vec3 color) //Calculates lighting { vec3 N = normal; vec3 E = normalize(eyePos); vec3 diffuse = vec3(0, 0, 0); vec3 specular = vec3(0, 0, 0); /* handle perspective/orthographic */ E = (gl_ProjectionMatrix[3][3] == 0.0) ? E : vec3(0.0, 0.0, -1.0); //workaround for for loop unrolling. Change type from int to float. for (float c = 0.0; c < float(lightCount); c++) { int i = int(c); float attenuation = 1.0; vec3 lightVec = vec3(0.0, 0.0, 1.0); if (lightType[i] == SPOT || lightType[i] == POINT) { lightVec = eyePos - lightPosition[i]; float lightDist = length(lightVec); // The invsquare attenuation calculation in Blender is not correct // I use Blenders attenuation calculation to get the same attenuation attenuation = lightDistance[i] / (lightDistance[i] + lightDist * lightDist); //attenuation = visifac in Blender shader code } else { lightVec = lightOrientation[i]; } vec3 L = normalize(lightVec); //L = lv in Blender shader code vec3 H = normalize(L+E); if (lightType[i] == SPOT) { float inpr = 0.0; vec2 scale = vec2(1.0, 1.0); float visifac = attenuation; inpr = dot(L, lightOrientation[i]); float t = lightSpotsize[i]; //spot size if(inpr <= t) { attenuation = 0.0; } else { /* soft area */ if(lightSpotblend[i] != 0.0) inpr *= smoothstep(0.0, 1.0, (inpr - t) / lightSpotblend[i]); attenuation = attenuation * inpr; } } float NdotL = dot(N, L); //float NdotH = dot(N, H); //float NdotE = dot(N, E); float ks; float kd; if (lightType[i] == HEMI) { NdotL = NdotL* 0.5 + 0.5; //NdotH = NdotH * 0.5 + 0.5; //ks = pow(max(NdotH, 0.0), hardness); ks = shade_hemi_spec(N, H, hardness); } else { //Phong specular shading ks = shade_phong_spec(N, H, L, E, hardness); //CookTorr specular shading //ks = shade_cooktorr_spec(H, N, E); //Toon specular shading /* float size = 0.5; float smooth = 0.1; ks = shade_toon_spec(N, H, size, smooth); */ //Wardiso specular shading /* float slope = 0.1; ks = shade_wardiso_spec(N, H, E, L, slope); */ //Blinn specular shading /* float refrac = 4.0; ks = shade_blinn_spec(N, H, L, E, refrac, hardness); */ } kd = max(NdotL, 0.0) * attenuation; diffuse += kd * color * lightColor[i]; ks = ks * attenuation; specular += ks * specularColor * lightColor[i]; } return diffuse + specular; } // ########################################Main-Function######################################## void main() { //vec3 normal = normalize(-normal); //activated Backface Culling (or when geometry shader will used) vec3 normal = (gl_FrontFacing)? normalize(-vNormal) : normalize(vNormal); //deactivated Backface Culling vec3 lighting = getLighting(normal, eyePos, diffuseColor); vec4 color = vec4((emission * diffuseColor) + ambientColor + lighting, 1.0); color.rgb = shade_mist_blend(eyePos, mistEnable, mistStart, mistDistance, mistType, mistIntensity, color.rgb, mistColor); color.rgb = linearrgb_to_srgb(color.rgb); gl_FragColor = color; }