2
Copyright 2009-2010 Michalis Kamburelis.
4
This file is part of "Castle Game Engine".
6
"Castle Game Engine" is free software; see the file COPYING.txt,
7
included in this distribution, for details about the copyright.
9
"Castle Game Engine" is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
----------------------------------------------------------------------------
16
/* Needed for % operator */
17
#extension GL_EXT_gpu_shader4 : enable
19
/* Fragment shader doing dynamic_ambient_occlusion.
20
See README for links and description what it does. */
22
uniform sampler2D tex_elements_position_area;
23
uniform sampler2D tex_elements_normal;
26
uniform sampler2D tex_elements_intensity;
30
/* Fglrx is dumb and fails when elements_count is a constant...
31
For other GPUs, elements_count as a constant is a good idea. */
32
uniform int tex_elements_size;
33
uniform int elements_count;
35
const int tex_elements_size = $tex_elements_size;
36
const int elements_count = $elements_count;
39
uniform float area_scale;
40
uniform vec3 position_scale;
41
uniform vec3 position_shift;
43
uniform float shadow_scale;
45
/* ATI (Radeon) on Linux (fglrx) doesn't tolerate const floats in code. */
47
/* uniform float pi; <- not used now */
51
/* calculate current element properties.
52
We know which element is "current" from gl_FragCoord. */
53
vec2 current_st = gl_FragCoord.xy;
54
int current_index = int(current_st.x) + int(current_st.y) * tex_elements_size;
56
if (current_index < elements_count)
58
current_st /= float(tex_elements_size); /* make ST coords of the texture in 0..1 */
59
vec4 current_pos_area = texture2D(tex_elements_position_area, current_st);
60
vec3 current_pos = (current_pos_area.xyz + position_shift) * position_scale;
62
vec3 current_normal = texture2D(tex_elements_normal, current_st).xyz;
63
current_normal = (current_normal - zero_5) * 2.0;
65
/* Another happy ATI (Radeon) on Linux (fglrx) bug:
66
When for testing I did "color = 0.0"
67
initialization, it... never executed "current_index < elements_count"
68
branch. Yes, I'm sure --- changing color initializer changes it's
69
idea of "current_index < elements_count". FUBAR optimizer.
71
So beware if experimenting with this.
75
for (int i = 0; i < elements_count; i++)
77
if (i != current_index)
79
vec2 element_st = vec2(
80
float(i % tex_elements_size),
81
float(i / tex_elements_size));
82
element_st /= float(tex_elements_size); /* make ST coords of the texture in 0..1 */
84
vec4 element_pos_area = texture2D(tex_elements_position_area, element_st);
85
vec3 element_pos = (element_pos_area.xyz + position_shift) * position_scale;
86
float element_area = element_pos_area.w * area_scale;
88
vec3 element_normal = texture2D(tex_elements_normal, element_st).xyz;
89
element_normal = (element_normal - zero_5) * 2.0;
91
vec3 direction_from_current = element_pos - current_pos;
92
float sqr_distance = dot(direction_from_current, direction_from_current);
94
/* normalize direction_from_current for following cos() calculations */
95
direction_from_current = normalize(direction_from_current);
96
float cos_emitter_angle = dot(direction_from_current, element_normal);
97
float cos_current_angle = dot(direction_from_current, current_normal);
99
/* We gather the light only from the dir of our normal,
100
so only when cos_current_angle >= 0.
101
This also means that we normalize by 2*pi (not 4*pi),
102
as we have effectively already cut off to hemisphere.
103
(Actually, this normalization is now in Pascal code, see ShadowScale).
105
Also, we are shadowed only by items that gather light
106
(that is, only if they are lighted then they also block the light).
108
That's the reasoning behind these checks. */
109
if (cos_emitter_angle >= 0.0 &&
110
cos_current_angle >= 0.0)
112
color -= (element_area * cos_emitter_angle * cos_current_angle *
113
shadow_scale / sqr_distance)
115
/* Multiply by intensity of this element from 1st pass.
116
If element is in shadow, then this is 0, and then we will
117
not take it's contribution --- as this means that something else
118
shadows it, so it will also shadow us. */
119
* texture2D(tex_elements_intensity, element_st).x
127
/* At the end of 2nd pass, result is the average of 1st and 2nd pass
129
color = (color + texture2D(tex_elements_intensity, current_st).x) / 2.0;
132
/* Return color only in the red component. Note that using "color"
133
for all RGB components (like
134
gl_FragColor = vec4(color, color, color, 1.0);
135
) causes wrong behavior if we catch the resulting fragments
136
to GL_LUMINANCE texture. It looks like the resulting luminance
137
is the sum of (red + green + blue), and so it's
138
far larger than expected. OpenGL spec says that luminance comes
139
from only red, so possibly this is a bug of fglrx (Linux ATI
140
drivers, ATI Mobility Radeon X1600, Mac Book Pro, chantal). */
142
gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
146
/* Only for testing, to mark colors not corresponding to any element. */
147
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);