I´ve used a spotlight as a basis, so they´re very simple and fast, also. You can orient them and change their width and height. They cast no shadow, that will be a different thread :D (a very blurred pcss shadowmap should do the trick). I´m very excited about them because (at least for me) they open a new world of illumination schemes!

Screenies:

Code: (there is room for optimization but it´s usable as it is)

vec3 projectOnPlane(in vec3 p, in vec3 pc, in vec3 pn) { float distance = dot(pn, p-pc); return p - distance*pn; } int sideOfPlane(in vec3 p, in vec3 pc, in vec3 pn){ if (dot(p-pc,pn)>=0.0) return 1; else return 0; } vec3 linePlaneIntersect(in vec3 lp, in vec3 lv, in vec3 pc, in vec3 pn){ return lp+lv*(dot(pn,pc-lp)/dot(pn,lv)); } void areaLight(in int i, in vec3 N, in vec3 V, in float shininess, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular) { vec3 right = normalize(vec3(gl_ModelViewMatrix*gl_LightSource[i].ambient)); vec3 pnormal = normalize(gl_LightSource[i].spotDirection); vec3 up = normalize(cross(right,pnormal)); //width and height of the area light: float width = 1.0; float height = 4.0; //project onto plane and calculate direction from center to the projection. vec3 projection = projectOnPlane(V,vec3(gl_LightSource[i].position.xyz),pnormal);// projection in plane vec3 dir = projection-vec3(gl_LightSource[i].position.xyz); //calculate distance from area: vec2 diagonal = vec2(dot(dir,right),dot(dir,up)); vec2 nearest2D = vec2(clamp( diagonal.x,-width,width ),clamp( diagonal.y,-height,height)); vec3 nearestPointInside = vec3(gl_LightSource[i].position.xyz)+(right*nearest2D.x+up*nearest2D.y); float dist = distance(V,nearestPointInside);//real distance to area rectangle vec3 L = normalize(nearestPointInside - V); float attenuation = calculateAttenuation(i, dist); float nDotL = dot(pnormal,-L); if (nDotL > 0.0 && sideOfPlane(V,vec3(gl_LightSource[i].position.xyz),pnormal) == 1) //looking at the plane { //shoot a ray to calculate specular: vec3 R = reflect(normalize(-V), N); vec3 E = linePlaneIntersect(V,R,vec3(gl_LightSource[i].position.xyz),pnormal); float specAngle = dot(R,pnormal); if (specAngle > 0.0){ vec3 dirSpec = E-vec3(gl_LightSource[i].position.xyz); vec2 dirSpec2D = vec2(dot(dirSpec,right),dot(dirSpec,up)); vec2 nearestSpec2D = vec2(clamp( dirSpec2D.x,-width,width ),clamp( dirSpec2D.y,-height,height)); float specFactor = 1.0-clamp(length(nearestSpec2D-dirSpec2D)*shininess,0.0,1.0); specular += gl_LightSource[i].specular * attenuation * specFactor * specAngle; } diffuse += gl_LightSource[i].diffuse * attenuation * nDotL; } ambient += gl_LightSource[i].ambient * attenuation; }

Specular is correctly calculated as you can see, along with diffuse and ambient.

I see lots of potential uses for this in any graphics application, for example:

-fluorescent bulbs (spot, omni or directional can´t even approximate this)

-windows

-glowing panels

-lava pits

...

You can even fake GI (fake because you are emitting light, not reflecting it) using some well-positioned area lights: in a room that has bright green floor, placing a greenish area light pointing upwards there can give quite a boost to the scene at a negligible cost.

[Edited by - ArKano22 on November 6, 2009 6:23:14 PM]