This is the first step of moving the create infos back inside shader sources. All info files are now treated as source files. However, they are not considered in the include tree yet. This will come in another following PR. Each shader source file now generate a `.info` file containing only the create info declarations. This renames all info files so that they do not conflict with their previous versions that were copied (non-generated). Pull Request: https://projects.blender.org/blender/blender/pulls/146676
205 lines
7.4 KiB
GLSL
205 lines
7.4 KiB
GLSL
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include "infos/eevee_common_infos.hh"
|
|
|
|
SHADER_LIBRARY_CREATE_INFO(eevee_global_ubo)
|
|
|
|
#include "draw_view_lib.glsl"
|
|
#include "eevee_sampling_lib.glsl"
|
|
#include "eevee_spherical_harmonics_lib.glsl"
|
|
#include "gpu_shader_math_matrix_transform_lib.glsl"
|
|
|
|
/* Based on Frosbite Unified Volumetric.
|
|
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
|
|
|
|
/* Per froxel jitter to break slices and flickering.
|
|
* Wrapped so that changing it is easier. */
|
|
float volume_froxel_jitter(int2 froxel, float offset)
|
|
{
|
|
return interleaved_gradient_noise(float2(froxel), 0.0f, offset);
|
|
}
|
|
|
|
/* Volume froxel texture normalized linear Z to view space Z.
|
|
* Not dependent on projection matrix (as long as drw_view_is_perspective is consistent). */
|
|
float volume_z_to_view_z(float z)
|
|
{
|
|
float near = uniform_buf.volumes.depth_near;
|
|
float far = uniform_buf.volumes.depth_far;
|
|
float distribution = uniform_buf.volumes.depth_distribution;
|
|
if (drw_view_is_perspective()) {
|
|
/* Exponential distribution. */
|
|
return (exp2(z / distribution) - near) / far;
|
|
}
|
|
else {
|
|
/* Linear distribution. */
|
|
return near + (far - near) * z;
|
|
}
|
|
}
|
|
|
|
/* View space Z to volume froxel texture normalized linear Z.
|
|
* Not dependent on projection matrix (as long as drw_view_is_perspective is consistent). */
|
|
float view_z_to_volume_z(float depth, float near, float far, float distribution)
|
|
{
|
|
if (drw_view_is_perspective()) {
|
|
/* Exponential distribution. */
|
|
return distribution * log2(depth * far + near);
|
|
}
|
|
else {
|
|
/* Linear distribution. */
|
|
return (depth - near) / (far - near);
|
|
}
|
|
}
|
|
float view_z_to_volume_z(float depth)
|
|
{
|
|
return view_z_to_volume_z(depth,
|
|
uniform_buf.volumes.depth_near,
|
|
uniform_buf.volumes.depth_far,
|
|
uniform_buf.volumes.depth_distribution);
|
|
}
|
|
|
|
/* Jittered volume texture normalized coordinates to view space position. */
|
|
float3 volume_jitter_to_view(float3 coord)
|
|
{
|
|
/* Since we use an infinite projection matrix for rendering inside the jittered volumes,
|
|
* we need to use a different matrix to reconstruct positions as the infinite matrix is not
|
|
* always invertible. */
|
|
float4x4 winmat = uniform_buf.volumes.winmat_finite;
|
|
float4x4 wininv = uniform_buf.volumes.wininv_finite;
|
|
/* Input coordinates are in jittered volume texture space. */
|
|
float view_z = volume_z_to_view_z(coord.z);
|
|
/* We need to recover the NDC position for correct perspective divide. */
|
|
float ndc_z = drw_perspective_divide(winmat * float4(0.0f, 0.0f, view_z, 1.0f)).z;
|
|
float2 ndc_xy = drw_screen_to_ndc(coord.xy);
|
|
/* NDC to view. */
|
|
return drw_perspective_divide(wininv * float4(ndc_xy, ndc_z, 1.0f)).xyz;
|
|
}
|
|
|
|
/* View space position to jittered volume texture normalized coordinates. */
|
|
float3 volume_view_to_jitter(float3 vP)
|
|
{
|
|
/* Since we use an infinite projection matrix for rendering inside the jittered volumes,
|
|
* we need to use a different matrix to reconstruct positions as the infinite matrix is not
|
|
* always invertible. */
|
|
float4x4 winmat = uniform_buf.volumes.winmat_finite;
|
|
/* View to ndc. */
|
|
float3 ndc_P = drw_perspective_divide(winmat * float4(vP, 1.0f));
|
|
/* Here, screen is the same as volume texture UVW space. */
|
|
return float3(drw_ndc_to_screen(ndc_P.xy), view_z_to_volume_z(vP.z));
|
|
}
|
|
|
|
/* Volume texture normalized coordinates (UVW) to render screen (UV).
|
|
* Expect active view to be the main view. */
|
|
float3 volume_resolve_to_screen(float3 coord)
|
|
{
|
|
coord.z = volume_z_to_view_z(coord.z);
|
|
coord.z = drw_depth_view_to_screen(coord.z);
|
|
coord.xy /= uniform_buf.volumes.coord_scale;
|
|
return coord;
|
|
}
|
|
/* Render screen (UV) to volume texture normalized coordinates (UVW).
|
|
* Expect active view to be the main view. */
|
|
float3 volume_screen_to_resolve(float3 coord)
|
|
{
|
|
coord.xy *= uniform_buf.volumes.coord_scale;
|
|
coord.z = drw_depth_screen_to_view(coord.z);
|
|
coord.z = view_z_to_volume_z(coord.z);
|
|
return coord;
|
|
}
|
|
|
|
/* Returns the uvw (normalized coordinate) of a froxel in the previous frame.
|
|
* Returns float3(-1) if history is unavailable. */
|
|
float3 volume_history_uvw_get(int3 froxel)
|
|
{
|
|
float4x4 wininv = uniform_buf.volumes.wininv_stable;
|
|
float4x4 winmat = uniform_buf.volumes.winmat_stable;
|
|
/* We can't reproject by a simple matrix multiplication. We first need to remap to the view Z,
|
|
* then transform, then remap back to Volume range. */
|
|
float3 uvw = (float3(froxel) + 0.5f) * uniform_buf.volumes.inv_tex_size;
|
|
float3 ndc_P = drw_screen_to_ndc(uvw);
|
|
/* We need to recover the NDC position for correct perspective divide. */
|
|
float view_z = volume_z_to_view_z(uvw.z);
|
|
ndc_P.z = drw_perspective_divide(winmat * float4(0.0f, 0.0f, view_z, 1.0f)).z;
|
|
/* NDC to view. */
|
|
float3 vs_P = project_point(wininv, ndc_P);
|
|
|
|
/* Transform to previous camera view space. */
|
|
float3 vs_P_history = transform_point(uniform_buf.volumes.curr_view_to_past_view, vs_P);
|
|
|
|
/* View to NDC. */
|
|
float4 hs_P_history = uniform_buf.volumes.history_winmat_stable * float4(vs_P_history, 1.0f);
|
|
float3 ndc_P_history = drw_perspective_divide(hs_P_history);
|
|
|
|
if (hs_P_history.w < 0.0f || any(greaterThan(abs(ndc_P_history.xy), float2(1.0f)))) {
|
|
return float3(-1.0f);
|
|
}
|
|
|
|
float3 uvw_history;
|
|
uvw_history.xy = drw_ndc_to_screen(ndc_P_history.xy);
|
|
uvw_history.z = view_z_to_volume_z(vs_P_history.z,
|
|
uniform_buf.volumes.history_depth_near,
|
|
uniform_buf.volumes.history_depth_far,
|
|
uniform_buf.volumes.history_depth_distribution);
|
|
|
|
if (uvw_history.z < 0.0f || uvw_history.z > 1.0f) {
|
|
return float3(-1.0f);
|
|
}
|
|
return uvw_history;
|
|
}
|
|
|
|
float volume_phase_function_isotropic()
|
|
{
|
|
return 1.0f / (4.0f * M_PI);
|
|
}
|
|
|
|
float volume_phase_function(float3 V, float3 L, float g)
|
|
{
|
|
/* Henyey-Greenstein. */
|
|
float cos_theta = dot(V, L);
|
|
g = clamp(g, -1.0f + 1e-3f, 1.0f - 1e-3f);
|
|
float sqr_g = g * g;
|
|
return (1 - sqr_g) / max(1e-8f, 4.0f * M_PI * pow(1 + sqr_g - 2 * g * cos_theta, 3.0f / 2.0f));
|
|
}
|
|
|
|
SphericalHarmonicL1 volume_phase_function_as_sh_L1(float3 V, float g)
|
|
{
|
|
/* Compute rotated zonal harmonic.
|
|
* From Bartlomiej Wronsky
|
|
* "Volumetric Fog: Unified compute shader based solution to atmospheric scattering" page 55
|
|
* SIGGRAPH 2014
|
|
* https://bartwronski.files.wordpress.com/2014/08/bwronski_volumetric_fog_siggraph2014.pdf
|
|
*/
|
|
SphericalHarmonicL1 sh;
|
|
sh.L0.M0 = spherical_harmonics_L0_M0(V) * float4(1.0f);
|
|
sh.L1.Mn1 = spherical_harmonics_L1_Mn1(V) * float4(g);
|
|
sh.L1.M0 = spherical_harmonics_L1_M0(V) * float4(g);
|
|
sh.L1.Mp1 = spherical_harmonics_L1_Mp1(V) * float4(g);
|
|
return sh;
|
|
}
|
|
|
|
struct VolumeResolveSample {
|
|
float3 transmittance;
|
|
float3 scattering;
|
|
};
|
|
|
|
VolumeResolveSample volume_resolve(float3 ndc_P,
|
|
sampler3D transmittance_tx,
|
|
sampler3D scattering_tx)
|
|
{
|
|
float3 coord = volume_screen_to_resolve(ndc_P);
|
|
|
|
/* Volumes objects have the same aliasing problems has shadow maps.
|
|
* To fix this we need a quantization bias (the size of a step in Z) and a slope bias
|
|
* (multiplied by the size of a froxel in 2D). */
|
|
coord.z -= uniform_buf.volumes.inv_tex_size.z;
|
|
/* TODO(fclem): Slope bias. */
|
|
|
|
VolumeResolveSample volume;
|
|
volume.scattering = texture(scattering_tx, coord).rgb;
|
|
volume.transmittance = texture(transmittance_tx, coord).rgb;
|
|
return volume;
|
|
}
|