You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-09 12:50:35 +00:00
Add support for projectors in spot and omni lights.
This commit is contained in:
@@ -70,7 +70,7 @@ void Light3D::set_shadow(bool p_enable) {
|
|||||||
shadow = p_enable;
|
shadow = p_enable;
|
||||||
RS::get_singleton()->light_set_shadow(light, p_enable);
|
RS::get_singleton()->light_set_shadow(light, p_enable);
|
||||||
|
|
||||||
if (type == RenderingServer::LIGHT_SPOT) {
|
if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {
|
||||||
update_configuration_warning();
|
update_configuration_warning();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,6 +166,18 @@ Light3D::BakeMode Light3D::get_bake_mode() const {
|
|||||||
return bake_mode;
|
return bake_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Light3D::set_projector(const Ref<Texture> &p_texture) {
|
||||||
|
|
||||||
|
projector = p_texture;
|
||||||
|
RID tex_id = projector.is_valid() ? projector->get_rid() : RID();
|
||||||
|
RS::get_singleton()->light_set_projector(light, tex_id);
|
||||||
|
update_configuration_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Texture2D> Light3D::get_projector() const {
|
||||||
|
return projector;
|
||||||
|
}
|
||||||
|
|
||||||
void Light3D::_update_visibility() {
|
void Light3D::_update_visibility() {
|
||||||
|
|
||||||
if (!is_inside_tree())
|
if (!is_inside_tree())
|
||||||
@@ -221,6 +233,10 @@ void Light3D::_validate_property(PropertyInfo &property) const {
|
|||||||
property.usage = 0;
|
property.usage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_projector") {
|
||||||
|
property.usage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
|
if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
|
||||||
property.usage = 0;
|
property.usage = 0;
|
||||||
}
|
}
|
||||||
@@ -255,10 +271,14 @@ void Light3D::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode);
|
ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode);
|
||||||
ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode);
|
ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_projector", "projector"), &Light3D::set_projector);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_projector"), &Light3D::get_projector);
|
||||||
|
|
||||||
ADD_GROUP("Light", "light_");
|
ADD_GROUP("Light", "light_");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
|
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY);
|
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY);
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
|
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_projector", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_projector", "get_projector");
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,64,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE);
|
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,64,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE);
|
||||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE);
|
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE);
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
|
||||||
@@ -444,6 +464,19 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
|
|||||||
return shadow_mode;
|
return shadow_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String OmniLight3D::get_configuration_warning() const {
|
||||||
|
String warning = Light3D::get_configuration_warning();
|
||||||
|
|
||||||
|
if (!has_shadow() && get_projector().is_valid()) {
|
||||||
|
if (warning != String()) {
|
||||||
|
warning += "\n\n";
|
||||||
|
}
|
||||||
|
warning += TTR("Projector texture only works with shadows active.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return warning;
|
||||||
|
}
|
||||||
|
|
||||||
void OmniLight3D::_bind_methods() {
|
void OmniLight3D::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &OmniLight3D::set_shadow_mode);
|
ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &OmniLight3D::set_shadow_mode);
|
||||||
@@ -475,6 +508,13 @@ String SpotLight3D::get_configuration_warning() const {
|
|||||||
warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
|
warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!has_shadow() && get_projector().is_valid()) {
|
||||||
|
if (warning != String()) {
|
||||||
|
warning += "\n\n";
|
||||||
|
}
|
||||||
|
warning += TTR("Projector texture only works with shadows active.");
|
||||||
|
}
|
||||||
|
|
||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ private:
|
|||||||
bool editor_only;
|
bool editor_only;
|
||||||
void _update_visibility();
|
void _update_visibility();
|
||||||
BakeMode bake_mode;
|
BakeMode bake_mode;
|
||||||
|
Ref<Texture2D> projector;
|
||||||
|
|
||||||
// bind helpers
|
// bind helpers
|
||||||
|
|
||||||
@@ -125,6 +126,9 @@ public:
|
|||||||
void set_bake_mode(BakeMode p_mode);
|
void set_bake_mode(BakeMode p_mode);
|
||||||
BakeMode get_bake_mode() const;
|
BakeMode get_bake_mode() const;
|
||||||
|
|
||||||
|
void set_projector(const Ref<Texture> &p_texture);
|
||||||
|
Ref<Texture2D> get_projector() const;
|
||||||
|
|
||||||
virtual AABB get_aabb() const;
|
virtual AABB get_aabb() const;
|
||||||
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
|
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const;
|
||||||
|
|
||||||
@@ -196,6 +200,8 @@ public:
|
|||||||
void set_shadow_mode(ShadowMode p_mode);
|
void set_shadow_mode(ShadowMode p_mode);
|
||||||
ShadowMode get_shadow_mode() const;
|
ShadowMode get_shadow_mode() const;
|
||||||
|
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
|
||||||
OmniLight3D();
|
OmniLight3D();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -327,8 +327,8 @@ public:
|
|||||||
|
|
||||||
virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
|
virtual Size2 texture_size_with_proxy(RID p_proxy) = 0;
|
||||||
|
|
||||||
virtual void texture_add_to_decal_atlas(RID p_texture) = 0;
|
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
|
||||||
virtual void texture_remove_from_decal_atlas(RID p_texture) = 0;
|
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
|
||||||
|
|
||||||
/* SHADER API */
|
/* SHADER API */
|
||||||
|
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ RID RasterizerEffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1
|
|||||||
return uniform_set;
|
return uniform_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y) {
|
void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
|
||||||
|
|
||||||
zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant));
|
zeromem(©_to_fb.push_constant, sizeof(CopyToFbPushConstant));
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ void RasterizerEffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_f
|
|||||||
}
|
}
|
||||||
|
|
||||||
RD::DrawListID draw_list = p_draw_list;
|
RD::DrawListID draw_list = p_draw_list;
|
||||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
|
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_panorama ? COPY_TO_FB_COPY_PANORAMA_TO_DP : COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
|
||||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
|
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
|
||||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
|
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
|
||||||
RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant));
|
RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant));
|
||||||
@@ -1238,6 +1238,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
|
|||||||
{
|
{
|
||||||
Vector<String> copy_modes;
|
Vector<String> copy_modes;
|
||||||
copy_modes.push_back("\n");
|
copy_modes.push_back("\n");
|
||||||
|
copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n");
|
||||||
|
|
||||||
copy_to_fb.shader.initialize(copy_modes);
|
copy_to_fb.shader.initialize(copy_modes);
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ class RasterizerEffectsRD {
|
|||||||
|
|
||||||
enum CopyToFBMode {
|
enum CopyToFBMode {
|
||||||
COPY_TO_FB_COPY,
|
COPY_TO_FB_COPY,
|
||||||
|
COPY_TO_FB_COPY_PANORAMA_TO_DP,
|
||||||
COPY_TO_FB_MAX,
|
COPY_TO_FB_MAX,
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -565,7 +566,7 @@ public:
|
|||||||
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false);
|
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false);
|
||||||
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
|
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
|
||||||
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
|
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
|
||||||
void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false);
|
void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);
|
||||||
void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false);
|
void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false);
|
||||||
void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
|
void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
|
||||||
|
|
||||||
|
|||||||
@@ -1841,6 +1841,30 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
|
|||||||
light_data.atlas_rect[2] = 0;
|
light_data.atlas_rect[2] = 0;
|
||||||
light_data.atlas_rect[3] = 0;
|
light_data.atlas_rect[3] = 0;
|
||||||
|
|
||||||
|
RID projector = storage->light_get_projector(base);
|
||||||
|
|
||||||
|
if (projector.is_valid()) {
|
||||||
|
Rect2 rect = storage->decal_atlas_get_texture_rect(projector);
|
||||||
|
|
||||||
|
if (type == RS::LIGHT_SPOT) {
|
||||||
|
|
||||||
|
light_data.projector_rect[0] = rect.position.x;
|
||||||
|
light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
|
||||||
|
light_data.projector_rect[2] = rect.size.width;
|
||||||
|
light_data.projector_rect[3] = -rect.size.height;
|
||||||
|
} else {
|
||||||
|
light_data.projector_rect[0] = rect.position.x;
|
||||||
|
light_data.projector_rect[1] = rect.position.y;
|
||||||
|
light_data.projector_rect[2] = rect.size.width;
|
||||||
|
light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
light_data.projector_rect[0] = 0;
|
||||||
|
light_data.projector_rect[1] = 0;
|
||||||
|
light_data.projector_rect[2] = 0;
|
||||||
|
light_data.projector_rect[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
|
if (p_using_shadows && p_shadow_atlas.is_valid() && shadow_atlas_owns_light_instance(p_shadow_atlas, li)) {
|
||||||
// fill in the shadow information
|
// fill in the shadow information
|
||||||
|
|
||||||
@@ -1892,17 +1916,11 @@ void RasterizerSceneHighEndRD::_setup_lights(RID *p_light_cull_result, int p_lig
|
|||||||
|
|
||||||
} else if (type == RS::LIGHT_SPOT) {
|
} else if (type == RS::LIGHT_SPOT) {
|
||||||
|
|
||||||
//used for clamping in this light type
|
|
||||||
light_data.atlas_rect[2] += light_data.atlas_rect[0];
|
|
||||||
light_data.atlas_rect[3] += light_data.atlas_rect[1];
|
|
||||||
|
|
||||||
Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
|
Transform modelview = (p_camera_inverse_transform * light_transform).inverse();
|
||||||
CameraMatrix bias;
|
CameraMatrix bias;
|
||||||
bias.set_light_bias();
|
bias.set_light_bias();
|
||||||
CameraMatrix rectm;
|
|
||||||
rectm.set_light_atlas_rect(rect);
|
|
||||||
|
|
||||||
CameraMatrix shadow_mtx = rectm * bias * light_instance_get_shadow_camera(li, 0) * modelview;
|
CameraMatrix shadow_mtx = bias * light_instance_get_shadow_camera(li, 0) * modelview;
|
||||||
store_camera(shadow_mtx, light_data.shadow_matrix);
|
store_camera(shadow_mtx, light_data.shadow_matrix);
|
||||||
|
|
||||||
if (size > 0.0) {
|
if (size > 0.0) {
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ class RasterizerSceneHighEndRD : public RasterizerSceneRD {
|
|||||||
float soft_shadow_scale;
|
float soft_shadow_scale;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
uint32_t pad[2];
|
uint32_t pad[2];
|
||||||
|
float projector_rect[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DirectionalLightData {
|
struct DirectionalLightData {
|
||||||
|
|||||||
@@ -3180,7 +3180,19 @@ void RasterizerStorageRD::light_set_projector(RID p_light, RID p_texture) {
|
|||||||
Light *light = light_owner.getornull(p_light);
|
Light *light = light_owner.getornull(p_light);
|
||||||
ERR_FAIL_COND(!light);
|
ERR_FAIL_COND(!light);
|
||||||
|
|
||||||
|
if (light->projector == p_texture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
|
||||||
|
texture_remove_from_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
|
||||||
|
}
|
||||||
|
|
||||||
light->projector = p_texture;
|
light->projector = p_texture;
|
||||||
|
|
||||||
|
if (light->type != RS::LIGHT_DIRECTIONAL && light->projector.is_valid()) {
|
||||||
|
texture_add_to_decal_atlas(light->projector, light->type == RS::LIGHT_OMNI);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) {
|
void RasterizerStorageRD::light_set_negative(RID p_light, bool p_enable) {
|
||||||
@@ -4381,22 +4393,30 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
|
|||||||
return RS::INSTANCE_NONE;
|
return RS::INSTANCE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture) {
|
void RasterizerStorageRD::texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
|
||||||
if (!decal_atlas.textures.has(p_texture)) {
|
if (!decal_atlas.textures.has(p_texture)) {
|
||||||
DecalAtlas::Texture t;
|
DecalAtlas::Texture t;
|
||||||
t.users = 1;
|
t.users = 1;
|
||||||
|
t.panorama_to_dp_users = p_panorama_to_dp ? 1 : 0;
|
||||||
decal_atlas.textures[p_texture] = t;
|
decal_atlas.textures[p_texture] = t;
|
||||||
decal_atlas.dirty = true;
|
decal_atlas.dirty = true;
|
||||||
} else {
|
} else {
|
||||||
DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
|
DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
|
||||||
t->users++;
|
t->users++;
|
||||||
|
if (p_panorama_to_dp) {
|
||||||
|
t->panorama_to_dp_users++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture) {
|
void RasterizerStorageRD::texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp) {
|
||||||
DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
|
DecalAtlas::Texture *t = decal_atlas.textures.getptr(p_texture);
|
||||||
ERR_FAIL_COND(!t);
|
ERR_FAIL_COND(!t);
|
||||||
t->users--;
|
t->users--;
|
||||||
|
if (p_panorama_to_dp) {
|
||||||
|
ERR_FAIL_COND(t->panorama_to_dp_users == 0);
|
||||||
|
t->panorama_to_dp_users--;
|
||||||
|
}
|
||||||
if (t->users == 0) {
|
if (t->users == 0) {
|
||||||
decal_atlas.textures.erase(p_texture);
|
decal_atlas.textures.erase(p_texture);
|
||||||
//do not mark it dirty, there is no need to since it remains working
|
//do not mark it dirty, there is no need to since it remains working
|
||||||
@@ -4590,7 +4610,7 @@ void RasterizerStorageRD::_update_decal_atlas() {
|
|||||||
while ((K = decal_atlas.textures.next(K))) {
|
while ((K = decal_atlas.textures.next(K))) {
|
||||||
DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
|
DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K);
|
||||||
Texture *src_tex = texture_owner.getornull(*K);
|
Texture *src_tex = texture_owner.getornull(*K);
|
||||||
effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list);
|
effects.copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RD::get_singleton()->draw_list_end();
|
RD::get_singleton()->draw_list_end();
|
||||||
@@ -4732,6 +4752,7 @@ bool RasterizerStorageRD::free(RID p_rid) {
|
|||||||
|
|
||||||
} else if (light_owner.owns(p_rid)) {
|
} else if (light_owner.owns(p_rid)) {
|
||||||
|
|
||||||
|
light_set_projector(p_rid, RID()); //clear projector
|
||||||
// delete the texture
|
// delete the texture
|
||||||
Light *light = light_owner.getornull(p_rid);
|
Light *light = light_owner.getornull(p_rid);
|
||||||
light->instance_dependency.instance_notify_deleted(p_rid);
|
light->instance_dependency.instance_notify_deleted(p_rid);
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ private:
|
|||||||
struct DecalAtlas {
|
struct DecalAtlas {
|
||||||
struct Texture {
|
struct Texture {
|
||||||
|
|
||||||
|
int panorama_to_dp_users;
|
||||||
int users;
|
int users;
|
||||||
Rect2 uv_rect;
|
Rect2 uv_rect;
|
||||||
};
|
};
|
||||||
@@ -599,8 +600,8 @@ public:
|
|||||||
|
|
||||||
virtual Size2 texture_size_with_proxy(RID p_proxy);
|
virtual Size2 texture_size_with_proxy(RID p_proxy);
|
||||||
|
|
||||||
virtual void texture_add_to_decal_atlas(RID p_texture);
|
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false);
|
||||||
virtual void texture_remove_from_decal_atlas(RID p_texture);
|
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false);
|
||||||
|
|
||||||
RID decal_atlas_get_texture() const;
|
RID decal_atlas_get_texture() const;
|
||||||
RID decal_atlas_get_texture_srgb() const;
|
RID decal_atlas_get_texture_srgb() const;
|
||||||
@@ -964,6 +965,14 @@ public:
|
|||||||
return light->param[p_param];
|
return light->param[p_param];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ RID light_get_projector(RID p_light) {
|
||||||
|
|
||||||
|
const Light *light = light_owner.getornull(p_light);
|
||||||
|
ERR_FAIL_COND_V(!light, RID());
|
||||||
|
|
||||||
|
return light->projector;
|
||||||
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ Color light_get_color(RID p_light) {
|
_FORCE_INLINE_ Color light_get_color(RID p_light) {
|
||||||
|
|
||||||
const Light *light = light_owner.getornull(p_light);
|
const Light *light = light_owner.getornull(p_light);
|
||||||
|
|||||||
@@ -65,6 +65,34 @@ layout(location = 0) out vec4 frag_color;
|
|||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
vec2 uv = uv_interp;
|
vec2 uv = uv_interp;
|
||||||
|
|
||||||
|
#ifdef MODE_PANORAMA_TO_DP
|
||||||
|
|
||||||
|
//obtain normal from dual paraboloid uv
|
||||||
|
#define M_PI 3.14159265359
|
||||||
|
|
||||||
|
float side;
|
||||||
|
uv.y = modf(uv.y * 2.0, side);
|
||||||
|
side = side * 2.0 - 1.0;
|
||||||
|
vec3 normal = vec3(uv * 2.0 - 1.0, 0.0);
|
||||||
|
normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
|
||||||
|
normal *= -side;
|
||||||
|
normal = normalize(normal);
|
||||||
|
|
||||||
|
//now convert normal to panorama uv
|
||||||
|
|
||||||
|
vec2 st = vec2(atan(normal.x, normal.z), acos(normal.y));
|
||||||
|
|
||||||
|
if (st.x < 0.0)
|
||||||
|
st.x += M_PI * 2.0;
|
||||||
|
|
||||||
|
uv = st / vec2(M_PI * 2.0, M_PI);
|
||||||
|
|
||||||
|
if (side < 0.0) {
|
||||||
|
//uv.y = 1.0 - uv.y;
|
||||||
|
uv = 1.0 - uv;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
vec4 color = textureLod(source_color, uv, 0.0);
|
vec4 color = textureLod(source_color, uv, 0.0);
|
||||||
if (params.force_luminance) {
|
if (params.force_luminance) {
|
||||||
color.rgb = vec3(max(max(color.r, color.g), color.b));
|
color.rgb = vec3(max(max(color.r, color.g), color.b));
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
|
|||||||
|
|
||||||
#endif //USE_NO_SHADOWS
|
#endif //USE_NO_SHADOWS
|
||||||
|
|
||||||
void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
|
void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
vec3 backlight,
|
vec3 backlight,
|
||||||
#endif
|
#endif
|
||||||
@@ -976,8 +976,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
//redo shadowmapping, but shrink the model a bit to avoid arctifacts
|
//redo shadowmapping, but shrink the model a bit to avoid arctifacts
|
||||||
splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
|
splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
|
||||||
|
|
||||||
shadow_len = length(splane);
|
shadow_len = length(splane.xyz);
|
||||||
splane = normalize(splane);
|
splane = normalize(splane.xyz);
|
||||||
|
|
||||||
if (splane.z >= 0.0) {
|
if (splane.z >= 0.0) {
|
||||||
|
|
||||||
@@ -999,7 +999,70 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
|
vec3 no_shadow = vec3(1.0);
|
||||||
|
|
||||||
|
if (lights.data[idx].projector_rect != vec4(0.0)) {
|
||||||
|
|
||||||
|
vec3 local_v = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
|
||||||
|
local_v = normalize(local_v);
|
||||||
|
|
||||||
|
vec4 atlas_rect = lights.data[idx].projector_rect;
|
||||||
|
|
||||||
|
if (local_v.z >= 0.0) {
|
||||||
|
|
||||||
|
local_v.z += 1.0;
|
||||||
|
atlas_rect.y += atlas_rect.w;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
local_v.z = 1.0 - local_v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_v.xy /= local_v.z;
|
||||||
|
local_v.xy = local_v.xy * 0.5 + 0.5;
|
||||||
|
vec2 proj_uv = local_v.xy * atlas_rect.zw;
|
||||||
|
|
||||||
|
vec2 proj_uv_ddx;
|
||||||
|
vec2 proj_uv_ddy;
|
||||||
|
{
|
||||||
|
vec3 local_v_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0)).xyz;
|
||||||
|
local_v_ddx = normalize(local_v_ddx);
|
||||||
|
|
||||||
|
if (local_v_ddx.z >= 0.0) {
|
||||||
|
|
||||||
|
local_v_ddx.z += 1.0;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
local_v_ddx.z = 1.0 - local_v_ddx.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_v_ddx.xy /= local_v_ddx.z;
|
||||||
|
local_v_ddx.xy = local_v_ddx.xy * 0.5 + 0.5;
|
||||||
|
|
||||||
|
proj_uv_ddx = local_v_ddx.xy * atlas_rect.zw - proj_uv;
|
||||||
|
|
||||||
|
vec3 local_v_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0)).xyz;
|
||||||
|
local_v_ddy = normalize(local_v_ddy);
|
||||||
|
|
||||||
|
if (local_v_ddy.z >= 0.0) {
|
||||||
|
|
||||||
|
local_v_ddy.z += 1.0;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
local_v_ddy.z = 1.0 - local_v_ddy.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_v_ddy.xy /= local_v_ddy.z;
|
||||||
|
local_v_ddy.xy = local_v_ddy.xy * 0.5 + 0.5;
|
||||||
|
|
||||||
|
proj_uv_ddy = local_v_ddy.xy * atlas_rect.zw - proj_uv;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + atlas_rect.xy, proj_uv_ddx, proj_uv_ddy);
|
||||||
|
no_shadow = mix(no_shadow, proj.rgb, proj.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow);
|
||||||
}
|
}
|
||||||
#endif //USE_NO_SHADOWS
|
#endif //USE_NO_SHADOWS
|
||||||
|
|
||||||
@@ -1030,7 +1093,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
specular_light);
|
specular_light);
|
||||||
}
|
}
|
||||||
|
|
||||||
void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
|
void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
vec3 backlight,
|
vec3 backlight,
|
||||||
#endif
|
#endif
|
||||||
@@ -1114,6 +1177,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
|
|
||||||
//find blocker
|
//find blocker
|
||||||
|
|
||||||
|
vec2 shadow_uv = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy;
|
||||||
|
|
||||||
float blocker_count = 0.0;
|
float blocker_count = 0.0;
|
||||||
float blocker_average = 0.0;
|
float blocker_average = 0.0;
|
||||||
|
|
||||||
@@ -1126,10 +1191,11 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
}
|
}
|
||||||
|
|
||||||
float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale;
|
float uv_size = lights.data[idx].soft_shadow_size * z_norm * lights.data[idx].soft_shadow_scale;
|
||||||
|
vec2 clamp_max = lights.data[idx].atlas_rect.xy + lights.data[idx].atlas_rect.zw;
|
||||||
for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
|
for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
|
||||||
|
|
||||||
vec2 suv = splane.xy + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
|
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
|
||||||
suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw);
|
suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max);
|
||||||
float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
|
float d = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), suv, 0.0).r;
|
||||||
if (d < z_norm) {
|
if (d < z_norm) {
|
||||||
blocker_average += d;
|
blocker_average += d;
|
||||||
@@ -1146,8 +1212,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
|
|
||||||
shadow = 0.0;
|
shadow = 0.0;
|
||||||
for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
|
for (uint i = 0; i < scene_data.penumbra_shadow_samples; i++) {
|
||||||
vec2 suv = splane.xy + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
|
vec2 suv = shadow_uv + (disk_rotation * scene_data.penumbra_shadow_kernel[i].xy) * uv_size;
|
||||||
suv = clamp(suv, lights.data[idx].atlas_rect.xy, lights.data[idx].atlas_rect.zw);
|
suv = clamp(suv, lights.data[idx].atlas_rect.xy, clamp_max);
|
||||||
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
|
shadow += textureProj(sampler2DShadow(shadow_atlas, shadow_sampler), vec4(suv, z_norm, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,17 +1226,41 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
//hard shadow
|
//hard shadow
|
||||||
splane.z = z_norm;
|
vec4 shadow_uv = vec4(splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy, z_norm, 1.0);
|
||||||
shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
|
|
||||||
|
shadow = sample_pcf_shadow(shadow_atlas, lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, shadow_uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
shadow_attenuation = mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
|
vec3 no_shadow = vec3(1.0);
|
||||||
|
|
||||||
|
if (lights.data[idx].projector_rect != vec4(0.0)) {
|
||||||
|
|
||||||
|
splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
|
||||||
|
splane /= splane.w;
|
||||||
|
|
||||||
|
vec2 proj_uv = splane.xy * lights.data[idx].projector_rect.zw;
|
||||||
|
|
||||||
|
//ensure we have proper mipmaps
|
||||||
|
vec4 splane_ddx = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddx, 1.0));
|
||||||
|
splane_ddx /= splane_ddx.w;
|
||||||
|
vec2 proj_uv_ddx = splane_ddx.xy * lights.data[idx].projector_rect.zw - proj_uv;
|
||||||
|
|
||||||
|
vec4 splane_ddy = (lights.data[idx].shadow_matrix * vec4(vertex + vertex_ddy, 1.0));
|
||||||
|
splane_ddy /= splane_ddy.w;
|
||||||
|
vec2 proj_uv_ddy = splane_ddy.xy * lights.data[idx].projector_rect.zw - proj_uv;
|
||||||
|
|
||||||
|
vec4 proj = textureGrad(sampler2D(decal_atlas_srgb, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), proj_uv + lights.data[idx].projector_rect.xy, proj_uv_ddx, proj_uv_ddy);
|
||||||
|
no_shadow = mix(no_shadow, proj.rgb, proj.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
shadow_attenuation = mix(shadow_color_enabled.rgb, no_shadow, shadow);
|
||||||
|
|
||||||
#ifdef LIGHT_TRANSMITTANCE_USED
|
#ifdef LIGHT_TRANSMITTANCE_USED
|
||||||
{
|
{
|
||||||
|
|
||||||
vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
|
splane = (lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * lights.data[idx].transmittance_bias, 1.0));
|
||||||
splane /= splane.w;
|
splane /= splane.w;
|
||||||
|
splane.xy = splane.xy * lights.data[idx].atlas_rect.zw + lights.data[idx].atlas_rect.xy;
|
||||||
|
|
||||||
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
|
float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r;
|
||||||
//reconstruct depth
|
//reconstruct depth
|
||||||
@@ -1691,6 +1781,9 @@ FRAGMENT_SHADER_CODE
|
|||||||
#ifndef MODE_RENDER_DEPTH
|
#ifndef MODE_RENDER_DEPTH
|
||||||
|
|
||||||
uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)));
|
uvec4 cluster_cell = texture(usampler3D(cluster_texture, material_samplers[SAMPLER_NEAREST_CLAMP]), vec3(screen_uv, (abs(vertex.z) - scene_data.z_near) / (scene_data.z_far - scene_data.z_near)));
|
||||||
|
//used for interpolating anything cluster related
|
||||||
|
vec3 vertex_ddx = dFdx(vertex);
|
||||||
|
vec3 vertex_ddy = dFdy(vertex);
|
||||||
|
|
||||||
{ // process decals
|
{ // process decals
|
||||||
|
|
||||||
@@ -1698,8 +1791,6 @@ FRAGMENT_SHADER_CODE
|
|||||||
uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK;
|
uint decal_pointer = cluster_cell.w & CLUSTER_POINTER_MASK;
|
||||||
|
|
||||||
//do outside for performance and avoiding arctifacts
|
//do outside for performance and avoiding arctifacts
|
||||||
vec3 vertex_ddx = dFdx(vertex);
|
|
||||||
vec3 vertex_ddy = dFdy(vertex);
|
|
||||||
|
|
||||||
for (uint i = 0; i < decal_count; i++) {
|
for (uint i = 0; i < decal_count; i++) {
|
||||||
|
|
||||||
@@ -2195,7 +2286,7 @@ FRAGMENT_SHADER_CODE
|
|||||||
continue; //not masked
|
continue; //not masked
|
||||||
}
|
}
|
||||||
|
|
||||||
light_process_omni(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity,
|
light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
#endif
|
#endif
|
||||||
@@ -2234,7 +2325,7 @@ FRAGMENT_SHADER_CODE
|
|||||||
continue; //not masked
|
continue; //not masked
|
||||||
}
|
}
|
||||||
|
|
||||||
light_process_spot(light_index, vertex, view, normal, albedo, roughness, metallic, specular, specular_blob_intensity,
|
light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, albedo, roughness, metallic, specular, specular_blob_intensity,
|
||||||
#ifdef LIGHT_BACKLIGHT_USED
|
#ifdef LIGHT_BACKLIGHT_USED
|
||||||
backlight,
|
backlight,
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ struct LightData { //this structure needs to be as packed as possible
|
|||||||
uint color_specular; //rgb color, a specular (8 bit unorm)
|
uint color_specular; //rgb color, a specular (8 bit unorm)
|
||||||
uint cone_attenuation_angle; // attenuation and angle, (16bit float)
|
uint cone_attenuation_angle; // attenuation and angle, (16bit float)
|
||||||
uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
|
uint shadow_color_enabled; //shadow rgb color, a>0.5 enabled (8bit unorm)
|
||||||
vec4 atlas_rect; // used for spot
|
vec4 atlas_rect; // rect in the shadow atlas
|
||||||
mat4 shadow_matrix;
|
mat4 shadow_matrix;
|
||||||
float shadow_bias;
|
float shadow_bias;
|
||||||
float shadow_normal_bias;
|
float shadow_normal_bias;
|
||||||
@@ -162,6 +162,7 @@ struct LightData { //this structure needs to be as packed as possible
|
|||||||
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
|
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
|
||||||
uint mask;
|
uint mask;
|
||||||
uint pad[2];
|
uint pad[2];
|
||||||
|
vec4 projector_rect; //projector rect in srgb decal atlas
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
|
layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
|
||||||
|
|||||||
Reference in New Issue
Block a user