2023-08-24 10:54:59 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2023-06-23 08:39:46 +02:00
|
|
|
|
2024-10-04 15:48:22 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2025-09-25 10:57:02 +02:00
|
|
|
#include "infos/eevee_lightprobe_sphere_infos.hh"
|
2024-12-02 21:26:15 +01:00
|
|
|
|
|
|
|
|
/* TODO(fclem): Pass the lightprobe_sphere_buf around and avoid relying on interface.
|
|
|
|
|
* Currently in conflict with eevee_lightprobe_volume_load. */
|
|
|
|
|
#ifndef SPHERE_PROBE_SELECT
|
|
|
|
|
SHADER_LIBRARY_CREATE_INFO(eevee_lightprobe_sphere_data)
|
|
|
|
|
#endif
|
|
|
|
|
SHADER_LIBRARY_CREATE_INFO(eevee_lightprobe_planar_data)
|
|
|
|
|
/* TODO(fclem): Pass the atlas texture around and avoid relying on interface.
|
|
|
|
|
* Currently in conflict with eevee_lightprobe_volume_load. */
|
|
|
|
|
#ifndef IRRADIANCE_GRID_UPLOAD
|
|
|
|
|
SHADER_LIBRARY_CREATE_INFO(eevee_volume_probe_data)
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-10-04 15:48:22 +02:00
|
|
|
#include "gpu_shader_math_vector_lib.glsl"
|
|
|
|
|
#include "gpu_shader_utildefines_lib.glsl"
|
2023-06-23 08:39:46 +02:00
|
|
|
|
2024-04-15 21:57:31 +02:00
|
|
|
/**
|
|
|
|
|
* Returns world position of a volume lightprobe sample (center of cell).
|
|
|
|
|
* Returned position take into account the half voxel padding on each sides.
|
|
|
|
|
* `grid_local_to_world_mat` is the unmodified object matrix.
|
|
|
|
|
* `grid_res` is the un-padded grid resolution.
|
|
|
|
|
* `cell_coord` is the coordinate of the sample in [0..grid_res) range.
|
|
|
|
|
*/
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 lightprobe_volume_grid_sample_position(float4x4 grid_local_to_world_mat,
|
|
|
|
|
int3 grid_res,
|
|
|
|
|
int3 cell_coord)
|
2023-06-23 08:39:46 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 ls_cell_pos = (float3(cell_coord + 1)) / float3(grid_res + 1);
|
2025-04-11 18:28:45 +02:00
|
|
|
ls_cell_pos = ls_cell_pos * 2.0f - 1.0f;
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 ws_cell_pos = (grid_local_to_world_mat * float4(ls_cell_pos, 1.0f)).xyz;
|
2023-06-23 08:39:46 +02:00
|
|
|
return ws_cell_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return true if sample position is valid.
|
|
|
|
|
* \a r_lP is the local position in grid units [0..grid_size).
|
|
|
|
|
*/
|
2025-04-14 13:46:41 +02:00
|
|
|
bool lightprobe_volume_grid_local_coord(VolumeProbeData grid_data, float3 P, out float3 r_lP)
|
2023-06-23 08:39:46 +02:00
|
|
|
{
|
|
|
|
|
/* Position in cell units. */
|
|
|
|
|
/* NOTE: The vector-matrix multiplication swapped on purpose to cancel the matrix transpose. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 lP = (float4(P, 1.0f) * grid_data.world_to_grid_transposed).xyz;
|
|
|
|
|
r_lP = clamp(lP, float3(0.5f), float3(grid_data.grid_size_padded) - 0.5f);
|
2023-06-23 08:39:46 +02:00
|
|
|
/* Sample is valid if position wasn't clamped. */
|
|
|
|
|
return all(equal(lP, r_lP));
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
int lightprobe_volume_grid_brick_index_get(VolumeProbeData grid_data, int3 brick_coord)
|
2023-06-23 08:39:46 +02:00
|
|
|
{
|
2024-04-15 21:57:31 +02:00
|
|
|
int3 grid_size_in_bricks = divide_ceil(grid_data.grid_size_padded,
|
2023-06-23 08:39:46 +02:00
|
|
|
int3(IRRADIANCE_GRID_BRICK_SIZE - 1));
|
|
|
|
|
int brick_index = grid_data.brick_offset;
|
|
|
|
|
brick_index += brick_coord.x;
|
|
|
|
|
brick_index += brick_coord.y * grid_size_in_bricks.x;
|
|
|
|
|
brick_index += brick_coord.z * grid_size_in_bricks.x * grid_size_in_bricks.y;
|
|
|
|
|
return brick_index;
|
|
|
|
|
}
|
2023-08-06 13:43:17 +02:00
|
|
|
|
|
|
|
|
/* Return cell corner from a corner ID [0..7]. */
|
2025-04-14 13:46:41 +02:00
|
|
|
int3 lightprobe_volume_grid_cell_corner(int cell_corner_id)
|
2023-08-06 13:43:17 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
return (int3(cell_corner_id) >> int3(0, 1, 2)) & 1;
|
2023-08-06 13:43:17 +02:00
|
|
|
}
|
2023-10-10 12:55:18 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float lightprobe_planar_score(PlanarProbeData planar, float3 P, float3 V, float3 L)
|
2023-10-10 12:55:18 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 lP = float4(P, 1.0f) * planar.world_to_object_transposed;
|
|
|
|
|
if (any(greaterThan(abs(lP), float3(1.0f)))) {
|
2023-10-10 12:55:18 +02:00
|
|
|
/* TODO: Transition in Z. Dither? */
|
2025-04-11 18:28:45 +02:00
|
|
|
return 0.0f;
|
2023-10-10 12:55:18 +02:00
|
|
|
}
|
|
|
|
|
/* Return how much the ray is lined up with the captured ray. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 R = -reflect(V, planar.normal);
|
2023-10-13 18:33:08 +02:00
|
|
|
return saturate(dot(L, R));
|
2023-10-10 12:55:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef PLANAR_PROBES
|
|
|
|
|
/**
|
2023-10-12 16:03:18 +11:00
|
|
|
* Return the best planar probe index for a given light direction vector and position.
|
2023-10-10 12:55:18 +02:00
|
|
|
*/
|
2025-04-14 13:46:41 +02:00
|
|
|
int lightprobe_planar_select(float3 P, float3 V, float3 L)
|
2023-10-10 12:55:18 +02:00
|
|
|
{
|
|
|
|
|
/* Initialize to the score of a camera ray. */
|
2023-10-13 18:33:08 +02:00
|
|
|
float best_score = saturate(dot(L, -V));
|
2023-10-10 12:55:18 +02:00
|
|
|
int best_index = -1;
|
|
|
|
|
|
2024-02-08 19:48:28 +01:00
|
|
|
for (int index = 0; index < PLANAR_PROBE_MAX; index++) {
|
2023-10-10 12:55:18 +02:00
|
|
|
if (probe_planar_buf[index].layer_id == -1) {
|
2024-02-08 19:48:28 +01:00
|
|
|
/* PlanarProbeData doesn't contain any gap, exit at first item that is invalid. */
|
2023-10-10 12:55:18 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
float score = lightprobe_planar_score(probe_planar_buf[index], P, V, L);
|
|
|
|
|
if (score > best_score) {
|
|
|
|
|
best_score = score;
|
|
|
|
|
best_index = index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return best_index;
|
|
|
|
|
}
|
|
|
|
|
#endif
|