diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-09-14 00:37:42 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 12:01:22 +0100 |
commit | 6deffa62fbd1e91873afa663630b788b9ffabee3 (patch) | |
tree | e77c1a67c8b8ddb64429280131502f64c8cd8e8c /servers | |
parent | 9d7b7f931b6924399903e4954a0c32d59c15d4c3 (diff) |
Several fixes to 3D rendering, and multimesh implementation.
Diffstat (limited to 'servers')
18 files changed, 952 insertions, 95 deletions
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index fe682618a4..f5ce604b04 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -358,7 +358,8 @@ public: virtual RID multimesh_create() = 0; - virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data = VS::MULTIMESH_CUSTOM_DATA_NONE) = 0; + virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; + virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; @@ -374,7 +375,8 @@ public: virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; - virtual void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) = 0; + virtual void multimesh_set_buffer(RID p_multimesh, const PoolVector<float> &p_buffer) = 0; + virtual PoolVector<float> multimesh_get_buffer(RID p_multimesh) const = 0; virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; diff --git a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp index 1dc0503027..1a94f11334 100644 --- a/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_canvas_rd.cpp @@ -2107,7 +2107,7 @@ void RasterizerCanvasRD::MaterialData::update_parameters(const Map<StringName, V if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw()); + update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), false); } if (shader_data->ubo_size == 0 && !shader_data->uses_material_samplers) { diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp index be5b8f1845..bf4d7e4fc8 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp @@ -465,7 +465,7 @@ void RasterizerSceneForwardRD::MaterialData::update_parameters(const Map<StringN if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw()); + update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); } if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { @@ -607,6 +607,26 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, id.flags = 0; id.mask = e->instance->layer_mask; + if (e->instance->base_type == VS::INSTANCE_MULTIMESH) { + id.flags |= INSTANCE_DATA_FLAG_MULTIMESH; + uint32_t stride; + if (storage->multimesh_get_transform_format(e->instance->base) == VS::MULTIMESH_TRANSFORM_2D) { + id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D; + stride = 2; + } else { + stride = 3; + } + if (storage->multimesh_uses_colors(e->instance->base)) { + id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR; + stride += 1; + } + if (storage->multimesh_uses_custom_data(e->instance->base)) { + id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA; + stride += 1; + } + + id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT); + } //forward uint32_t reflection_count = 0; @@ -632,7 +652,7 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, } if (reflection_count < 8) { - id.omni_light_indices[omni_count] = reflection_probe_instance_get_render_index(rpi_ptrs[j]); + id.reflection_probe_indices[reflection_count] = reflection_probe_instance_get_render_index(rpi_ptrs[j]); reflection_count++; } } @@ -661,7 +681,7 @@ void RasterizerSceneForwardRD::_fill_instances(RenderList::Element **p_elements, } } else { if (spot_count < 8) { - id.omni_light_indices[spot_count] = light_instance_get_index(light_ptrs[j]); + id.spot_light_indices[spot_count] = light_instance_get_index(light_ptrs[j]); spot_count++; } } @@ -686,6 +706,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l //global scope bindings RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, 1); MaterialData *prev_material = nullptr; // ShaderData *prev_shader = nullptr; @@ -693,6 +714,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l RID prev_vertex_array_rd; RID prev_index_array_rd; RID prev_pipeline_rd; + RID prev_xforms_uniform_set; PushConstant push_constant; zeromem(&push_constant, sizeof(PushConstant)); @@ -703,6 +725,7 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l MaterialData *material = e->material; ShaderData *shader = material->shader_data; + RID xforms_uniform_set; //find cull variant ShaderData::CullVariant cull_variant; @@ -725,7 +748,12 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l primitive = storage->mesh_surface_get_primitive(e->instance->base, e->surface_index); } break; case VS::INSTANCE_MULTIMESH: { - ERR_CONTINUE(true); //should be a bug + RID mesh = storage->multimesh_get_mesh(e->instance->base); + ERR_CONTINUE(!mesh.is_valid()); //should be a bug + primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index); + + xforms_uniform_set = storage->multimesh_get_3d_uniform_set(e->instance->base, default_shader_rd, 1); + } break; case VS::INSTANCE_IMMEDIATE: { ERR_CONTINUE(true); //should be a bug @@ -790,7 +818,9 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l storage->mesh_surface_get_arrays_and_format(e->instance->base, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); } break; case VS::INSTANCE_MULTIMESH: { - ERR_CONTINUE(true); //should be a bug + RID mesh = storage->multimesh_get_mesh(e->instance->base); + ERR_CONTINUE(!mesh.is_valid()); //should be a bug + storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format); } break; case VS::INSTANCE_IMMEDIATE: { ERR_CONTINUE(true); //should be a bug @@ -824,6 +854,11 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l prev_pipeline_rd = pipeline_rd; } + if (xforms_uniform_set.is_valid() && prev_xforms_uniform_set != xforms_uniform_set) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material->uniform_set, 1); + prev_xforms_uniform_set = xforms_uniform_set; + } + if (material != prev_material) { //update uniform set if (material->uniform_set.is_valid()) { @@ -841,7 +876,8 @@ void RasterizerSceneForwardRD::_render_list(RenderingDevice::DrawListID p_draw_l RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid()); } break; case VS::INSTANCE_MULTIMESH: { - + uint32_t instances = storage->multimesh_get_instances_to_draw(e->instance->base); + RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances); } break; case VS::INSTANCE_IMMEDIATE: { @@ -1223,28 +1259,35 @@ void RasterizerSceneForwardRD::_fill_render_list(InstanceBase **p_cull_result, i //mesh->last_pass=frame; } break; -#if 0 + case VS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(inst->base); - ERR_CONTINUE(!multi_mesh); + if (storage->multimesh_get_instances_to_draw(inst->base) == 0) { + //not visible, 0 instances + continue; + } - if (multi_mesh->size == 0 || multi_mesh->visible_instances == 0) + RID mesh = storage->multimesh_get_mesh(inst->base); + if (!mesh.is_valid()) { continue; + } - RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(multi_mesh->mesh); - if (!mesh) - continue; //mesh not assigned + const RID *materials = NULL; + uint32_t surface_count; - int ssize = mesh->surfaces.size(); + materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count); + if (!materials) { + continue; //nothing to do + } - for (int j = 0; j < ssize; j++) { + for (uint32_t j = 0; j < surface_count; j++) { - RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; - _add_geometry(s, inst, multi_mesh, -1, p_depth_pass, p_shadow_pass); + uint32_t surface_index = storage->mesh_surface_get_multimesh_render_pass_index(inst->base, j, render_pass, &geometry_index); + _add_geometry(inst, j, materials[j], p_pass_mode, surface_index); } } break; +#if 0 case VS::INSTANCE_IMMEDIATE: { RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); @@ -2589,7 +2632,7 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag actions.renames["POINT_COORD"] = "gl_PointCoord"; actions.renames["INSTANCE_CUSTOM"] = "instance_custom"; actions.renames["SCREEN_UV"] = "screen_uv"; - actions.renames["SCREEN_TEXTURE"] = "screen_texture"; + actions.renames["SCREEN_TEXTURE"] = "color_buffer"; actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; actions.renames["NORMAL_TEXTURE"] = "normal_buffer"; actions.renames["DEPTH"] = "gl_FragDepth"; @@ -2698,6 +2741,17 @@ RasterizerSceneForwardRD::RasterizerSceneForwardRD(RasterizerStorageRD *p_storag } { + default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256); + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.ids.push_back(default_vec4_xform_buffer); + u.binding = 0; + uniforms.push_back(u); + + default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, 1); + } + { RD::SamplerState sampler; sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h index c8166c3f88..912d62b1d8 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h @@ -247,6 +247,15 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { float shadow_matrices[4][16]; }; + enum { + INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, + INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, + INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT = 16, + INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_MASK = 0x7, + }; + struct InstanceData { float transform[16]; float normal_transform[16]; @@ -471,6 +480,9 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD { RID default_material; RID default_shader_rd; + RID default_vec4_xform_buffer; + RID default_vec4_xform_uniform_set; + enum PassMode { PASS_MODE_COLOR, PASS_MODE_COLOR_SPECULAR, diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp index 63b65a8a15..7bb615eda9 100644 --- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp @@ -428,6 +428,7 @@ VS::EnvironmentReflectionSource RasterizerSceneRD::environment_get_reflection_so void RasterizerSceneRD::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { Environent *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + env->exposure = p_exposure; env->tone_mapper = p_tone_mapper; env->auto_exposure = p_auto_exposure; env->white = p_white; @@ -1414,7 +1415,7 @@ bool RasterizerSceneRD::free(RID p_rid) { reflection_atlas_owner.free(p_rid); } else if (reflection_probe_instance_owner.owns(p_rid)) { //not much to delete, just free it - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid); + //ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid); reflection_probe_release_atlas_index(p_rid); reflection_probe_instance_owner.free(p_rid); } else if (sky_owner.owns(p_rid)) { diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index e80f5f54b9..7cf93a82e0 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -199,7 +199,7 @@ Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_ima case Image::FORMAT_DXT1: { if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK; - r_format.format_srgb = RD::DATA_FORMAT_BC1_RGBA_SRGB_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_BC1_RGB_SRGB_BLOCK; } else { //not supported, reconvert r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; @@ -788,16 +788,31 @@ void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, } void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + tex->path = p_path; } String RasterizerStorageRD::texture_get_path(RID p_texture) const { return String(); } void RasterizerStorageRD::texture_set_detect_3d_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + tex->detect_3d_callback_ud = p_userdata; + tex->detect_3d_callback = p_callback; } void RasterizerStorageRD::texture_set_detect_normal_callback(RID p_texture, VS::TextureDetectCallback p_callback, void *p_userdata) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + tex->detect_normal_callback_ud = p_userdata; + tex->detect_normal_callback = p_callback; } void RasterizerStorageRD::texture_set_detect_roughness_callback(RID p_texture, VS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + tex->detect_roughness_callback_ud = p_userdata; + tex->detect_roughness_callback = p_callback; } void RasterizerStorageRD::texture_debug_usage(List<VS::TextureInfo> *r_info) { } @@ -1611,9 +1626,14 @@ void RasterizerStorageRD::MaterialData::update_uniform_buffer(const Map<StringNa } } -void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures) { +void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { RasterizerStorageRD *singleton = (RasterizerStorageRD *)RasterizerStorage::base_singleton; +#ifdef TOOLS_ENABLED + Texture *roughness_detect_texture = nullptr; + VS::TextureDetectRoughnessChannel roughness_channel; + Texture *normal_detect_texture = nullptr; +#endif for (int i = 0; i < p_texture_uniforms.size(); i++) { @@ -1653,8 +1673,31 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va } break; } } else { - bool srgb = p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO; - rd_texture = singleton->texture_get_rd_texture(texture, srgb); + bool srgb = p_use_linear_color && p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO; + + Texture *tex = singleton->texture_owner.getornull(texture); + + if (tex) { + rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; +#ifdef TOOLS_ENABLED + if (tex->detect_3d_callback && p_use_linear_color) { + tex->detect_3d_callback(tex->detect_3d_callback_ud); + } + if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { + if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) { + normal_detect_texture = tex; + } + tex->detect_normal_callback(tex->detect_normal_callback_ud); + } + if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) { + //find the normal texture + roughness_detect_texture = tex; + roughness_channel = VS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R); + } + +#endif + } + if (rd_texture.is_null()) { //wtf rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); @@ -1663,6 +1706,11 @@ void RasterizerStorageRD::MaterialData::update_textures(const Map<StringName, Va p_textures[i] = rd_texture; } +#ifdef TOOLS_ENABLED + if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); + } +#endif } void RasterizerStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { @@ -2087,6 +2135,568 @@ void RasterizerStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Su v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers); } +////////////////// MULTIMESH + +RID RasterizerStorageRD::multimesh_create() { + + return multimesh_owner.make_rid(MultiMesh()); +} + +void RasterizerStorageRD::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + + if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) { + return; + } + + if (multimesh->buffer.is_valid()) { + RD::get_singleton()->free(multimesh->buffer); + multimesh->buffer = RID(); + multimesh->uniform_set_3d = RID(); //cleared by dependency + } + + if (multimesh->data_cache_dirty_regions) { + memdelete_arr(multimesh->data_cache_dirty_regions); + multimesh->data_cache_dirty_regions = nullptr; + multimesh->data_cache_used_dirty_regions = 0; + } + + multimesh->instances = p_instances; + multimesh->xform_format = p_transform_format; + multimesh->uses_colors = p_use_colors; + multimesh->color_offset_cache = p_transform_format == VS::MULTIMESH_TRANSFORM_2D ? 8 : 12; + multimesh->uses_custom_data = p_use_custom_data; + multimesh->custom_data_offset_cache = multimesh->color_offset_cache + (p_use_colors ? 4 : 0); + multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0); + multimesh->buffer_set = false; + + print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == VS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances)); + multimesh->data_cache = PoolVector<float>(); + multimesh->aabb = AABB(); + multimesh->aabb_dirty = false; + multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances); + + if (multimesh->instances) { + + multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache); + } +} + +int RasterizerStorageRD::multimesh_get_instance_count(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, 0); + return multimesh->instances; +} + +void RasterizerStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + if (multimesh->mesh == p_mesh) { + return; + } + multimesh->mesh = p_mesh; + + if (multimesh->instances == 0) { + return; + } + + if (multimesh->data_cache.size()) { + //we have a data cache, just mark it dirt + _multimesh_mark_all_dirty(multimesh, false, true); + } else if (multimesh->instances) { + //need to re-create AABB unfortunately, calling this has a penalty + { + PoolVector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); + PoolVector<uint8_t>::Read r = buffer.read(); + const float *data = (const float *)r.ptr(); + _multimesh_re_create_aabb(multimesh, data, multimesh->instances); + } + } + + multimesh->instance_dependency.instance_notify_changed(true, true); +} + +#define MULTIMESH_DIRTY_REGION_SIZE 512 + +void RasterizerStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { + if (multimesh->data_cache.size() > 0) { + return; //already local + } + ERR_FAIL_COND(multimesh->data_cache.size() > 0); + // this means that the user wants to load/save individual elements, + // for this, the data must reside on CPU, so just copy it there. + multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache); + { + PoolVector<float>::Write w = multimesh->data_cache.write(); + + if (multimesh->buffer_set) { + PoolVector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); + { + + PoolVector<uint8_t>::Read r = buffer.read(); + copymem(w.ptr(), r.ptr(), buffer.size()); + } + } else { + zeromem(w.ptr(), multimesh->instances * multimesh->stride_cache * sizeof(float)); + } + } + uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count); + for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { + multimesh->data_cache_dirty_regions[i] = 0; + } + multimesh->data_cache_used_dirty_regions = 0; +} + +void RasterizerStorageRD::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) { + + uint32_t region_index = p_index / MULTIMESH_DIRTY_REGION_SIZE; +#ifdef DEBUG_ENABLED + uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + ERR_FAIL_INDEX(region_index, data_cache_dirty_region_count); //bug +#endif + if (!multimesh->data_cache_dirty_regions[region_index]) { + multimesh->data_cache_dirty_regions[p_index] = true; + multimesh->data_cache_used_dirty_regions++; + } + + if (p_aabb) { + multimesh->aabb_dirty = true; + } + + if (!multimesh->dirty) { + multimesh->dirty_list = multimesh_dirty_list; + multimesh_dirty_list = multimesh; + multimesh->dirty = true; + } +} + +void RasterizerStorageRD::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb) { + if (p_data) { + uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + + for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { + if (!multimesh->data_cache_dirty_regions[i]) { + multimesh->data_cache_dirty_regions[i] = true; + multimesh->data_cache_used_dirty_regions++; + } + } + } + + if (p_aabb) { + multimesh->aabb_dirty = true; + } + + if (!multimesh->dirty) { + multimesh->dirty_list = multimesh_dirty_list; + multimesh_dirty_list = multimesh; + multimesh->dirty = true; + } +} + +void RasterizerStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { + + ERR_FAIL_COND(multimesh->mesh.is_null()); + AABB aabb; + AABB mesh_aabb = mesh_get_aabb(multimesh->mesh); + for (int i = 0; i < p_instances; i++) { + const float *data = p_data + multimesh->stride_cache * i; + Transform t; + + if (multimesh->xform_format == VS::MULTIMESH_TRANSFORM_3D) { + t.basis[0].x = data[0]; + t.basis[0].y = data[1]; + t.basis[0].z = data[2]; + t.basis[1].x = data[3]; + t.basis[1].y = data[4]; + t.basis[1].z = data[5]; + t.basis[2].x = data[6]; + t.basis[2].y = data[7]; + t.basis[2].z = data[8]; + t.origin.x = data[9]; + t.origin.y = data[10]; + t.origin.z = data[11]; + + } else { + + t.basis.elements[0].x = data[0]; + t.basis.elements[1].x = data[1]; + t.origin.x = data[3]; + + t.basis.elements[0].y = data[4]; + t.basis.elements[1].y = data[5]; + t.origin.y = data[7]; + } + + if (i == 0) { + aabb = t.xform(mesh_aabb); + } else { + aabb.merge_with(t.xform(mesh_aabb)); + } + } + + multimesh->aabb = aabb; +} + +void RasterizerStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index, multimesh->instances); + ERR_FAIL_COND(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_3D); + + _multimesh_make_local(multimesh); + + { + PoolVector<float>::Write w = multimesh->data_cache.write(); + + float *dataptr = w.ptr() + p_index * multimesh->stride_cache; + + dataptr[0] = p_transform.basis[0].x; + dataptr[1] = p_transform.basis[0].y; + dataptr[2] = p_transform.basis[0].z; + dataptr[3] = p_transform.basis[1].x; + dataptr[4] = p_transform.basis[1].y; + dataptr[5] = p_transform.basis[1].z; + dataptr[6] = p_transform.basis[2].x; + dataptr[7] = p_transform.basis[2].y; + dataptr[8] = p_transform.basis[2].z; + dataptr[9] = p_transform.origin.x; + dataptr[10] = p_transform.origin.y; + dataptr[11] = p_transform.origin.z; + } + + _multimesh_mark_dirty(multimesh, p_index, true); +} + +void RasterizerStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index, multimesh->instances); + ERR_FAIL_COND(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_2D); + + _multimesh_make_local(multimesh); + + { + PoolVector<float>::Write w = multimesh->data_cache.write(); + + float *dataptr = w.ptr() + p_index * multimesh->stride_cache; + + dataptr[0] = p_transform.elements[0].x; + dataptr[1] = p_transform.elements[1].x; + dataptr[2] = 0; + dataptr[3] = p_transform.elements[2].x; + dataptr[4] = p_transform.elements[0].y; + dataptr[5] = p_transform.elements[1].y; + dataptr[6] = 0; + dataptr[7] = p_transform.elements[2].y; + } + + _multimesh_mark_dirty(multimesh, p_index, true); +} +void RasterizerStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index, multimesh->instances); + ERR_FAIL_INDEX(p_index, !multimesh->uses_colors); + + _multimesh_make_local(multimesh); + + { + PoolVector<float>::Write w = multimesh->data_cache.write(); + + float *dataptr = w.ptr() + p_index * multimesh->stride_cache + multimesh->color_offset_cache; + + dataptr[0] = p_color.r; + dataptr[1] = p_color.g; + dataptr[2] = p_color.b; + dataptr[3] = p_color.a; + } + + _multimesh_mark_dirty(multimesh, p_index, false); +} +void RasterizerStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_INDEX(p_index, multimesh->instances); + ERR_FAIL_INDEX(p_index, !multimesh->uses_custom_data); + + _multimesh_make_local(multimesh); + + { + PoolVector<float>::Write w = multimesh->data_cache.write(); + + float *dataptr = w.ptr() + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache; + + dataptr[0] = p_color.r; + dataptr[1] = p_color.g; + dataptr[2] = p_color.b; + dataptr[3] = p_color.a; + } + + _multimesh_mark_dirty(multimesh, p_index, false); +} + +RID RasterizerStorageRD::multimesh_get_mesh(RID p_multimesh) const { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, RID()); + + return multimesh->mesh; +} + +Transform RasterizerStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, Transform()); + ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform()); + ERR_FAIL_COND_V(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_3D, Transform()); + + _multimesh_make_local(multimesh); + + Transform t; + { + PoolVector<float>::Read r = multimesh->data_cache.read(); + + const float *dataptr = r.ptr() + p_index * multimesh->stride_cache; + + t.basis[0].x = dataptr[0]; + t.basis[0].y = dataptr[1]; + t.basis[0].z = dataptr[2]; + t.basis[1].x = dataptr[3]; + t.basis[1].y = dataptr[4]; + t.basis[1].z = dataptr[5]; + t.basis[2].x = dataptr[6]; + t.basis[2].y = dataptr[7]; + t.basis[2].z = dataptr[8]; + t.origin.x = dataptr[9]; + t.origin.y = dataptr[10]; + t.origin.z = dataptr[11]; + } + + return t; +} +Transform2D RasterizerStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, Transform2D()); + ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D()); + ERR_FAIL_COND_V(multimesh->xform_format != VS::MULTIMESH_TRANSFORM_2D, Transform2D()); + + _multimesh_make_local(multimesh); + + Transform2D t; + { + PoolVector<float>::Read r = multimesh->data_cache.read(); + + const float *dataptr = r.ptr() + p_index * multimesh->stride_cache; + + t.elements[0].x = dataptr[0]; + t.elements[1].x = dataptr[1]; + t.elements[2].x = dataptr[3]; + + t.elements[0].y = dataptr[4]; + t.elements[1].y = dataptr[5]; + t.elements[2].y = dataptr[7]; + } + + return t; +} +Color RasterizerStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, Color()); + ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); + ERR_FAIL_INDEX_V(p_index, !multimesh->uses_colors, Color()); + + _multimesh_make_local(multimesh); + + Color c; + { + PoolVector<float>::Read r = multimesh->data_cache.read(); + + const float *dataptr = r.ptr() + p_index * multimesh->stride_cache + multimesh->color_offset_cache; + + c.r = dataptr[0]; + c.g = dataptr[1]; + c.b = dataptr[2]; + c.a = dataptr[3]; + } + + return c; +} +Color RasterizerStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, Color()); + ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); + ERR_FAIL_INDEX_V(p_index, !multimesh->uses_custom_data, Color()); + + _multimesh_make_local(multimesh); + + Color c; + { + PoolVector<float>::Read r = multimesh->data_cache.read(); + + const float *dataptr = r.ptr() + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache; + + c.r = dataptr[0]; + c.g = dataptr[1]; + c.b = dataptr[2]; + c.a = dataptr[3]; + } + + return c; +} + +void RasterizerStorageRD::multimesh_set_buffer(RID p_multimesh, const PoolVector<float> &p_buffer) { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); + + { + PoolVector<float>::Read r = p_buffer.read(); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r.ptr(), false); + multimesh->buffer_set = true; + } + + if (multimesh->data_cache.size()) { + //if we have a data cache, just update it + multimesh->data_cache = p_buffer; + { + //clear dirty since nothing will be dirty anymore + uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { + multimesh->data_cache_dirty_regions[i] = false; + } + multimesh->data_cache_used_dirty_regions = 0; + } + + _multimesh_mark_all_dirty(multimesh, false, true); //update AABB + } else if (multimesh->mesh.is_valid()) { + //if we have a mesh set, we need to re-generate the AABB from the new data + PoolVector<float>::Read r = p_buffer.read(); + const float *data = r.ptr(); + _multimesh_re_create_aabb(multimesh, data, multimesh->instances); + multimesh->instance_dependency.instance_notify_changed(true, false); + } +} + +PoolVector<float> RasterizerStorageRD::multimesh_get_buffer(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, PoolVector<float>()); + if (multimesh->buffer.is_null()) { + return PoolVector<float>(); + } else if (multimesh->data_cache.size()) { + return multimesh->data_cache; + } else { + //get from memory + + PoolVector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer); + PoolVector<float> ret; + ret.resize(multimesh->instances); + { + PoolVector<float>::Write w = multimesh->data_cache.write(); + PoolVector<uint8_t>::Read r = buffer.read(); + copymem(w.ptr(), r.ptr(), buffer.size()); + } + + return ret; + } +} + +void RasterizerStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { + + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND(!multimesh); + ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances); + if (multimesh->visible_instances == p_visible) { + return; + } + + if (multimesh->data_cache.size()) { + //there is a data cache.. + _multimesh_mark_all_dirty(multimesh, false, true); + } + + multimesh->visible_instances = p_visible; +} +int RasterizerStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, 0); + return multimesh->visible_instances; +} + +AABB RasterizerStorageRD::multimesh_get_aabb(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + ERR_FAIL_COND_V(!multimesh, AABB()); + if (multimesh->aabb_dirty) { + const_cast<RasterizerStorageRD *>(this)->_update_dirty_multimeshes(); + } + return multimesh->aabb; +} + +void RasterizerStorageRD::_update_dirty_multimeshes() { + + while (multimesh_dirty_list) { + + MultiMesh *multimesh = multimesh_dirty_list; + + if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists + PoolVector<float>::Read r = multimesh->data_cache.read(); + const float *data = r.ptr(); + + uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances; + + if (multimesh->data_cache_used_dirty_regions) { + + uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t visible_region_count = (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + + uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float); + + if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) { + //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much + RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache), data, false); + } else { + //not that many regions? update them all + for (uint32_t i = 0; i < visible_region_count; i++) { + if (multimesh->data_cache_dirty_regions[i]) { + uint64_t offset = i * region_size; + uint64_t size = multimesh->stride_cache * multimesh->instances; + RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size], false); + } + } + } + + for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) { + multimesh->data_cache_dirty_regions[i] = false; + } + + multimesh->data_cache_used_dirty_regions = 0; + } + + if (multimesh->aabb_dirty) { + //aabb is dirty.. + _multimesh_re_create_aabb(multimesh, data, visible_instances); + multimesh->aabb_dirty = false; + multimesh->instance_dependency.instance_notify_changed(true, false); + } + } + + multimesh_dirty_list = multimesh->dirty_list; + + multimesh->dirty_list = nullptr; + multimesh->dirty = false; + } + + multimesh_dirty_list = nullptr; +} + /* LIGHT */ RID RasterizerStorageRD::light_create(VS::LightType p_type) { @@ -2889,6 +3499,13 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In if (mesh_owner.owns(p_base)) { Mesh *mesh = mesh_owner.getornull(p_base); p_instance->update_dependency(&mesh->instance_dependency); + } else if (multimesh_owner.owns(p_base)) { + + MultiMesh *multimesh = multimesh_owner.getornull(p_base); + p_instance->update_dependency(&multimesh->instance_dependency); + if (multimesh->mesh.is_valid()) { + base_update_dependency(multimesh->mesh, p_instance); + } } else if (reflection_probe_owner.owns(p_base)) { ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); p_instance->update_dependency(&rp->instance_dependency); @@ -2903,6 +3520,9 @@ VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; } + if (multimesh_owner.owns(p_rid)) { + return VS::INSTANCE_MULTIMESH; + } if (reflection_probe_owner.owns(p_rid)) { return VS::INSTANCE_REFLECTION_PROBE; } @@ -2914,8 +3534,29 @@ VS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const { } void RasterizerStorageRD::update_dirty_resources() { _update_queued_materials(); + _update_dirty_multimeshes(); } +bool RasterizerStorageRD::has_os_feature(const String &p_feature) const { + + if (p_feature == "s3tc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) { + return true; + } + + if (p_feature == "bptc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) { + return true; + } + + if ((p_feature == "etc" || p_feature == "etc2") && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) { + return true; + } + + if (p_feature == "pvrtc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, RD::TEXTURE_USAGE_SAMPLING_BIT)) { + return true; + } + + return false; +} bool RasterizerStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { @@ -2972,6 +3613,12 @@ bool RasterizerStorageRD::free(RID p_rid) { Mesh *mesh = mesh_owner.getornull(p_rid); mesh->instance_dependency.instance_notify_deleted(p_rid); mesh_owner.free(p_rid); + } else if (multimesh_owner.owns(p_rid)) { + _update_dirty_multimeshes(); + multimesh_allocate(p_rid, 0, VS::MULTIMESH_TRANSFORM_2D); + MultiMesh *multimesh = multimesh_owner.getornull(p_rid); + multimesh->instance_dependency.instance_notify_deleted(p_rid); + multimesh_owner.free(p_rid); } else if (reflection_probe_owner.owns(p_rid)) { ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); reflection_probe->instance_dependency.instance_notify_deleted(p_rid); diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 3cfd5601e8..ef22a6689b 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -62,7 +62,7 @@ public: struct MaterialData { void update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color); - void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures); + void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color); virtual void set_render_priority(int p_priority) = 0; virtual void set_next_pass(RID p_pass) = 0; @@ -135,6 +135,15 @@ private: RID proxy_to; Vector<RID> proxies; + + VS::TextureDetectCallback detect_3d_callback = nullptr; + void *detect_3d_callback_ud = nullptr; + + VS::TextureDetectCallback detect_normal_callback = nullptr; + void *detect_normal_callback_ud = nullptr; + + VS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr; + void *detect_roughness_callback_ud = nullptr; }; struct TextureToRDFormat { @@ -281,6 +290,43 @@ private: RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX]; + /* MultiMesh */ + struct MultiMesh { + RID mesh; + int instances = 0; + VS::MultimeshTransformFormat xform_format = VS::MULTIMESH_TRANSFORM_3D; + bool uses_colors = false; + bool uses_custom_data = false; + int visible_instances = -1; + AABB aabb; + bool aabb_dirty = false; + bool buffer_set = false; + uint32_t stride_cache = 0; + uint32_t color_offset_cache = 0; + uint32_t custom_data_offset_cache = 0; + + PoolVector<float> data_cache; //used if individual setting is used + bool *data_cache_dirty_regions = nullptr; + uint32_t data_cache_used_dirty_regions = 0; + + RID buffer; //storage buffer + RID uniform_set_3d; + + bool dirty = false; + MultiMesh *dirty_list = nullptr; + + RasterizerScene::InstanceDependency instance_dependency; + }; + + mutable RID_Owner<MultiMesh> multimesh_owner; + + MultiMesh *multimesh_dirty_list = nullptr; + + _FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const; + _FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb); + _FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb); + _FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances); + void _update_dirty_multimeshes(); /* LIGHT */ struct Light { @@ -485,7 +531,7 @@ public: _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); - if (material->shader_type != p_shader_type) { + if (!material || material->shader_type != p_shader_type) { return NULL; } else { return material->data; @@ -612,30 +658,69 @@ public: /* MULTIMESH API */ - virtual RID multimesh_create() { return RID(); } + RID multimesh_create(); - void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data = VS::MULTIMESH_CUSTOM_DATA_NONE) {} - int multimesh_get_instance_count(RID p_multimesh) const { return 0; } + void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false); + int multimesh_get_instance_count(RID p_multimesh) const; - void multimesh_set_mesh(RID p_multimesh, RID p_mesh) {} - void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {} - void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {} - void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {} - void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {} + void multimesh_set_mesh(RID p_multimesh, RID p_mesh); + void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform); + void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform); + void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color); + void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color); - RID multimesh_get_mesh(RID p_multimesh) const { return RID(); } + RID multimesh_get_mesh(RID p_multimesh) const; - Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const { return Transform(); } - Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { return Transform2D(); } - Color multimesh_instance_get_color(RID p_multimesh, int p_index) const { return Color(); } - Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { return Color(); } + Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const; + Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const; + Color multimesh_instance_get_color(RID p_multimesh, int p_index) const; + Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const; - void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) {} + void multimesh_set_buffer(RID p_multimesh, const PoolVector<float> &p_buffer); + PoolVector<float> multimesh_get_buffer(RID p_multimesh) const; - void multimesh_set_visible_instances(RID p_multimesh, int p_visible) {} - int multimesh_get_visible_instances(RID p_multimesh) const { return 0; } + void multimesh_set_visible_instances(RID p_multimesh, int p_visible); + int multimesh_get_visible_instances(RID p_multimesh) const; - AABB multimesh_get_aabb(RID p_multimesh) const { return AABB(); } + AABB multimesh_get_aabb(RID p_multimesh) const; + + _FORCE_INLINE_ VS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + return multimesh->xform_format; + } + + _FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + return multimesh->uses_colors; + } + + _FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + return multimesh->uses_custom_data; + } + + _FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + if (multimesh->visible_instances >= 0) { + return multimesh->visible_instances; + } + return multimesh->instances; + } + + _FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const { + MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + if (!multimesh->uniform_set_3d.is_valid()) { + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.ids.push_back(multimesh->buffer); + uniforms.push_back(u); + multimesh->uniform_set_3d = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set); + } + + return multimesh->uniform_set_3d; + } /* IMMEDIATE API */ @@ -919,7 +1004,7 @@ public: bool free(RID p_rid); - bool has_os_feature(const String &p_feature) const { return false; } + bool has_os_feature(const String &p_feature) const; void update_dirty_resources(); diff --git a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp index 3908fbec3f..1aa48a82fc 100644 --- a/servers/visual/rasterizer_rd/shader_compiler_rd.cpp +++ b/servers/visual/rasterizer_rd/shader_compiler_rd.cpp @@ -482,8 +482,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge //code for functions for (int i = 0; i < pnode->functions.size(); i++) { SL::FunctionNode *fnode = pnode->functions[i].function; + function = fnode; current_func_name = fnode->name; function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + function = NULL; } //place functions in actual code @@ -763,7 +765,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge sampler_name = actions.custom_samplers[texture_uniform]; } else { if (shader->uniforms.has(texture_uniform)) { - print_line("shader from texture uniform " + itos(shader->uniforms[texture_uniform].filter) + ", " + itos(shader->uniforms[texture_uniform].repeat)); sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); } else { bool found = false; diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl index d64276a2bf..1bd11c4288 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl @@ -86,16 +86,50 @@ layout(location =8) out float dp_clip; void main() { instance_index = draw_call.instance_index; - - /*if (draw_call.instance_increment) { - instance_index += gl_InstanceIndex; - }*/ - - vec3 vertex = vertex_attrib; + vec4 instance_custom = vec4(0.0); +#if defined(COLOR_USED) + color_interp = color_attrib; +#endif mat4 world_matrix = instances.data[instance_index].transform; mat3 world_normal_matrix= mat3(instances.data[instance_index].normal_transform); + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH)) { + //multimesh, instances are for it + uint offset = (instances.data[instance_index].flags>>INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT)&INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK; + offset*=gl_InstanceIndex; + + + mat4 matrix; + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + mat4 matrix = mat4(transforms.data[offset+0],transforms.data[offset+1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0)); + offset+=2; + } else { + mat4 matrix = mat4(transforms.data[offset+0],transforms.data[offset+1],transforms.data[offset+2],vec4(0.0,0.0,0.0,1.0)); + offset+=3; + } + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { +#ifdef COLOR_USED + color_interp *= transforms.data[offset]; +#endif + offset+=1; + } + + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + instance_custom = transforms.data[offset]; + } + + //transposed, so multiply in opposite order + world_matrix = matrix * world_matrix; + world_normal_matrix = mat3(matrix) * world_normal_matrix; + + } else { + //not a multimesh, instances are for multiple draw calls + instance_index += gl_InstanceIndex; + } + + vec3 vertex = vertex_attrib; vec3 normal = normal_attrib; #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) @@ -103,10 +137,6 @@ void main() { float binormalf = tangent_attrib.a; #endif -#if defined(COLOR_USED) - color_interp = color_attrib; -#endif - #if defined(TANGENT_USED) || defined(NORMALMAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 binormal = normalize(cross(normal, tangent) * binormalf); @@ -124,7 +154,7 @@ void main() { vec4 position; #endif - vec4 instance_custom = vec4(0.0); + mat4 projection_matrix = scene_data.projection_matrix; @@ -768,7 +798,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a transmission, #endif #ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, + rim * spot_attenuation, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -932,7 +962,7 @@ void main() { float normaldepth = 1.0; #if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; + vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size; #endif float sss_strength = 0.0; @@ -1182,7 +1212,7 @@ FRAGMENT_SHADER_CODE transmission, #endif #ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, + rim, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl index d6b6aa4301..4d1a1c9495 100644 --- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl +++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl @@ -118,11 +118,20 @@ layout(set=0,binding=8,std140) uniform SceneData { #endif } scene_data; -#define INSTANCE_FLAGS_FORWARD_MASK 3 +#define INSTANCE_FLAGS_FORWARD_MASK 0x7 #define INSTANCE_FLAGS_FORWARD_OMNI_LIGHT_SHIFT 3 #define INSTANCE_FLAGS_FORWARD_SPOT_LIGHT_SHIFT 6 #define INSTANCE_FLAGS_FORWARD_DECAL_SHIFT 9 +#define INSTANCE_FLAGS_MULTIMESH (1 << 12) +#define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) +#define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) +#define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) +#define INSTANCE_FLAGS_MULTIMESH_STRIDE_SHIFT 16 +//3 bits of stride +#define INSTANCE_FLAGS_MULTIMESH_STRIDE_MASK 0x7 + + struct InstanceData { mat4 transform; @@ -217,6 +226,11 @@ layout(set=0,binding=15,std430) buffer Skeletons { //layout(set = 1, binding = 0) uniform textureBuffer multimesh_transforms; +layout(set=1,binding=0,std430) buffer Transforms { + vec4 data[]; +} transforms; + + /* Set 2 Instancing (Multimesh) data */ #if 0 diff --git a/servers/visual/rasterizer_rd/shaders/tonemap.glsl b/servers/visual/rasterizer_rd/shaders/tonemap.glsl index 6797ff9f77..f54c938e24 100644 --- a/servers/visual/rasterizer_rd/shaders/tonemap.glsl +++ b/servers/visual/rasterizer_rd/shaders/tonemap.glsl @@ -145,7 +145,7 @@ vec3 tonemap_filmic(vec3 color, float white) { vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; - return color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f); + return color_tonemapped / white_tonemapped; } vec3 tonemap_aces(vec3 color, float white) { @@ -159,7 +159,7 @@ vec3 tonemap_aces(vec3 color, float white) { vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E); float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E); - return color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f); + return color_tonemapped / white_tonemapped; } vec3 tonemap_reinhard(vec3 color, float white) { diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index c343e23881..5ef51e3e1a 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -307,6 +307,12 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_HINT_WHITE_TEXTURE, "hint_white" }, { TK_HINT_BLACK_TEXTURE, "hint_black" }, { TK_HINT_NORMAL_TEXTURE, "hint_normal" }, + { TK_HINT_ROUGHNESS_NORMAL_TEXTURE, "hint_roughness_normal" }, + { TK_HINT_ROUGHNESS_R, "hint_roughness_r" }, + { TK_HINT_ROUGHNESS_G, "hint_roughness_g" }, + { TK_HINT_ROUGHNESS_B, "hint_roughness_b" }, + { TK_HINT_ROUGHNESS_A, "hint_roughness_a" }, + { TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray" }, { TK_HINT_ANISO_TEXTURE, "hint_aniso" }, { TK_HINT_ALBEDO_TEXTURE, "hint_albedo" }, { TK_HINT_BLACK_ALBEDO_TEXTURE, "hint_black_albedo" }, @@ -5171,6 +5177,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct uniform2.hint = ShaderNode::Uniform::HINT_BLACK; } else if (tk.type == TK_HINT_NORMAL_TEXTURE) { uniform2.hint = ShaderNode::Uniform::HINT_NORMAL; + } else if (tk.type == TK_HINT_ROUGHNESS_NORMAL_TEXTURE) { + uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL; + } else if (tk.type == TK_HINT_ROUGHNESS_R) { + uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_R; + } else if (tk.type == TK_HINT_ROUGHNESS_G) { + uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_G; + } else if (tk.type == TK_HINT_ROUGHNESS_B) { + uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_B; + } else if (tk.type == TK_HINT_ROUGHNESS_A) { + uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_A; + } else if (tk.type == TK_HINT_ROUGHNESS_GRAY) { + uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_GRAY; } else if (tk.type == TK_HINT_ANISO_TEXTURE) { uniform2.hint = ShaderNode::Uniform::HINT_ANISO; } else if (tk.type == TK_HINT_ALBEDO_TEXTURE) { diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 3a1ded0547..da5b0600ff 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -150,6 +150,12 @@ public: TK_HINT_WHITE_TEXTURE, TK_HINT_BLACK_TEXTURE, TK_HINT_NORMAL_TEXTURE, + TK_HINT_ROUGHNESS_NORMAL_TEXTURE, + TK_HINT_ROUGHNESS_R, + TK_HINT_ROUGHNESS_G, + TK_HINT_ROUGHNESS_B, + TK_HINT_ROUGHNESS_A, + TK_HINT_ROUGHNESS_GRAY, TK_HINT_ANISO_TEXTURE, TK_HINT_ALBEDO_TEXTURE, TK_HINT_BLACK_ALBEDO_TEXTURE, @@ -576,6 +582,12 @@ public: HINT_ALBEDO, HINT_BLACK_ALBEDO, HINT_NORMAL, + HINT_ROUGHNESS_NORMAL, + HINT_ROUGHNESS_R, + HINT_ROUGHNESS_G, + HINT_ROUGHNESS_B, + HINT_ROUGHNESS_A, + HINT_ROUGHNESS_GRAY, HINT_BLACK, HINT_WHITE, HINT_ANISO, diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index be19a935e9..8543289083 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -248,7 +248,7 @@ public: BIND0R(RID, multimesh_create) - BIND5(multimesh_allocate, RID, int, MultimeshTransformFormat, MultimeshColorFormat, MultimeshCustomDataFormat) + BIND5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool) BIND1RC(int, multimesh_get_instance_count, RID) BIND2(multimesh_set_mesh, RID, RID) @@ -265,7 +265,8 @@ public: BIND2RC(Color, multimesh_instance_get_color, RID, int) BIND2RC(Color, multimesh_instance_get_custom_data, RID, int) - BIND2(multimesh_set_as_bulk_array, RID, const PoolVector<float> &) + BIND2(multimesh_set_buffer, RID, const PoolVector<float> &) + BIND1RC(PoolVector<float>, multimesh_get_buffer, RID) BIND2(multimesh_set_visible_instances, RID, int) BIND1RC(int, multimesh_get_visible_instances, RID) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 3f33ec945c..96831d1cc2 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1863,7 +1863,6 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca bool keep = false; if ((camera_layer_mask & ins->layer_mask) == 0) { - //failure } else if (ins->base_type == VS::INSTANCE_LIGHT && ins->visible) { diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index d8cd6771c1..a58d36f279 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -175,7 +175,7 @@ public: FUNCRID(multimesh) - FUNC5(multimesh_allocate, RID, int, MultimeshTransformFormat, MultimeshColorFormat, MultimeshCustomDataFormat) + FUNC5(multimesh_allocate, RID, int, MultimeshTransformFormat, bool, bool) FUNC1RC(int, multimesh_get_instance_count, RID) FUNC2(multimesh_set_mesh, RID, RID) @@ -192,7 +192,8 @@ public: FUNC2RC(Color, multimesh_instance_get_color, RID, int) FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int) - FUNC2(multimesh_set_as_bulk_array, RID, const PoolVector<float> &) + FUNC2(multimesh_set_buffer, RID, const PoolVector<float> &) + FUNC1RC(PoolVector<float>, multimesh_get_buffer, RID) FUNC2(multimesh_set_visible_instances, RID, int) FUNC1RC(int, multimesh_get_visible_instances, RID) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 66e0d67938..0c72a09a91 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1638,7 +1638,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &VisualServer::mesh_clear); ClassDB::bind_method(D_METHOD("multimesh_create"), &VisualServer::multimesh_create); - ClassDB::bind_method(D_METHOD("multimesh_allocate", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &VisualServer::multimesh_allocate, DEFVAL(MULTIMESH_CUSTOM_DATA_NONE)); + ClassDB::bind_method(D_METHOD("multimesh_allocate", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &VisualServer::multimesh_allocate, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("multimesh_get_instance_count", "multimesh"), &VisualServer::multimesh_get_instance_count); ClassDB::bind_method(D_METHOD("multimesh_set_mesh", "multimesh", "mesh"), &VisualServer::multimesh_set_mesh); ClassDB::bind_method(D_METHOD("multimesh_instance_set_transform", "multimesh", "index", "transform"), &VisualServer::multimesh_instance_set_transform); @@ -1653,7 +1653,8 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("multimesh_instance_get_custom_data", "multimesh", "index"), &VisualServer::multimesh_instance_get_custom_data); ClassDB::bind_method(D_METHOD("multimesh_set_visible_instances", "multimesh", "visible"), &VisualServer::multimesh_set_visible_instances); ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &VisualServer::multimesh_get_visible_instances); - ClassDB::bind_method(D_METHOD("multimesh_set_as_bulk_array", "multimesh", "array"), &VisualServer::multimesh_set_as_bulk_array); + ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &VisualServer::multimesh_set_buffer); + ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &VisualServer::multimesh_get_buffer); #ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("immediate_create"), &VisualServer::immediate_create); ClassDB::bind_method(D_METHOD("immediate_begin", "immediate", "primitive", "texture"), &VisualServer::immediate_begin, DEFVAL(RID())); @@ -2151,12 +2152,6 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_2D); BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_3D); - BIND_ENUM_CONSTANT(MULTIMESH_COLOR_NONE); - BIND_ENUM_CONSTANT(MULTIMESH_COLOR_8BIT); - BIND_ENUM_CONSTANT(MULTIMESH_COLOR_FLOAT); - BIND_ENUM_CONSTANT(MULTIMESH_CUSTOM_DATA_NONE); - BIND_ENUM_CONSTANT(MULTIMESH_CUSTOM_DATA_8BIT); - BIND_ENUM_CONSTANT(MULTIMESH_CUSTOM_DATA_FLOAT); BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE); BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS); diff --git a/servers/visual_server.h b/servers/visual_server.h index 2ab521c7c0..06dba99860 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -319,21 +319,7 @@ public: MULTIMESH_TRANSFORM_3D, }; - enum MultimeshColorFormat { - MULTIMESH_COLOR_NONE, - MULTIMESH_COLOR_8BIT, - MULTIMESH_COLOR_FLOAT, - MULTIMESH_COLOR_MAX, - }; - - enum MultimeshCustomDataFormat { - MULTIMESH_CUSTOM_DATA_NONE, - MULTIMESH_CUSTOM_DATA_8BIT, - MULTIMESH_CUSTOM_DATA_FLOAT, - MULTIMESH_CUSTOM_DATA_MAX, - }; - - virtual void multimesh_allocate(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, MultimeshColorFormat p_color_format, MultimeshCustomDataFormat p_data_format = MULTIMESH_CUSTOM_DATA_NONE) = 0; + virtual void multimesh_allocate(RID p_multimesh, int p_instances, MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) = 0; virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; @@ -350,7 +336,8 @@ public: virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; - virtual void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) = 0; + virtual void multimesh_set_buffer(RID p_multimesh, const PoolVector<float> &p_buffer) = 0; + virtual PoolVector<float> multimesh_get_buffer(RID p_multimesh) const = 0; virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; @@ -1100,8 +1087,6 @@ VARIANT_ENUM_CAST(VisualServer::CanvasOccluderPolygonCullMode); VARIANT_ENUM_CAST(VisualServer::RenderInfo); VARIANT_ENUM_CAST(VisualServer::Features); VARIANT_ENUM_CAST(VisualServer::MultimeshTransformFormat); -VARIANT_ENUM_CAST(VisualServer::MultimeshColorFormat); -VARIANT_ENUM_CAST(VisualServer::MultimeshCustomDataFormat); VARIANT_ENUM_CAST(VisualServer::LightOmniShadowMode); VARIANT_ENUM_CAST(VisualServer::LightDirectionalShadowMode); VARIANT_ENUM_CAST(VisualServer::LightDirectionalShadowDepthRangeMode); |