mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
EEVEE: Add support for camera light visibility
Ref #119100 Adds support for `visible_camera` in EEVEE. Pull Request: https://projects.blender.org/blender/blender/pulls/158416
This commit is contained in:
parent
d0c8ae7db3
commit
f07bcb85cb
23 changed files with 268 additions and 27 deletions
|
|
@ -437,6 +437,7 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
|
|||
if ob.type in {'LIGHT'}:
|
||||
layout.separator()
|
||||
col = layout.column(heading="Ray Visibility")
|
||||
col.prop(ob, "visible_camera", text="Camera", toggle=False)
|
||||
col.prop(ob, "visible_diffuse", text="Diffuse", toggle=False)
|
||||
col.prop(ob, "visible_glossy", text="Glossy", toggle=False)
|
||||
col.prop(ob, "visible_transmission", text="Transmission", toggle=False)
|
||||
|
|
|
|||
|
|
@ -445,6 +445,7 @@ set(GLSL_SRC
|
|||
engines/eevee/shaders/eevee_hiz_update_comp.glsl
|
||||
engines/eevee/shaders/eevee_fast_gi.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_culling.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_shape_display.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_shadow_setup.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_data.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_eval.bsl.hh
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ void Light::sync(ShadowModule &shadows,
|
|||
this->lod_min = shadow_lod_min_get(la);
|
||||
this->filter_radius = la->shadow_filter_radius;
|
||||
this->shadow_jitter = (la->mode & LA_SHADOW_JITTER) != 0;
|
||||
this->visible_camera = (visibility_flag & OB_HIDE_CAMERA) == 0;
|
||||
|
||||
if (la->mode & LA_SHADOW) {
|
||||
shadow_ensure(shadows);
|
||||
|
|
@ -376,6 +377,7 @@ void LightModule::add_world_sun_light(const ObjectKey &key, bool use_diffuse, bo
|
|||
int visibility_flag = 0;
|
||||
SET_FLAG_FROM_TEST(visibility_flag, !use_diffuse, OB_HIDE_DIFFUSE);
|
||||
SET_FLAG_FROM_TEST(visibility_flag, !use_glossy, OB_HIDE_GLOSSY);
|
||||
visibility_flag |= OB_HIDE_CAMERA;
|
||||
|
||||
Light &light = light_map_.lookup_or_add_default(key);
|
||||
light.used = true;
|
||||
|
|
@ -535,9 +537,27 @@ void LightModule::end_sync()
|
|||
|
||||
culling_pass_sync();
|
||||
update_pass_sync();
|
||||
shape_display_pass_sync();
|
||||
debug_pass_sync();
|
||||
}
|
||||
|
||||
void LightModule::shape_display_pass_sync()
|
||||
{
|
||||
shape_display_ps_.init();
|
||||
|
||||
if (lights_len_ == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
shape_display_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD |
|
||||
DRW_STATE_CLIP_CONTROL_UNIT_RANGE | inst_.film.depth.test_state);
|
||||
shape_display_ps_.shader_set(inst_.shaders.static_shader_get(LIGHT_SHAPE_DISPLAY));
|
||||
shape_display_ps_.bind_resources(inst_.uniform_data);
|
||||
shape_display_ps_.bind_resources(inst_.volume.result);
|
||||
shape_display_ps_.bind_resources(inst_.lights);
|
||||
shape_display_ps_.draw_procedural(GPU_PRIM_TRIS, 1, lights_len_ * 6);
|
||||
}
|
||||
|
||||
void LightModule::culling_pass_sync()
|
||||
{
|
||||
uint safe_lights_len = max_ii(lights_len_, 1);
|
||||
|
|
@ -654,6 +674,12 @@ void LightModule::debug_draw(View &view, gpu::FrameBuffer *view_fb)
|
|||
}
|
||||
}
|
||||
|
||||
void LightModule::shape_display_draw(View &view, gpu::FrameBuffer *view_fb)
|
||||
{
|
||||
GPU_framebuffer_bind(view_fb);
|
||||
inst_.manager->submit(shape_display_ps_, view);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::eevee
|
||||
|
|
|
|||
|
|
@ -175,6 +175,8 @@ class LightModule {
|
|||
|
||||
/** Update light on the GPU after culling. Ran for each sample. */
|
||||
PassSimple update_ps_ = {"LightUpdate"};
|
||||
/** Draw camera-visible light shapes. */
|
||||
PassSimple shape_display_ps_ = {"Light.ShapeDisplay"};
|
||||
|
||||
/** Debug Culling visualization. */
|
||||
PassSimple debug_draw_ps_ = {"LightCulling.Debug"};
|
||||
|
|
@ -192,6 +194,7 @@ class LightModule {
|
|||
*/
|
||||
void set_view(View &view, const int2 extent);
|
||||
|
||||
void shape_display_draw(View &view, gpu::FrameBuffer *view_fb);
|
||||
void debug_draw(View &view, gpu::FrameBuffer *view_fb);
|
||||
|
||||
template<typename PassType> void bind_resources(PassType &pass)
|
||||
|
|
@ -205,6 +208,7 @@ class LightModule {
|
|||
private:
|
||||
void culling_pass_sync();
|
||||
void update_pass_sync();
|
||||
void shape_display_pass_sync();
|
||||
void debug_pass_sync();
|
||||
|
||||
void add_world_sun_light(const ObjectKey &key, bool use_diffuse, bool use_glossy);
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ struct [[host_shared]] LightData {
|
|||
float lod_min;
|
||||
/* True if the light uses jittered soft shadows. */
|
||||
bool32_t shadow_jitter;
|
||||
float _pad2;
|
||||
/* True if the light shape should be visible to camera rays. */
|
||||
bool32_t visible_camera;
|
||||
uint2 light_set_membership;
|
||||
/** Used by shadow sync. */
|
||||
/* TODO(fclem): this should be part of #eevee::Light struct. But for some reason it gets cleared
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ ShaderGroups ShaderModule::static_shaders_load(const ShaderGroups request_bits,
|
|||
LIGHT_CULLING_SORT,
|
||||
LIGHT_CULLING_TILE,
|
||||
LIGHT_CULLING_ZBIN,
|
||||
LIGHT_SHAPE_DISPLAY,
|
||||
LIGHT_SHADOW_SETUP};
|
||||
request(LIGHT_CULLING_SHADERS, AS_SPAN(shader_list));
|
||||
}
|
||||
|
|
@ -449,6 +450,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
|
|||
return "eevee_light_culling_tile";
|
||||
case LIGHT_CULLING_ZBIN:
|
||||
return "eevee_light_culling_zbin";
|
||||
case LIGHT_SHAPE_DISPLAY:
|
||||
return "eevee_light_shape_display";
|
||||
case LIGHT_SHADOW_SETUP:
|
||||
return "eevee_light_shadow_setup";
|
||||
case RAY_DENOISE_SPATIAL:
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ enum eShaderType {
|
|||
LIGHT_CULLING_SORT,
|
||||
LIGHT_CULLING_TILE,
|
||||
LIGHT_CULLING_ZBIN,
|
||||
LIGHT_SHAPE_DISPLAY,
|
||||
LIGHT_SHADOW_SETUP,
|
||||
|
||||
LIGHTPROBE_IRRADIANCE_BOUNDS,
|
||||
|
|
|
|||
|
|
@ -169,6 +169,8 @@ void ShadingView::render()
|
|||
inst_.pipelines.forward.render(
|
||||
render_view_, rbufs.depth_tx, prepass_fb_, transparent_fb_, combined_fb_, extent_);
|
||||
|
||||
inst_.lights.shape_display_draw(render_view_, combined_fb_);
|
||||
|
||||
inst_.lights.debug_draw(render_view_, combined_fb_);
|
||||
inst_.hiz_buffer.debug_draw(render_view_, combined_fb_);
|
||||
inst_.shadows.debug_draw(render_view_, combined_fb_);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "eevee_light_eval.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_iter.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_shadow_setup.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_shape_display.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_lightprobe_display.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_ltc_lib.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_ltc_lut_lib.bsl.hh" /* IWYU pragma: export */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "draw_view_infos.hh"
|
||||
#include "infos/eevee_light_infos.hh"
|
||||
#include "infos/eevee_volume_resolved_infos.hh"
|
||||
|
||||
FRAGMENT_SHADER_CREATE_INFO(draw_view)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_light_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_volume_lib)
|
||||
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_reverse_z_lib.bsl.hh"
|
||||
#include "eevee_volume_lib.bsl.hh"
|
||||
#include "gpu_shader_math_base_lib.glsl"
|
||||
#include "gpu_shader_math_constants_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_transform_lib.glsl"
|
||||
|
||||
namespace eevee::light {
|
||||
|
||||
struct ShapeDisplayResources {
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_volume_lib;
|
||||
};
|
||||
|
||||
struct ShapeDisplayVertOut {
|
||||
[[smooth]] float2 lP;
|
||||
[[smooth]] float3 P;
|
||||
[[flat]] float3 radiance;
|
||||
[[flat]] int light_index;
|
||||
[[flat]] uint light_type;
|
||||
};
|
||||
|
||||
struct ShapeDisplayFragOut {
|
||||
[[frag_color(0)]] float4 out_color;
|
||||
};
|
||||
|
||||
float shape_display_light_radiance_get(LightData light)
|
||||
{
|
||||
if (is_sun_light(light.type)) {
|
||||
float radius = light.sun().shape_radius;
|
||||
return M_1_PI * (1.0f + 1.0f / max(radius * radius, 1e-20f));
|
||||
}
|
||||
|
||||
if (is_area_light(light.type)) {
|
||||
float area = light.area().size.x * light.area().size.y * 4.0f;
|
||||
if (light.type == LIGHT_ELLIPSE) {
|
||||
area *= M_PI * 0.25f;
|
||||
}
|
||||
return 1.0f / max(M_PI * area, 1e-20f);
|
||||
}
|
||||
|
||||
float radius = light.local().local.shape_radius;
|
||||
float area = 4.0f * M_PI * radius * radius;
|
||||
return 1.0f / max(M_PI * area, 1e-20f);
|
||||
}
|
||||
|
||||
float3 shape_display_light_position_get(LightData light, float2 quad_pos)
|
||||
{
|
||||
if (is_area_light(light.type)) {
|
||||
return transform_point(light.object_to_world, float3(quad_pos * light.area().size, 0.0f));
|
||||
}
|
||||
|
||||
float radius = light.local().local.shape_radius;
|
||||
float3 center = light_position_get(light);
|
||||
float3 view_right = drw_view().viewinv[0].xyz;
|
||||
float3 view_up = drw_view().viewinv[1].xyz;
|
||||
float3 L = center - drw_view_position();
|
||||
float dist = length(L);
|
||||
if (dist > 1e-8f) {
|
||||
L /= dist;
|
||||
make_orthonormal_basis(L, view_right, view_up);
|
||||
}
|
||||
|
||||
if (is_sphere_light(light.type)) {
|
||||
if (dist > radius) {
|
||||
radius = light_sphere_disk_radius(radius, dist);
|
||||
}
|
||||
else {
|
||||
radius = drw_view_far();
|
||||
}
|
||||
}
|
||||
|
||||
return center + (view_right * quad_pos.x + view_up * quad_pos.y) * radius;
|
||||
}
|
||||
|
||||
float3 shape_display_far_plane_position_get(float2 ndc_pos)
|
||||
{
|
||||
return drw_point_ndc_to_world(float3(ndc_pos, 1.0f));
|
||||
}
|
||||
|
||||
float2 shape_display_quad_position_get(int vertex_id)
|
||||
{
|
||||
int quad_vertex_id = vertex_id % 6;
|
||||
float x = (quad_vertex_id == 0 || quad_vertex_id == 2 || quad_vertex_id == 5) ? -1.0f : 1.0f;
|
||||
float y = (quad_vertex_id == 0 || quad_vertex_id == 1 || quad_vertex_id == 3) ? -1.0f : 1.0f;
|
||||
return float2(x, y);
|
||||
}
|
||||
|
||||
[[vertex]] [[clip_control]]
|
||||
void shape_display_vert([[resource_table]] const ShapeDisplayResources & /*srt*/,
|
||||
[[vertex_id]] const int vertex_id,
|
||||
[[out]] ShapeDisplayVertOut &v_out,
|
||||
[[position]] float4 &out_position)
|
||||
{
|
||||
v_out.lP = shape_display_quad_position_get(vertex_id);
|
||||
v_out.P = float3(0.0f);
|
||||
v_out.radiance = float3(0.0f);
|
||||
v_out.light_index = 0;
|
||||
v_out.light_type = uint(LIGHT_RECT);
|
||||
out_position = float4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
int draw_index = vertex_id / 6;
|
||||
int visible_count = int(light_cull_buf.visible_count + light_cull_buf.sun_lights_len);
|
||||
|
||||
if (draw_index >= visible_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
int light_index;
|
||||
if (draw_index < int(light_cull_buf.visible_count)) {
|
||||
light_index = draw_index;
|
||||
}
|
||||
else {
|
||||
int offset = draw_index - int(light_cull_buf.visible_count);
|
||||
light_index = int(light_cull_buf.local_lights_len) + offset;
|
||||
}
|
||||
|
||||
LightData light = light_buf[light_index];
|
||||
if (!light.visible_camera) {
|
||||
return;
|
||||
}
|
||||
|
||||
v_out.light_type = uint(light.type);
|
||||
v_out.light_index = light_index;
|
||||
v_out.radiance = light.color * shape_display_light_radiance_get(light);
|
||||
|
||||
if (is_sun_light(light.type)) {
|
||||
v_out.P = shape_display_far_plane_position_get(v_out.lP);
|
||||
out_position = reverse_z::transform(float4(v_out.lP, 1.0f, 1.0f));
|
||||
return;
|
||||
}
|
||||
|
||||
v_out.P = shape_display_light_position_get(light, v_out.lP);
|
||||
out_position = reverse_z::transform(drw_point_world_to_homogenous(v_out.P));
|
||||
}
|
||||
|
||||
[[fragment]]
|
||||
void shape_display_frag([[resource_table]] const ShapeDisplayResources & /*srt*/,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[in]] const ShapeDisplayVertOut &v_out,
|
||||
[[out]] ShapeDisplayFragOut &frag_out)
|
||||
{
|
||||
eLightType light_type = eLightType(v_out.light_type);
|
||||
LightData light = light_buf[v_out.light_index];
|
||||
float3 P = v_out.P;
|
||||
|
||||
if (is_sun_light(light_type)) {
|
||||
float3 V = -drw_world_incident_vector(P);
|
||||
float3 sun_direction = light.sun().direction;
|
||||
float sun_cos = cos_from_tan(light.sun().shape_radius);
|
||||
if (dot(V, sun_direction) < sun_cos) {
|
||||
gpu_discard_fragment();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_area_light(light_type) && dot(drw_world_incident_vector(P), light_z_axis(light)) > 0.0f)
|
||||
{
|
||||
gpu_discard_fragment();
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_circle = light_type == LIGHT_ELLIPSE || is_point_light(light_type);
|
||||
if (is_circle && dot(v_out.lP, v_out.lP) > 1.0f) {
|
||||
gpu_discard_fragment();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float depth = reverse_z::read(frag_co.z);
|
||||
|
||||
float2 uvs = frag_co.xy * uniform_buf.volumes.main_view_extent_inv;
|
||||
float3 radiance = v_out.radiance;
|
||||
if (is_spot_light(light_type)) {
|
||||
radiance *= light_spot_attenuation(light, -drw_world_incident_vector(P));
|
||||
}
|
||||
|
||||
VolumeResolveSample vol = volume_resolve(
|
||||
float3(uvs, depth), volume_transmittance_tx, volume_scattering_tx);
|
||||
frag_out.out_color = float4(radiance * vol.transmittance, 1.0f);
|
||||
}
|
||||
|
||||
PipelineGraphic shape_display(shape_display_vert, shape_display_frag);
|
||||
|
||||
} // namespace eevee::light
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8c403104659e659032d1214a6431277b5f65584330a0a741cce8b5c0a9bbf3b2
|
||||
size 21399
|
||||
oid sha256:5ec41f722897d0ef6d0edc1efbd364b55b7d57e7098c2ac714842aae9bc58265
|
||||
size 21482
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9abcdd0f48a74e7b4da7b7f9ebc234755605665f2f6aad7033381cad33927b3d
|
||||
size 27852
|
||||
oid sha256:a7f44182dda3bb5ada6428290d3c5e01c21c011b87390bb15d62c40fe6063566
|
||||
size 27962
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6524a94b41bf9270dc60d8184ecfdbcd4b54d845019db6671213aecfa644d5f2
|
||||
size 12940
|
||||
oid sha256:c977e74ae7d26b2794e15fa602f7acc0255c66c1ef32f68bd01ef4db60ce3524
|
||||
size 12902
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8c90f2719bf3a900b19650040a6162878f1fb648121244fe4e65de2dd321a318
|
||||
size 17086
|
||||
oid sha256:b40096d0cf2ff3aa3001162b41398556a381abe366b099c522ae5f8ae7779114
|
||||
size 17741
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9c184ca262078d82938773b6864ae327bd3658cc0352b8e7531a772182a76a7d
|
||||
size 7488
|
||||
oid sha256:478883c8f9e6a53b27706cc28e2b320ddacf3bc3c0a0488c0c26e3cd3bb39cfd
|
||||
size 6382
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:749da7dd876bc17706200cc5f27dee02342eced95603e9da2b88843f1866fbd9
|
||||
size 18790
|
||||
oid sha256:becaa2961d6c4715d1e3468921581c92d0038fe51cd0b9660339c6bfabf0d68b
|
||||
size 18198
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c9e73537f23761d15ea48b3746639b82501fa94f5772ef3b12e6c5f1c1b43cc0
|
||||
size 16261
|
||||
oid sha256:61e39049a9226424675f4536fda00043581d958ecb606f591d0dd54f0c8e60fb
|
||||
size 16394
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:884416f11a9df1d27f78c4cfac14474fd83e06ce1e9d5995f5677dd8177a148b
|
||||
size 16272
|
||||
oid sha256:4805d2a850f1e3b52e381ece3b64947b2b0a3549ca8e10b01e5ba1b196323b69
|
||||
size 16405
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3445164d7b646bfa424fa8b09d023f01016e10bc1901a3965d3045eafa37758c
|
||||
size 56563
|
||||
oid sha256:e3900daf1f642f948b5ae22717281ef0ce0d81d2a871619e23348fdf3eff6c96
|
||||
size 57614
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f22dd680524511b722cd07d23f36ea19b96f51b3d6e508672ee5260e2361f2f1
|
||||
size 55786
|
||||
oid sha256:11d316146b99d7c9cb07937fd151ddaba6574d28528a571e9a70fe02326097f4
|
||||
size 57177
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f7a18e76cc75f228d73edccc976b276ccbe8aa16f4fb0f96cf1c53bbbe963bc5
|
||||
size 20444
|
||||
oid sha256:52a40c3e2a0d609213563cef00a1d1c1b2ffadbd3aca3234018d5c9e02e94b4f
|
||||
size 20412
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ba68ea54078ca615b2a8cabde91a05af05601c8273f0e7908238a30d5011e941
|
||||
size 5710
|
||||
oid sha256:cfeede17acf1194a7d2dd5f62d79353c589b1e2b9ac674d70c2098ed1059726c
|
||||
size 5949
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b3565479322ad95f1f310a872094e495e6992ab050b592586455214e773c203b
|
||||
size 17744
|
||||
oid sha256:b727d62f514ad8362d5db5ce6a44b3053f7189f8fab4fb12aa898e2370e87f90
|
||||
size 17912
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue