~ubuntu-branches/ubuntu/utopic/castle-game-engine/utopic

« back to all changes in this revision

Viewing changes to examples/dynamic_ambient_occlusion/dynamic_ambient_occlusion.fs

  • Committer: Package Import Robot
  • Author(s): Abou Al Montacir
  • Date: 2013-04-27 18:06:40 UTC
  • Revision ID: package-import@ubuntu.com-20130427180640-eink4nmwzuivez1c
Tags: upstream-4.0.1
ImportĀ upstreamĀ versionĀ 4.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright 2009-2010 Michalis Kamburelis.
 
3
 
 
4
  This file is part of "Castle Game Engine".
 
5
 
 
6
  "Castle Game Engine" is free software; see the file COPYING.txt,
 
7
  included in this distribution, for details about the copyright.
 
8
 
 
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.
 
12
 
 
13
  ----------------------------------------------------------------------------
 
14
*/
 
15
 
 
16
/* Needed for % operator */
 
17
#extension GL_EXT_gpu_shader4 : enable
 
18
 
 
19
/* Fragment shader doing dynamic_ambient_occlusion.
 
20
   See README for links and description what it does. */
 
21
 
 
22
uniform sampler2D tex_elements_position_area;
 
23
uniform sampler2D tex_elements_normal;
 
24
 
 
25
#ifdef PASS_2
 
26
uniform sampler2D tex_elements_intensity;
 
27
#endif
 
28
 
 
29
#ifdef FGLRX
 
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;
 
34
#else
 
35
const int tex_elements_size = $tex_elements_size;
 
36
const int elements_count = $elements_count;
 
37
#endif
 
38
 
 
39
uniform float area_scale;
 
40
uniform vec3 position_scale;
 
41
uniform vec3 position_shift;
 
42
 
 
43
uniform float shadow_scale;
 
44
 
 
45
/* ATI (Radeon) on Linux (fglrx) doesn't tolerate const floats in code. */
 
46
uniform float zero_5;
 
47
/* uniform float pi; <- not used now */
 
48
 
 
49
void main(void)
 
50
{
 
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;
 
55
 
 
56
  if (current_index < elements_count)
 
57
  {
 
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;
 
61
 
 
62
    vec3 current_normal = texture2D(tex_elements_normal, current_st).xyz;
 
63
    current_normal = (current_normal - zero_5) * 2.0;
 
64
 
 
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.
 
70
 
 
71
       So beware if experimenting with this.
 
72
    */
 
73
    float color = 1.0;
 
74
 
 
75
    for (int i = 0; i < elements_count; i++)
 
76
    {
 
77
      if (i != current_index)
 
78
      {
 
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 */
 
83
 
 
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;
 
87
 
 
88
        vec3 element_normal = texture2D(tex_elements_normal, element_st).xyz;
 
89
        element_normal = (element_normal - zero_5) * 2.0;
 
90
 
 
91
        vec3 direction_from_current = element_pos - current_pos;
 
92
        float sqr_distance = dot(direction_from_current, direction_from_current);
 
93
 
 
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);
 
98
 
 
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).
 
104
 
 
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).
 
107
 
 
108
           That's the reasoning behind these checks. */
 
109
        if (cos_emitter_angle >= 0.0 &&
 
110
            cos_current_angle >= 0.0)
 
111
        {
 
112
          color -= (element_area * cos_emitter_angle * cos_current_angle *
 
113
            shadow_scale / sqr_distance)
 
114
            #ifdef PASS_2
 
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
 
120
            #endif
 
121
            ;
 
122
        }
 
123
      }
 
124
    }
 
125
 
 
126
    #ifdef PASS_2
 
127
    /* At the end of 2nd pass, result is the average of 1st and 2nd pass
 
128
       results. */
 
129
    color = (color + texture2D(tex_elements_intensity, current_st).x) / 2.0;
 
130
    #endif
 
131
 
 
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). */
 
141
 
 
142
    gl_FragColor = vec4(color, 0.0, 0.0, 1.0);
 
143
  }
 
144
  else
 
145
  {
 
146
    /* Only for testing, to mark colors not corresponding to any element. */
 
147
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
 
148
  }
 
149
}