Welcome to mirror list, hosted at ThFree Co, Russian Federation.

volumetric_lib.glsl « shaders « eevee « engines « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9b852a57ec4b0a1488c75da25fde2005c96131a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

#pragma BLENDER_REQUIRE(lights_lib.glsl)
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(irradiance_lib.glsl)

/* Based on Frosbite Unified Volumetric.
 * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */

/* Volume slice to view space depth. */
float volume_z_to_view_z(float z)
{
  if (ProjectionMatrix[3][3] == 0.0) {
    /* Exponential distribution */
    return (exp2(z / volDepthParameters.z) - volDepthParameters.x) / volDepthParameters.y;
  }
  else {
    /* Linear distribution */
    return mix(volDepthParameters.x, volDepthParameters.y, z);
  }
}

float view_z_to_volume_z(float depth)
{
  if (ProjectionMatrix[3][3] == 0.0) {
    /* Exponential distribution */
    return volDepthParameters.z * log2(depth * volDepthParameters.y + volDepthParameters.x);
  }
  else {
    /* Linear distribution */
    return (depth - volDepthParameters.x) * volDepthParameters.z;
  }
}

/* Volume texture normalized coordinates to NDC (special range [0, 1]). */
vec3 volume_to_ndc(vec3 cos)
{
  cos.z = volume_z_to_view_z(cos.z);
  cos.z = get_depth_from_view_z(cos.z);
  cos.xy /= volCoordScale.xy;
  return cos;
}

vec3 ndc_to_volume(vec3 cos)
{
  cos.z = get_view_z_from_depth(cos.z);
  cos.z = view_z_to_volume_z(cos.z);
  cos.xy *= volCoordScale.xy;
  return cos;
}

float phase_function_isotropic()
{
  return 1.0 / (4.0 * M_PI);
}

float phase_function(vec3 v, vec3 l, float g)
{
  /* Henyey-Greenstein */
  float cos_theta = dot(v, l);
  g = clamp(g, -1.0 + 1e-3, 1.0 - 1e-3);
  float sqr_g = g * g;
  return (1 - sqr_g) / max(1e-8, 4.0 * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0 / 2.0));
}

vec3 light_volume(LightData ld, vec4 l_vector)
{
  float power;
  /* TODO : Area lighting ? */
  /* XXX : Removing Area Power. */
  /* TODO : put this out of the shader. */
  /* See eevee_light_setup(). */
  if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) {
    power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
    if (ld.l_type == AREA_ELLIPSE) {
      power *= M_PI * 0.25;
    }
    power *= 20.0 *
             max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
  }
  else if (ld.l_type == SUN) {
    power = ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
    power /= 1.0f + (ld.l_radius * ld.l_radius * 0.5f);
    power *= M_PI * 0.5; /* Matching cycles. */
  }
  else {
    power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
    power *= M_2PI; /* Matching cycles with point light. */
  }

  power /= (l_vector.w * l_vector.w);

  /* OPTI: find a better way than calculating this on the fly */
  float lum = dot(ld.l_color, vec3(0.3, 0.6, 0.1));       /* luminance approx. */
  vec3 tint = (lum > 0.0) ? ld.l_color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */

  lum = min(lum * power, volLightClamp);

  return tint * lum;
}

#define VOLUMETRIC_SHADOW_MAX_STEP 32.0

vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction)
{
  /* Waiting for proper volume shadowmaps and out of frustum shadow map. */
  vec3 ndc = project_point(ViewProjectionMatrix, wpos);
  vec3 volume_co = ndc_to_volume(ndc * 0.5 + 0.5);

  /* Let the texture be clamped to edge. This reduce visual glitches. */
  return texture(volume_extinction, volume_co).rgb;
}

vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D volume_extinction)
{
#if defined(VOLUME_SHADOW)
  /* Heterogeneous volume shadows */
  float dd = l_vector.w / volShadowSteps;
  vec3 L = l_vector.xyz * l_vector.w;
  vec3 shadow = vec3(1.0);
  for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) {
    vec3 pos = ray_wpos + L * (s / volShadowSteps);
    vec3 s_extinction = participating_media_extinction(pos, volume_extinction);
    shadow *= exp(-s_extinction * dd);
  }
  return shadow;
#else
  return vec3(1.0);
#endif /* VOLUME_SHADOW */
}

vec3 irradiance_volumetric(vec3 wpos)
{
#ifdef IRRADIANCE_HL2
  IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0));
  vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
  ir_data = load_irradiance_cell(0, vec3(-1.0));
  irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
  irradiance *= 0.16666666; /* 1/6 */
  return irradiance;
#else
  return vec3(0.0);
#endif
}

uniform sampler3D inScattering;
uniform sampler3D inTransmittance;

void volumetric_resolve(vec2 frag_uvs,
                        float frag_depth,
                        out vec3 transmittance,
                        out vec3 scattering)
{
  vec3 volume_cos = ndc_to_volume(vec3(frag_uvs, frag_depth));

  scattering = texture(inScattering, volume_cos).rgb;
  transmittance = texture(inTransmittance, volume_cos).rgb;
}