forked from blender/blender
main sync #3
@ -722,7 +722,7 @@ void ShadowModule::begin_sync()
|
|||||||
PassMain::Sub &sub = pass.sub("Transparent");
|
PassMain::Sub &sub = pass.sub("Transparent");
|
||||||
/* WORKAROUND: The DRW_STATE_WRITE_STENCIL is here only to avoid enabling the rasterizer
|
/* WORKAROUND: The DRW_STATE_WRITE_STENCIL is here only to avoid enabling the rasterizer
|
||||||
* discard inside draw manager. */
|
* discard inside draw manager. */
|
||||||
sub.state_set(DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_STENCIL);
|
sub.state_set(DRW_STATE_CULL_FRONT | DRW_STATE_WRITE_STENCIL);
|
||||||
sub.state_stencil(0, 0, 0);
|
sub.state_stencil(0, 0, 0);
|
||||||
sub.framebuffer_set(&usage_tag_fb);
|
sub.framebuffer_set(&usage_tag_fb);
|
||||||
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT));
|
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT));
|
||||||
@ -730,6 +730,10 @@ void ShadowModule::begin_sync()
|
|||||||
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
|
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
|
||||||
sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
|
sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
|
||||||
sub.push_constant("tilemap_projection_ratio", &tilemap_projection_ratio_);
|
sub.push_constant("tilemap_projection_ratio", &tilemap_projection_ratio_);
|
||||||
|
sub.push_constant("pixel_world_radius", &pixel_world_radius_);
|
||||||
|
sub.push_constant("fb_resolution", &usage_tag_fb_resolution_);
|
||||||
|
sub.push_constant("fb_lod", &usage_tag_fb_lod_);
|
||||||
|
inst_.hiz_buffer.bind_resources(&sub);
|
||||||
inst_.lights.bind_resources(&sub);
|
inst_.lights.bind_resources(&sub);
|
||||||
|
|
||||||
box_batch_ = DRW_cache_cube_get();
|
box_batch_ = DRW_cache_cube_get();
|
||||||
@ -1092,12 +1096,17 @@ void ShadowModule::set_view(View &view)
|
|||||||
int3 target_size = inst_.render_buffers.depth_tx.size();
|
int3 target_size = inst_.render_buffers.depth_tx.size();
|
||||||
dispatch_depth_scan_size_ = math::divide_ceil(target_size, int3(SHADOW_DEPTH_SCAN_GROUP_SIZE));
|
dispatch_depth_scan_size_ = math::divide_ceil(target_size, int3(SHADOW_DEPTH_SCAN_GROUP_SIZE));
|
||||||
|
|
||||||
tilemap_projection_ratio_ = tilemap_pixel_radius() /
|
pixel_world_radius_ = screen_pixel_radius(view, int2(target_size));
|
||||||
screen_pixel_radius(view, int2(target_size));
|
tilemap_projection_ratio_ = tilemap_pixel_radius() / pixel_world_radius_;
|
||||||
|
|
||||||
|
usage_tag_fb_resolution_ = math::divide_ceil(int2(target_size),
|
||||||
|
int2(std::exp2(usage_tag_fb_lod_)));
|
||||||
|
usage_tag_fb.ensure(usage_tag_fb_resolution_);
|
||||||
|
|
||||||
usage_tag_fb.ensure(int2(target_size));
|
|
||||||
render_fb_.ensure(int2(SHADOW_TILEMAP_RES * shadow_page_size_));
|
render_fb_.ensure(int2(SHADOW_TILEMAP_RES * shadow_page_size_));
|
||||||
|
|
||||||
|
inst_.hiz_buffer.update();
|
||||||
|
|
||||||
bool tile_update_remains = true;
|
bool tile_update_remains = true;
|
||||||
while (tile_update_remains) {
|
while (tile_update_remains) {
|
||||||
DRW_stats_group_start("Shadow");
|
DRW_stats_group_start("Shadow");
|
||||||
|
@ -216,6 +216,9 @@ class ShadowModule {
|
|||||||
int3 dispatch_depth_scan_size_;
|
int3 dispatch_depth_scan_size_;
|
||||||
/* Ratio between tile-map pixel world "radius" and film pixel world "radius". */
|
/* Ratio between tile-map pixel world "radius" and film pixel world "radius". */
|
||||||
float tilemap_projection_ratio_;
|
float tilemap_projection_ratio_;
|
||||||
|
float pixel_world_radius_;
|
||||||
|
int2 usage_tag_fb_resolution_;
|
||||||
|
int usage_tag_fb_lod_ = 5;
|
||||||
|
|
||||||
/* Statistics that are read back to CPU after a few frame (to avoid stall). */
|
/* Statistics that are read back to CPU after a few frame (to avoid stall). */
|
||||||
SwapChain<ShadowStatisticsBuf, 5> statistics_buf_;
|
SwapChain<ShadowStatisticsBuf, 5> statistics_buf_;
|
||||||
|
@ -3,13 +3,120 @@
|
|||||||
* Virtual shadowmapping: Usage tagging
|
* Virtual shadowmapping: Usage tagging
|
||||||
*
|
*
|
||||||
* Shadow pages are only allocated if they are visible.
|
* Shadow pages are only allocated if they are visible.
|
||||||
* This pass scan the depth buffer and tag all tiles that are needed for light shadowing as
|
* This ray-marches the current fragment along the bounds depth and tags all the intersected shadow
|
||||||
* needed.
|
* tiles.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma BLENDER_REQUIRE(eevee_shadow_tag_usage_lib.glsl)
|
#pragma BLENDER_REQUIRE(eevee_shadow_tag_usage_lib.glsl)
|
||||||
|
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||||
|
|
||||||
|
#pragma BLENDER_REQUIRE(common_debug_shape_lib.glsl)
|
||||||
|
|
||||||
|
float ray_aabb(vec3 ray_origin, vec3 ray_direction, vec3 aabb_min, vec3 aabb_max)
|
||||||
|
{
|
||||||
|
/* https://gdbooks.gitbooks.io/3dcollisions/content/Chapter3/raycast_aabb.html */
|
||||||
|
vec3 t_mins = (aabb_min - ray_origin) / ray_direction;
|
||||||
|
vec3 t_maxs = (aabb_max - ray_origin) / ray_direction;
|
||||||
|
|
||||||
|
float t_min = max_v3(min(t_mins, t_maxs));
|
||||||
|
float t_max = min_v3(max(t_mins, t_maxs));
|
||||||
|
|
||||||
|
/* AABB is in the opposite direction. */
|
||||||
|
if (t_max < 0.0) {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
/* No intersection. */
|
||||||
|
if (t_min > t_max) {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
/* The ray origin is inside the aabb. */
|
||||||
|
if (t_min < 0.0) {
|
||||||
|
/* For regular ray casting we would return t_max here,
|
||||||
|
* but we want to ray cast against the box volume, not just the surface. */
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return t_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pixel_size_at(float linear_depth)
|
||||||
|
{
|
||||||
|
float pixel_size = pixel_world_radius;
|
||||||
|
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||||
|
if (is_persp) {
|
||||||
|
pixel_size *= max(0.01, linear_depth);
|
||||||
|
}
|
||||||
|
return pixel_size * exp2(fb_lod);
|
||||||
|
}
|
||||||
|
|
||||||
|
void step_bounding_sphere(vec3 vs_near_plane,
|
||||||
|
vec3 vs_view_direction,
|
||||||
|
float near_t,
|
||||||
|
float far_t,
|
||||||
|
out vec3 sphere_center,
|
||||||
|
out float sphere_radius)
|
||||||
|
{
|
||||||
|
float near_pixel_size = pixel_size_at(near_t);
|
||||||
|
vec3 near_center = vs_near_plane + vs_view_direction * near_t;
|
||||||
|
|
||||||
|
float far_pixel_size = pixel_size_at(far_t);
|
||||||
|
vec3 far_center = vs_near_plane + vs_view_direction * far_t;
|
||||||
|
|
||||||
|
sphere_center = mix(near_center, far_center, 0.5);
|
||||||
|
sphere_radius = 0;
|
||||||
|
|
||||||
|
for (int x = -1; x <= 1; x += 2) {
|
||||||
|
for (int y = -1; y <= 1; y += 2) {
|
||||||
|
vec3 near_corner = near_center + (near_pixel_size * 0.5 * vec3(x, y, 0));
|
||||||
|
sphere_radius = max(sphere_radius, len_squared(near_corner - sphere_center));
|
||||||
|
|
||||||
|
vec3 far_corner = far_center + (far_pixel_size * 0.5 * vec3(x, y, 0));
|
||||||
|
sphere_radius = max(sphere_radius, len_squared(far_corner - sphere_center));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sphere_center = point_view_to_world(sphere_center);
|
||||||
|
sphere_radius = sqrt(sphere_radius);
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
shadow_tag_usage(interp.vP, interp.P, gl_FragCoord.xy);
|
vec2 screen_uv = gl_FragCoord.xy / vec2(fb_resolution);
|
||||||
|
|
||||||
|
float opaque_depth = texelFetch(hiz_tx, int2(gl_FragCoord.xy), fb_lod).r;
|
||||||
|
vec3 ws_opaque = get_world_space_from_depth(screen_uv, opaque_depth);
|
||||||
|
|
||||||
|
vec3 ws_near_plane = get_world_space_from_depth(screen_uv, 0);
|
||||||
|
vec3 ws_view_direction = normalize(interp.P - ws_near_plane);
|
||||||
|
vec3 vs_near_plane = get_view_space_from_depth(screen_uv, 0);
|
||||||
|
vec3 vs_view_direction = normalize(interp.vP - vs_near_plane);
|
||||||
|
vec3 ls_near_plane = point_world_to_object(ws_near_plane);
|
||||||
|
vec3 ls_view_direction = normalize(point_world_to_object(interp.P) - ls_near_plane);
|
||||||
|
|
||||||
|
/* TODO (Miguel Pozo): We could try to ray-cast against the non-inflated bounds first,
|
||||||
|
* and fallback to the inflated ones if theres no hit.
|
||||||
|
* The inflated bounds can cause unnecesary extra steps. */
|
||||||
|
float ls_near_box_t = ray_aabb(
|
||||||
|
ls_near_plane, ls_view_direction, interp.ls_aabb_min, interp.ls_aabb_max);
|
||||||
|
vec3 ls_near_box = ls_near_plane + ls_view_direction * ls_near_box_t;
|
||||||
|
vec3 ws_near_box = point_object_to_world(ls_near_box);
|
||||||
|
|
||||||
|
float near_box_t = distance(ws_near_plane, ws_near_box);
|
||||||
|
float far_box_t = distance(ws_near_plane, interp.P);
|
||||||
|
/* Depth test. */
|
||||||
|
far_box_t = min(far_box_t, distance(ws_near_plane, ws_opaque));
|
||||||
|
|
||||||
|
/* Ray march from the front to the back of the bbox, and tag shadow usage along the way. */
|
||||||
|
float step_size;
|
||||||
|
for (float t = near_box_t; t <= far_box_t; t += step_size) {
|
||||||
|
/* Ensure we don't get past far_box_t. */
|
||||||
|
t = min(t, far_box_t);
|
||||||
|
step_size = pixel_size_at(t);
|
||||||
|
|
||||||
|
vec3 P = ws_near_plane + (ws_view_direction * t);
|
||||||
|
float step_radius;
|
||||||
|
step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
|
||||||
|
vec3 vP = point_world_to_view(P);
|
||||||
|
|
||||||
|
shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
* Virtual shadowmapping: Usage tagging
|
* Virtual shadowmapping: Usage tagging
|
||||||
*
|
*
|
||||||
* Shadow pages are only allocated if they are visible.
|
* Shadow pages are only allocated if they are visible.
|
||||||
* This pass scan the depth buffer and tag all tiles that are needed for light shadowing as
|
* This contains the common logic used for tagging shadows for opaque and transparent receivers.
|
||||||
* needed.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
|
||||||
@ -14,7 +13,18 @@
|
|||||||
#pragma BLENDER_REQUIRE(eevee_light_lib.glsl)
|
#pragma BLENDER_REQUIRE(eevee_light_lib.glsl)
|
||||||
#pragma BLENDER_REQUIRE(eevee_shadow_lib.glsl)
|
#pragma BLENDER_REQUIRE(eevee_shadow_lib.glsl)
|
||||||
|
|
||||||
void shadow_tag_usage_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool is_directional)
|
void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_index)
|
||||||
|
{
|
||||||
|
if (tilemap_index > light_tilemap_max_get(light)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tile_co >>= lod;
|
||||||
|
int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod);
|
||||||
|
atomicOr(tiles_buf[tile_index], SHADOW_IS_USED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius)
|
||||||
{
|
{
|
||||||
LightData light = light_buf[l_idx];
|
LightData light = light_buf[l_idx];
|
||||||
|
|
||||||
@ -22,83 +32,141 @@ void shadow_tag_usage_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lod = 0;
|
vec3 lP = shadow_world_to_local(light, P);
|
||||||
ivec2 tile_co;
|
|
||||||
int tilemap_index = light.tilemap_index;
|
|
||||||
if (is_directional) {
|
|
||||||
vec3 lP = shadow_world_to_local(light, P);
|
|
||||||
|
|
||||||
|
if (radius == 0) {
|
||||||
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);
|
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);
|
||||||
|
shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index);
|
||||||
tile_co = coord.tile_coord;
|
|
||||||
tilemap_index = coord.tilemap_index;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
vec3 lP = light_world_to_local(light, P - light._position);
|
vec3 start_lP = shadow_world_to_local(light, P - V * radius);
|
||||||
float dist_to_light = length(lP);
|
vec3 end_lP = shadow_world_to_local(light, P + V * radius);
|
||||||
if (dist_to_light > light.influence_radius_max) {
|
int min_level = shadow_directional_level(light, start_lP - light._position);
|
||||||
return;
|
int max_level = shadow_directional_level(light, end_lP - light._position);
|
||||||
}
|
|
||||||
if (light.type == LIGHT_SPOT) {
|
for (int level = min_level; level <= max_level; level++) {
|
||||||
/* Early out if out of cone. */
|
ShadowCoordinates coord_min = shadow_directional_coordinates_at_level(
|
||||||
float angle_tan = length(lP.xy / dist_to_light);
|
light, lP - vec3(radius, radius, 0), level);
|
||||||
if (angle_tan > light.spot_tan) {
|
ShadowCoordinates coord_max = shadow_directional_coordinates_at_level(
|
||||||
return;
|
light, lP + vec3(radius, radius, 0), level);
|
||||||
|
|
||||||
|
for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) {
|
||||||
|
for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) {
|
||||||
|
shadow_tag_usage_tile(light, ivec2(x, y), 0, coord_min.tilemap_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_area_light(light.type)) {
|
|
||||||
/* Early out if on the wrong side. */
|
|
||||||
if (lP.z > 0.0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* How much a shadow map pixel covers a final image pixel.
|
|
||||||
* We project a shadow map pixel (as a sphere for simplicity) to the receiver plane.
|
|
||||||
* We then reproject this sphere onto the camera screen and compare it to the film pixel size.
|
|
||||||
* This gives a good approximation of what LOD to select to get a somewhat uniform shadow map
|
|
||||||
* resolution in screen space. */
|
|
||||||
float footprint_ratio = dist_to_light;
|
|
||||||
/* Project the radius to the screen. 1 unit away from the camera the same way
|
|
||||||
* pixel_world_radius_inv was computed. Not needed in orthographic mode. */
|
|
||||||
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
|
||||||
if (is_persp) {
|
|
||||||
footprint_ratio /= dist_to_cam;
|
|
||||||
}
|
|
||||||
/* Apply resolution ratio. */
|
|
||||||
footprint_ratio *= tilemap_projection_ratio;
|
|
||||||
|
|
||||||
int face_id = shadow_punctual_face_index_get(lP);
|
|
||||||
lP = shadow_punctual_local_position_to_face_local(face_id, lP);
|
|
||||||
|
|
||||||
ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id);
|
|
||||||
tile_co = coord.tile_coord;
|
|
||||||
tilemap_index = coord.tilemap_index;
|
|
||||||
|
|
||||||
lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias));
|
|
||||||
lod = clamp(lod, 0, SHADOW_TILEMAP_LOD);
|
|
||||||
}
|
}
|
||||||
tile_co >>= lod;
|
}
|
||||||
|
|
||||||
if (tilemap_index > light_tilemap_max_get(light)) {
|
void shadow_tag_usage_tilemap_punctual(uint l_idx, vec3 P, vec3 V, float dist_to_cam, float radius)
|
||||||
|
{
|
||||||
|
LightData light = light_buf[l_idx];
|
||||||
|
|
||||||
|
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod);
|
vec3 lP = light_world_to_local(light, P - light._position);
|
||||||
atomicOr(tiles_buf[tile_index], SHADOW_IS_USED);
|
float dist_to_light = length(lP) - radius;
|
||||||
|
if (dist_to_light > light.influence_radius_max) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (light.type == LIGHT_SPOT) {
|
||||||
|
/* Early out if out of cone. */
|
||||||
|
float angle_tan = length(lP.xy / dist_to_light);
|
||||||
|
if (angle_tan > light.spot_tan) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (is_area_light(light.type)) {
|
||||||
|
/* Early out if on the wrong side. */
|
||||||
|
if (lP.z - radius > 0.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* How much a shadow map pixel covers a final image pixel.
|
||||||
|
* We project a shadow map pixel (as a sphere for simplicity) to the receiver plane.
|
||||||
|
* We then reproject this sphere onto the camera screen and compare it to the film pixel size.
|
||||||
|
* This gives a good approximation of what LOD to select to get a somewhat uniform shadow map
|
||||||
|
* resolution in screen space. */
|
||||||
|
float footprint_ratio = dist_to_light;
|
||||||
|
/* Project the radius to the screen. 1 unit away from the camera the same way
|
||||||
|
* pixel_world_radius_inv was computed. Not needed in orthographic mode. */
|
||||||
|
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||||
|
if (is_persp) {
|
||||||
|
footprint_ratio /= dist_to_cam;
|
||||||
|
}
|
||||||
|
/* Apply resolution ratio. */
|
||||||
|
footprint_ratio *= tilemap_projection_ratio;
|
||||||
|
|
||||||
|
if (radius == 0) {
|
||||||
|
int face_id = shadow_punctual_face_index_get(lP);
|
||||||
|
lP = shadow_punctual_local_position_to_face_local(face_id, lP);
|
||||||
|
ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id);
|
||||||
|
|
||||||
|
int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[coord.tilemap_index].lod_bias));
|
||||||
|
lod = clamp(lod, 0, SHADOW_TILEMAP_LOD);
|
||||||
|
|
||||||
|
shadow_tag_usage_tile(light, coord.tile_coord, lod, coord.tilemap_index);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint faces = 0u;
|
||||||
|
for (int x = -1; x <= 1; x += 2) {
|
||||||
|
for (int y = -1; y <= 1; y += 2) {
|
||||||
|
for (int z = -1; z <= 1; z += 2) {
|
||||||
|
vec3 _lP = lP + vec3(x, y, z) * radius;
|
||||||
|
faces |= 1u << shadow_punctual_face_index_get(_lP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int face_id = 0; face_id < 6; face_id++) {
|
||||||
|
if ((faces & (1u << uint(face_id))) == 0u) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tilemap_index = light.tilemap_index + face_id;
|
||||||
|
int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias));
|
||||||
|
lod = clamp(lod, 0, SHADOW_TILEMAP_LOD);
|
||||||
|
|
||||||
|
vec3 _lP = shadow_punctual_local_position_to_face_local(face_id, lP);
|
||||||
|
|
||||||
|
vec3 offset = vec3(radius, radius, 0);
|
||||||
|
ShadowCoordinates coord_min = shadow_punctual_coordinates(light, _lP - offset, face_id);
|
||||||
|
ShadowCoordinates coord_max = shadow_punctual_coordinates(light, _lP + offset, face_id);
|
||||||
|
|
||||||
|
for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) {
|
||||||
|
for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) {
|
||||||
|
shadow_tag_usage_tile(light, ivec2(x, y), lod, tilemap_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \a radius Radius of the tagging area in world space.
|
||||||
|
* Used for downsampled/ray-marched tagging, so all the shadowmap texels covered get correctly
|
||||||
|
* tagged.
|
||||||
|
*/
|
||||||
|
void shadow_tag_usage(vec3 vP, vec3 P, vec3 V, float radius, float dist_to_cam, vec2 pixel)
|
||||||
|
{
|
||||||
|
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||||
|
shadow_tag_usage_tilemap_directional(l_idx, P, V, radius);
|
||||||
|
}
|
||||||
|
LIGHT_FOREACH_END
|
||||||
|
|
||||||
|
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) {
|
||||||
|
shadow_tag_usage_tilemap_punctual(l_idx, P, V, dist_to_cam, radius);
|
||||||
|
}
|
||||||
|
LIGHT_FOREACH_END
|
||||||
}
|
}
|
||||||
|
|
||||||
void shadow_tag_usage(vec3 vP, vec3 P, vec2 pixel)
|
void shadow_tag_usage(vec3 vP, vec3 P, vec2 pixel)
|
||||||
{
|
{
|
||||||
float dist_to_cam = length(vP);
|
float dist_to_cam = length(vP);
|
||||||
|
|
||||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
shadow_tag_usage(vP, P, vec3(0), 0, dist_to_cam, pixel);
|
||||||
shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, true);
|
|
||||||
}
|
|
||||||
LIGHT_FOREACH_END
|
|
||||||
|
|
||||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) {
|
|
||||||
shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, false);
|
|
||||||
}
|
|
||||||
LIGHT_FOREACH_END
|
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,89 @@
|
|||||||
* Virtual shadowmapping: Usage tagging
|
* Virtual shadowmapping: Usage tagging
|
||||||
*
|
*
|
||||||
* Shadow pages are only allocated if they are visible.
|
* Shadow pages are only allocated if they are visible.
|
||||||
* This renders bounding boxes for transparent objects in order to tag the correct shadows.
|
* This renders the bounding boxes for transparent objects in order to tag the correct shadows.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||||
|
#pragma BLENDER_REQUIRE(common_shape_lib.glsl)
|
||||||
|
|
||||||
|
#pragma BLENDER_REQUIRE(common_debug_shape_lib.glsl)
|
||||||
|
|
||||||
|
/* Inflate bounds by half a pixel as a conservative rasterization alternative,
|
||||||
|
* to ensure the tiles needed by all LOD0 pixels get tagged */
|
||||||
|
void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP)
|
||||||
|
{
|
||||||
|
vec3 vP = point_world_to_view(P);
|
||||||
|
|
||||||
|
float inflate_scale = pixel_world_radius * exp2(fb_lod);
|
||||||
|
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||||
|
if (is_persp) {
|
||||||
|
inflate_scale *= -vP.z;
|
||||||
|
}
|
||||||
|
/* Half-pixel. */
|
||||||
|
inflate_scale *= 0.5;
|
||||||
|
|
||||||
|
vec3 vs_inflate_vector = normal_object_to_view(sign(lP - ls_center));
|
||||||
|
vs_inflate_vector.z = 0;
|
||||||
|
/* Scale the vector so the largest axis length is 1 */
|
||||||
|
vs_inflate_vector /= max_v2(abs(vs_inflate_vector.xy));
|
||||||
|
vs_inflate_vector *= inflate_scale;
|
||||||
|
|
||||||
|
vP += vs_inflate_vector;
|
||||||
|
P = point_view_to_world(vP);
|
||||||
|
lP = point_world_to_object(P);
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
ObjectBounds bounds = bounds_buf[drw_ResourceID];
|
PASS_RESOURCE_ID
|
||||||
|
|
||||||
interp.P = bounds.bounding_corners[0].xyz;
|
const ObjectBounds bounds = bounds_buf[resource_id];
|
||||||
interp.P += bounds.bounding_corners[1].xyz * pos.x;
|
|
||||||
interp.P += bounds.bounding_corners[2].xyz * pos.y;
|
Box box = shape_box(bounds.bounding_corners[0].xyz,
|
||||||
interp.P += bounds.bounding_corners[3].xyz * pos.z;
|
bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz,
|
||||||
|
bounds.bounding_corners[0].xyz + bounds.bounding_corners[2].xyz,
|
||||||
|
bounds.bounding_corners[0].xyz + bounds.bounding_corners[3].xyz);
|
||||||
|
|
||||||
|
vec3 ws_aabb_min = bounds.bounding_corners[0].xyz;
|
||||||
|
vec3 ws_aabb_max = bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz +
|
||||||
|
bounds.bounding_corners[2].xyz + bounds.bounding_corners[3].xyz;
|
||||||
|
|
||||||
|
vec3 ls_center = point_world_to_object((ws_aabb_min + ws_aabb_max) / 2.0);
|
||||||
|
|
||||||
|
vec3 ls_conservative_min = vec3(FLT_MAX);
|
||||||
|
vec3 ls_conservative_max = vec3(-FLT_MAX);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
vec3 P = box.corners[i];
|
||||||
|
vec3 lP = point_world_to_object(P);
|
||||||
|
inflate_bounds(ls_center, P, lP);
|
||||||
|
|
||||||
|
ls_conservative_min = min(ls_conservative_min, lP);
|
||||||
|
ls_conservative_max = max(ls_conservative_max, lP);
|
||||||
|
}
|
||||||
|
|
||||||
|
interp.ls_aabb_min = ls_conservative_min;
|
||||||
|
interp.ls_aabb_max = ls_conservative_max;
|
||||||
|
|
||||||
|
vec3 lP = mix(ls_conservative_min, ls_conservative_max, max(vec3(0), pos));
|
||||||
|
|
||||||
|
interp.P = point_object_to_world(lP);
|
||||||
interp.vP = point_world_to_view(interp.P);
|
interp.vP = point_world_to_view(interp.P);
|
||||||
|
|
||||||
gl_Position = point_world_to_ndc(interp.P);
|
gl_Position = point_world_to_ndc(interp.P);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (gl_VertexID == 0) {
|
||||||
|
Box debug_box = shape_box(
|
||||||
|
ls_conservative_min,
|
||||||
|
ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(1, 0, 0),
|
||||||
|
ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(0, 1, 0),
|
||||||
|
ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(0, 0, 1));
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
debug_box.corners[i] = point_object_to_world(debug_box.corners[i]);
|
||||||
|
}
|
||||||
|
drw_debug(debug_box);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,12 @@ ShadowTileData shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilem
|
|||||||
return shadow_tile_unpack(tile_data);
|
return shadow_tile_unpack(tile_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function should be the inverse of ShadowDirectional::coverage_get(). */
|
/**
|
||||||
|
* This function should be the inverse of ShadowDirectional::coverage_get().
|
||||||
|
*
|
||||||
|
* \a lP shading point position in light space, relative to the to camera position snapped to
|
||||||
|
* the smallest clipmap level (`shadow_world_to_local(light, P) - light._position`).
|
||||||
|
*/
|
||||||
int shadow_directional_level(LightData light, vec3 lP)
|
int shadow_directional_level(LightData light, vec3 lP)
|
||||||
{
|
{
|
||||||
float lod;
|
float lod;
|
||||||
@ -144,14 +149,11 @@ ivec2 shadow_decompress_grid_offset(eLightType light_type, ivec2 offset, int lev
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \a lP shading point position in light space (world unit) and translated to camera position
|
* \a lP shading point position in light space (`shadow_world_to_local(light, P)`).
|
||||||
* snapped to smallest clipmap level.
|
|
||||||
*/
|
*/
|
||||||
ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
|
ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3 lP, int level)
|
||||||
{
|
{
|
||||||
ShadowCoordinates ret;
|
ShadowCoordinates ret;
|
||||||
|
|
||||||
int level = shadow_directional_level(light, lP - light._position);
|
|
||||||
/* This difference needs to be less than 32 for the later shift to be valid.
|
/* This difference needs to be less than 32 for the later shift to be valid.
|
||||||
* This is ensured by ShadowDirectional::clipmap_level_range(). */
|
* This is ensured by ShadowDirectional::clipmap_level_range(). */
|
||||||
int level_relative = level - light.clipmap_lod_min;
|
int level_relative = level - light.clipmap_lod_min;
|
||||||
@ -173,6 +175,15 @@ ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \a lP shading point position in light space (`shadow_world_to_local(light, P)`).
|
||||||
|
*/
|
||||||
|
ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
|
||||||
|
{
|
||||||
|
int level = shadow_directional_level(light, lP - light._position);
|
||||||
|
return shadow_directional_coordinates_at_level(light, lP, level);
|
||||||
|
}
|
||||||
|
|
||||||
/* Transform vector to face local coordinate. */
|
/* Transform vector to face local coordinate. */
|
||||||
vec3 shadow_punctual_local_position_to_face_local(int face_id, vec3 lL)
|
vec3 shadow_punctual_local_position_to_face_local(int face_id, vec3 lL)
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,9 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
|
|||||||
|
|
||||||
GPU_SHADER_INTERFACE_INFO(eevee_shadow_tag_transparent_iface, "interp")
|
GPU_SHADER_INTERFACE_INFO(eevee_shadow_tag_transparent_iface, "interp")
|
||||||
.smooth(Type::VEC3, "P")
|
.smooth(Type::VEC3, "P")
|
||||||
.smooth(Type::VEC3, "vP");
|
.smooth(Type::VEC3, "vP")
|
||||||
|
.flat(Type::VEC3, "ls_aabb_min")
|
||||||
|
.flat(Type::VEC3, "ls_aabb_max");
|
||||||
|
|
||||||
GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
|
GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
|
||||||
.do_static_compilation(true)
|
.do_static_compilation(true)
|
||||||
@ -63,9 +65,17 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
|
|||||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||||
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||||
|
.push_constant(Type::FLOAT, "pixel_world_radius")
|
||||||
|
.push_constant(Type::IVEC2, "fb_resolution")
|
||||||
|
.push_constant(Type::INT, "fb_lod")
|
||||||
.vertex_out(eevee_shadow_tag_transparent_iface)
|
.vertex_out(eevee_shadow_tag_transparent_iface)
|
||||||
.additional_info(
|
.additional_info("eevee_shared",
|
||||||
"eevee_shared", "draw_view", "draw_view_culling", "draw_modelmat_new", "eevee_light_data")
|
"draw_resource_id_varying",
|
||||||
|
"draw_view",
|
||||||
|
"draw_view_culling",
|
||||||
|
"draw_modelmat_new",
|
||||||
|
"eevee_hiz_data",
|
||||||
|
"eevee_light_data")
|
||||||
.vertex_source("eevee_shadow_tag_usage_vert.glsl")
|
.vertex_source("eevee_shadow_tag_usage_vert.glsl")
|
||||||
.fragment_source("eevee_shadow_tag_usage_frag.glsl");
|
.fragment_source("eevee_shadow_tag_usage_frag.glsl");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user