Several fixes to GIProbes

This commit is contained in:
Juan Linietsky 2019-10-31 19:54:21 -03:00
parent 971ce680f2
commit da0457fa29
17 changed files with 234 additions and 18 deletions

View file

@ -87,6 +87,8 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
SavePNGFunc Image::save_png_func = NULL;
SaveEXRFunc Image::save_exr_func = NULL;
SavePNGBufferFunc Image::save_png_buffer_func = NULL;
void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) {
uint32_t ofs = (p_y * width + p_x) * p_pixelsize;
@ -901,6 +903,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS));
if (p_width == width && p_height == height)
return;
@ -1593,6 +1596,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH);
ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT);
ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS));
int mm = 0;
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
@ -1612,6 +1616,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH);
ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT);
ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS));
int mm;
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
@ -1910,6 +1915,14 @@ Error Image::save_png(const String &p_path) const {
return save_png_func(p_path, Ref<Image>((Image *)this));
}
PoolVector<uint8_t> Image::save_png_to_buffer() const {
if (save_png_buffer_func == NULL) {
return PoolVector<uint8_t>();
}
return save_png_buffer_func(Ref<Image>((Image *)this));
}
Error Image::save_exr(const String &p_path, bool p_grayscale) const {
if (save_exr_func == NULL)

View file

@ -47,6 +47,7 @@
class Image;
typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
typedef PoolVector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
@ -57,10 +58,12 @@ class Image : public Resource {
public:
static SavePNGFunc save_png_func;
static SaveEXRFunc save_exr_func;
static SavePNGBufferFunc save_png_buffer_func;
enum {
MAX_WIDTH = 16384, // force a limit somehow
MAX_HEIGHT = 16384 // force a limit somehow
MAX_WIDTH = (1 << 24), // force a limit somehow
MAX_HEIGHT = (1 << 24), // force a limit somehow
MAX_PIXELS = 268435456
};
enum Format {
@ -265,6 +268,7 @@ public:
Error load(const String &p_path);
Error save_png(const String &p_path) const;
PoolVector<uint8_t> save_png_to_buffer() const;
Error save_exr(const String &p_path, bool p_grayscale) const;
/**

View file

@ -183,7 +183,7 @@ bool Vector3i::operator==(const Vector3i &p_v) const {
bool Vector3i::operator!=(const Vector3i &p_v) const {
return (x != p_v.x || y == p_v.y || z == p_v.z);
return (x != p_v.x || y != p_v.y || z != p_v.z);
}
bool Vector3i::operator<(const Vector3i &p_v) const {

View file

@ -114,6 +114,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) {
ERR_FAIL_COND_V_MSG(check_error(png_img), ERR_FILE_CORRUPT, png_img.message);
ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
//print_line("png width: "+itos(png_img.width)+" height: "+itos(png_img.height));
p_image->create(png_img.width, png_img.height, 0, dest_format, buffer);
return OK;

View file

@ -71,6 +71,14 @@ Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img
return OK;
}
PoolVector<uint8_t> ResourceSaverPNG::save_image_to_buffer(const Ref<Image> &p_img) {
PoolVector<uint8_t> buffer;
Error err = PNGDriverCommon::image_to_png(p_img, buffer);
ERR_FAIL_COND_V_MSG(err, PoolVector<uint8_t>(), "Can't convert image to PNG.");
return buffer;
}
bool ResourceSaverPNG::recognize(const RES &p_resource) const {
return (p_resource.is_valid() && p_resource->is_class("ImageTexture"));
@ -86,4 +94,5 @@ void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<Str
ResourceSaverPNG::ResourceSaverPNG() {
Image::save_png_func = &save_image;
Image::save_png_buffer_func = &save_image_to_buffer;
};

View file

@ -37,6 +37,7 @@
class ResourceSaverPNG : public ResourceFormatSaver {
public:
static Error save_image(const String &p_path, const Ref<Image> &p_img);
static PoolVector<uint8_t> save_image_to_buffer(const Ref<Image> &p_img);
virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
virtual bool recognize(const RES &p_resource) const;

View file

@ -36,6 +36,8 @@
#include "drivers/vulkan/vulkan_context.h"
#include "thirdparty/spirv-reflect/spirv_reflect.h"
//#define FORCE_FULL_BARRIER
void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
if (!dependency_map.has(p_depends_on)) {
@ -1499,6 +1501,42 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas
vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL);
}
void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) {
//used for debug
_memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT |
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_TRANSFER_READ_BIT |
VK_ACCESS_TRANSFER_WRITE_BIT |
VK_ACCESS_HOST_READ_BIT |
VK_ACCESS_HOST_WRITE_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT |
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
VK_ACCESS_SHADER_READ_BIT |
VK_ACCESS_SHADER_WRITE_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
VK_ACCESS_TRANSFER_READ_BIT |
VK_ACCESS_TRANSFER_WRITE_BIT |
VK_ACCESS_HOST_READ_BIT |
VK_ACCESS_HOST_WRITE_BIT,
p_sync_with_draw);
}
void RenderingDeviceVulkan::_buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) {
VkBufferMemoryBarrier buffer_mem_barrier;
@ -4643,7 +4681,11 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
}
_buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw);
#ifdef FORCE_FULL_BARRIER
_full_barrier(p_sync_with_draw);
#else
_buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw);
#endif
return err;
}
@ -6038,7 +6080,12 @@ void RenderingDeviceVulkan::draw_list_end() {
// To ensure proper synchronization, we must make sure rendering is done before:
// * Some buffer is copied
// * Another render pass happens (since we may be done
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
#else
_memory_barrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, true);
#endif
}
/***********************/
@ -6298,7 +6345,11 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
}
void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
#else
_memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, true);
#endif
}
void RenderingDeviceVulkan::compute_list_end() {
@ -6330,8 +6381,11 @@ void RenderingDeviceVulkan::compute_list_end() {
memdelete(compute_list);
compute_list = NULL;
#ifdef FORCE_FULL_BARRIER
_full_barrier(true);
#else
_memory_barrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT, true);
#endif
}
#if 0

View file

@ -216,6 +216,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
Error _buffer_free(Buffer *p_buffer);
Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32);
void _full_barrier(bool p_sync_with_draw);
void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw);
void _buffer_memory_barrier(VkBuffer buffer, uint64_t p_from, uint64_t p_size, VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw);

View file

@ -33,6 +33,18 @@
void GIProbeEditorPlugin::_bake() {
if (gi_probe) {
if (gi_probe->get_probe_data().is_null()) {
String path = get_tree()->get_edited_scene_root()->get_filename();
if (path==String()) {
path="res://"+gi_probe->get_name()+"_data.res";
} else {
String ext = path.get_extension();
path = path.get_basename()+"."+gi_probe->get_name()+"_data.res";
}
probe_file->set_current_path(path);
probe_file->popup_centered_ratio();
return;
}
gi_probe->bake();
}
}
@ -51,13 +63,42 @@ bool GIProbeEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("GIProbe");
}
void GIProbeEditorPlugin::_notification(int p_what) {
if (p_what==NOTIFICATION_PROCESS) {
if (!gi_probe) {
return;
}
String text;
Vector3i size = gi_probe->get_estimated_cell_size();
text = itos(size.x)+", "+itos(size.y)+", "+itos(size.z);
int data_size = 4;
if (GLOBAL_GET("rendering/quality/gi_probes/anisotropic")) {
data_size+=4;
}
text += " - VRAM Size: " + String::num(size.x*size.y*size.z*data_size/(1024.0*1024.0),2)+" Mb.";
if (bake_info->get_text()==text) {
return;
}
bake_info->add_color_override("font_color", bake_info->get_color("success_color", "Editor"));
bake_info->set_text(text);
}
}
void GIProbeEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
bake->show();
bake_hb->show();
set_process(true);
} else {
bake->hide();
bake_hb->hide();
set_process(false);
}
}
@ -82,21 +123,46 @@ void GIProbeEditorPlugin::bake_func_end() {
tmp_progress = NULL;
}
void GIProbeEditorPlugin::_giprobe_save_path_and_bake(const String& p_path) {
probe_file->hide();
if (gi_probe) {
gi_probe->bake();
ERR_FAIL_COND( gi_probe->get_probe_data().is_null() );
ResourceSaver::save(p_path,gi_probe->get_probe_data(),ResourceSaver::FLAG_CHANGE_PATH);
}
}
void GIProbeEditorPlugin::_bind_methods() {
ClassDB::bind_method("_bake", &GIProbeEditorPlugin::_bake);
ClassDB::bind_method("_giprobe_save_path_and_bake", &GIProbeEditorPlugin::_giprobe_save_path_and_bake);
}
GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) {
editor = p_node;
bake_hb = memnew( HBoxContainer );
bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bake_hb->hide();
bake = memnew(ToolButton);
bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons"));
bake->set_text(TTR("Bake GI Probe"));
bake->hide();
bake->connect("pressed", this, "_bake");
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
bake_hb->add_child(bake);
bake_info = memnew( Label );
bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bake_info->set_clip_text(true);
bake_hb->add_child(bake_info);
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb);
gi_probe = NULL;
probe_file = memnew( EditorFileDialog );
probe_file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
probe_file->add_filter("*.res");
probe_file->connect("file_selected",this,"_giprobe_save_path_and_bake");
get_editor_interface()->get_base_control()->add_child(probe_file);
probe_file->set_title(TTR("Select path for GIProbe Data File"));
GIProbe::bake_begin_function = bake_func_begin;
GIProbe::bake_step_function = bake_func_step;

View file

@ -42,18 +42,25 @@ class GIProbeEditorPlugin : public EditorPlugin {
GIProbe *gi_probe;
HBoxContainer *bake_hb;
Label *bake_info;
ToolButton *bake;
EditorNode *editor;
EditorFileDialog *probe_file;
static EditorProgress *tmp_progress;
static void bake_func_begin(int p_steps);
static void bake_func_step(int p_step, const String &p_description);
static void bake_func_end();
void _bake();
void _giprobe_save_path_and_bake(const String& p_path);
protected:
static void _bind_methods();
void _notification(int p_what);
public:
virtual String get_name() const { return "GIProbe"; }

View file

@ -41,7 +41,7 @@ void GIProbeData::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("octree_size"));
ERR_FAIL_COND(!p_data.has("octree_cells"));
ERR_FAIL_COND(!p_data.has("octree_data"));
ERR_FAIL_COND(!p_data.has("octree_df"));
ERR_FAIL_COND(!p_data.has("octree_df") && !p_data.has("octree_df_png"));
ERR_FAIL_COND(!p_data.has("level_counts"));
ERR_FAIL_COND(!p_data.has("to_cell_xform"));
@ -49,7 +49,19 @@ void GIProbeData::_set_data(const Dictionary &p_data) {
Vector3 octree_size = p_data["octree_size"];
PoolVector<uint8_t> octree_cells = p_data["octree_cells"];
PoolVector<uint8_t> octree_data = p_data["octree_data"];
PoolVector<uint8_t> octree_df = p_data["octree_df"];
PoolVector<uint8_t> octree_df;
if (p_data.has("octree_df")) {
octree_df = p_data["octree_df"];
} else if (p_data.has("octree_df_png")) {
PoolVector<uint8_t> octree_df_png = p_data["octree_df_png"];
Ref<Image> img;
img.instance();
Error err = img->load_png_from_buffer(octree_df_png);
ERR_FAIL_COND(err != OK);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_L8);
octree_df = img->get_data();
}
PoolVector<int> octree_levels = p_data["level_counts"];
Transform to_cell_xform = p_data["to_cell_xform"];
@ -59,10 +71,21 @@ void GIProbeData::_set_data(const Dictionary &p_data) {
Dictionary GIProbeData::_get_data() const {
Dictionary d;
d["bounds"] = get_bounds();
d["octree_size"] = get_octree_size();
Vector3i otsize = get_octree_size();
d["octree_size"] = Vector3(otsize);
d["octree_cells"] = get_octree_cells();
d["octree_data"] = get_data_cells();
d["octree_df"] = get_distance_field();
if (otsize != Vector3i()) {
Ref<Image> img;
img.instance();
img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field());
PoolVector<uint8_t> df_png = img->save_png_to_buffer();
ERR_FAIL_COND_V(df_png.size() == 0, Dictionary());
d["octree_df_png"] = df_png;
} else {
d["octree_df"] = PoolVector<uint8_t>();
}
d["level_counts"] = get_level_counts();
d["to_cell_xform"] = get_to_cell_xform();
return d;
@ -384,6 +407,32 @@ GIProbe::BakeBeginFunc GIProbe::bake_begin_function = NULL;
GIProbe::BakeStepFunc GIProbe::bake_step_function = NULL;
GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL;
Vector3i GIProbe::get_estimated_cell_size() const {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
int cell_subdiv = subdiv_value[subdiv];
int axis_cell_size[3];
AABB bounds = AABB(-extents, extents * 2.0);
int longest_axis = bounds.get_longest_axis_index();
axis_cell_size[longest_axis] = 1 << cell_subdiv;
for (int i = 0; i < 3; i++) {
if (i == longest_axis)
continue;
axis_cell_size[i] = axis_cell_size[longest_axis];
float axis_size = bounds.size[longest_axis];
//shrink until fit subdiv
while (axis_size / 2.0 >= bounds.size[i]) {
axis_size /= 2.0;
axis_cell_size[i] >>= 1;
}
}
return Vector3i(axis_cell_size[0],axis_cell_size[1],axis_cell_size[2]);
}
void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
@ -458,6 +507,8 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) {
if (bake_end_function) {
bake_end_function();
}
_change_notify(); //bake property may have changed
}
void GIProbe::_debug_bake() {

View file

@ -159,6 +159,7 @@ public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
Vector3i get_estimated_cell_size() const;
void bake(Node *p_from_node = NULL, bool p_create_visual_debug = false);

View file

@ -409,6 +409,7 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_GROUP("Skeleton", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
}

View file

@ -2363,11 +2363,14 @@ void RasterizerSceneForwardRD::_setup_render_pass_uniform_set(RID p_depth_buffer
RD::Uniform u;
u.binding = 6;
u.type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (p_shadow_atlas.is_valid()) {
u.ids.push_back(shadow_atlas_get_texture(p_shadow_atlas));
} else {
u.ids.push_back(storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE));
texture = shadow_atlas_get_texture(p_shadow_atlas);
}
if (!texture.is_valid()) {
texture = storage->texture_rd_get_default(RasterizerStorageRD::DEFAULT_RD_TEXTURE_WHITE);
}
u.ids.push_back(texture);
uniforms.push_back(u);
}

View file

@ -2334,6 +2334,7 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas
}
} else {
//render shadow
_render_shadow(render_fb, p_cull_result, p_cull_count, light_projection, light_transform, zfar, bias, normal_bias, using_dual_paraboloid, using_dual_paraboloid_flip);
//copy to atlas

View file

@ -266,7 +266,7 @@ VERTEX_SHADER_CODE
#else
float z_ofs = scene_data.z_offset;
z_ofs += (1.0 - abs(normal_interp.z)) * scene_data.z_slope_scale;
z_ofs += max(0.0,1.0 - abs(normalize(normal_interp).z)) * scene_data.z_slope_scale;
vertex_interp.z -= z_ofs;
#endif

View file

@ -851,7 +851,7 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK));
//ERR_FAIL_COND(((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK));
switch (p_flags) {
@ -2526,6 +2526,9 @@ void VisualServerScene::render_probes() {
for (List<InstanceGIProbeData::PairInfo>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) {
if (instance_cull_count < MAX_INSTANCE_CULL) {
Instance *ins = E->get().geometry;
if (!ins->visible) {
continue;
}
InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data;
if (geom->gi_probes_dirty) {