(revisited)
DevTricks
Tyler Howard
Forward:
Each light is applied directly to each objects' first and only render to screen
Cost is roughly m x n lighting calculations
m objects
n lights
Deferred:
m objects
n lights
Composite step
(merge objects into single object, kinda)
Cost is roughly m + n lighting calculations
Deferred rendering scales much better as you add more objects or lights, by orders of magnitude.
It's possible to have many more objects and lights in a scene and still be able to meet target framerates between 24-60 fps.
Final render of scene:
Working backwards:
Depth
Working backwards:
Normal
Working backwards:
Color
<script id="pass_fs" type="x-shader/x-fragment">
#extension GL_EXT_draw_buffers : require
precision highp float;
uniform vec3 u_Color;
//in
varying vec3 fs_Normal;
varying vec4 fs_Position;
varying vec2 fs_Texcoord;
varying float fs_Depth;
uniform sampler2D u_Texture;
void main(void)
{
//normal, position, depth, color
gl_FragData[0] = vec4(vec3(fs_Depth), 1.0);
gl_FragData[1] = vec4(normalize(fs_Normal.xyz), 1.0);
gl_FragData[2] = fs_Position;
gl_FragData[3] = vec4(texture2D(u_Texture, fs_Texcoord).xyz, 1.0);
}
</script>Making the composite -- rendering to multiple 2D textures at once
240 lights applied to composite image/geometry buffer
~58 fps
Applying lights to scene -- for each light
uniform sampler2D u_Depthtex;
uniform sampler2D u_Normaltex;
uniform sampler2D u_Positiontex;
uniform sampler2D u_Colortex;
uniform vec4 u_Light;
uniform vec3 u_LightColor;
in vec2 fs_Texcoord;
out vec4 fragmentColor;
void main()
{
vec3 normal = texture(u_Normaltex, fs_Texcoord).xyz;
vec3 position = texture(u_Positiontex, fs_Texcoord).xyz;
vec3 color = texture(u_Colortex, fs_Texcoord).xyz;
vec3 light = u_Light.xyz;
float lightRadius = u_Light.w;
if(distance(light, position) < lightRadius)
{
float dist = distance(light, position);
float lightR = lightRadius;
float attenuation = dist/(1.0 - (dist/lightR) * (dist/lightR));
attenuation = attenuation / lightR + 1.0;
attenuation = 1.0 / (attenuation * attenuation);
float diffuse = abs(dot(normal, normalize(light - position)));
fragmentColor = vec4(diffuse * u_LightColor * color * attenuation, 1.0);
}
else
fragmentColor = vec4(0.0,0.0,0.0,1.0);
}Live Demo & Code
(someone else's implementation, so we're clear)
http://tiansijie.github.io/Tile_Based_WebGL_DeferredShader/
https://github.com/tiansijie/Tile_Based_WebGL_DeferredShader
(pertinent shader code lives in index.html <script type="x-shader/(x-fragment or x-vertex)"> tags)