Merge pull request #79833 from puchik/multimesh-custom-aabb

Support custom AABBs within MultiMesh resources
This commit is contained in:
Rémi Verschelde 2024-02-17 00:22:36 +01:00
commit 7b152de1e9
No known key found for this signature in database
GPG Key ID: C3336907360768E1
19 changed files with 261 additions and 8 deletions

View File

@ -309,6 +309,10 @@
<member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> <member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum tangent acceleration. Minimum tangent acceleration.
</member> </member>
<member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB(-4, -4, -4, 8, 8, 8)">
The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active.
Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool.
</member>
</members> </members>
<signals> <signals>
<signal name="finished"> <signal name="finished">

View File

@ -92,7 +92,11 @@
</member> </member>
<member name="color_array" type="PackedColorArray" setter="_set_color_array" getter="_get_color_array" deprecated="Use [method set_instance_color] instead."> <member name="color_array" type="PackedColorArray" setter="_set_color_array" getter="_get_color_array" deprecated="Use [method set_instance_color] instead.">
</member> </member>
<member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB(0, 0, 0, 0, 0, 0)">
Custom AABB for this MultiMesh resource. Setting this manually prevents costly runtime AABB recalculations.
</member>
<member name="custom_data_array" type="PackedColorArray" setter="_set_custom_data_array" getter="_get_custom_data_array" deprecated="Use [method set_instance_custom_data] instead."> <member name="custom_data_array" type="PackedColorArray" setter="_set_custom_data_array" getter="_get_custom_data_array" deprecated="Use [method set_instance_custom_data] instead.">
See [method set_instance_custom_data].
</member> </member>
<member name="instance_count" type="int" setter="set_instance_count" getter="get_instance_count" default="0"> <member name="instance_count" type="int" setter="set_instance_count" getter="get_instance_count" default="0">
Number of instances that will get drawn. This clears and (re)sizes the buffers. Setting data format or flags afterwards will have no effect. Number of instances that will get drawn. This clears and (re)sizes the buffers. Setting data format or flags afterwards will have no effect.

View File

@ -2332,6 +2332,13 @@
[b]Note:[/b] If the buffer is in the engine's internal cache, it will have to be fetched from GPU memory and possibly decompressed. This means [method multimesh_get_buffer] is potentially a slow operation and should be avoided whenever possible. [b]Note:[/b] If the buffer is in the engine's internal cache, it will have to be fetched from GPU memory and possibly decompressed. This means [method multimesh_get_buffer] is potentially a slow operation and should be avoided whenever possible.
</description> </description>
</method> </method>
<method name="multimesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
<param index="0" name="multimesh" type="RID" />
<description>
Returns the custom AABB defined for this MultiMesh resource.
</description>
</method>
<method name="multimesh_get_instance_count" qualifiers="const"> <method name="multimesh_get_instance_count" qualifiers="const">
<return type="int" /> <return type="int" />
<param index="0" name="multimesh" type="RID" /> <param index="0" name="multimesh" type="RID" />
@ -2442,6 +2449,14 @@
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
<method name="multimesh_set_custom_aabb">
<return type="void" />
<param index="0" name="multimesh" type="RID" />
<param index="1" name="aabb" type="AABB" />
<description>
Sets the custom AABB for this MultiMesh resource.
</description>
</method>
<method name="multimesh_set_mesh"> <method name="multimesh_set_mesh">
<return type="void" /> <return type="void" />
<param index="0" name="multimesh" type="RID" /> <param index="0" name="multimesh" type="RID" />

View File

@ -1607,6 +1607,9 @@ void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, b
void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) {
ERR_FAIL_COND(multimesh->mesh.is_null()); ERR_FAIL_COND(multimesh->mesh.is_null());
if (multimesh->custom_aabb != AABB()) {
return;
}
AABB aabb; AABB aabb;
AABB mesh_aabb = mesh_get_aabb(multimesh->mesh); AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
for (int i = 0; i < p_instances; i++) { for (int i = 0; i < p_instances; i++) {
@ -1749,9 +1752,25 @@ RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
return multimesh->mesh; return multimesh->mesh;
} }
void MeshStorage::multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
multimesh->custom_aabb = p_aabb;
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
AABB MeshStorage::multimesh_get_custom_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, AABB());
return multimesh->custom_aabb;
}
AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const { AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, AABB()); ERR_FAIL_NULL_V(multimesh, AABB());
if (multimesh->custom_aabb != AABB()) {
return multimesh->custom_aabb;
}
if (multimesh->aabb_dirty) { if (multimesh->aabb_dirty) {
const_cast<MeshStorage *>(this)->_update_dirty_multimeshes(); const_cast<MeshStorage *>(this)->_update_dirty_multimeshes();
} }
@ -1943,8 +1962,10 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
//if we have a mesh set, we need to re-generate the AABB from the new data //if we have a mesh set, we need to re-generate the AABB from the new data
const float *data = p_buffer.ptr(); const float *data = p_buffer.ptr();
_multimesh_re_create_aabb(multimesh, data, multimesh->instances); if (multimesh->custom_aabb != AABB()) {
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
} }
} }
@ -2091,9 +2112,11 @@ void MeshStorage::_update_dirty_multimeshes() {
} }
if (multimesh->aabb_dirty && multimesh->mesh.is_valid()) { if (multimesh->aabb_dirty && multimesh->mesh.is_valid()) {
_multimesh_re_create_aabb(multimesh, data, visible_instances);
multimesh->aabb_dirty = false; multimesh->aabb_dirty = false;
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); if (multimesh->custom_aabb != AABB()) {
_multimesh_re_create_aabb(multimesh, data, visible_instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
} }
} }

View File

@ -189,6 +189,7 @@ struct MultiMesh {
bool uses_custom_data = false; bool uses_custom_data = false;
int visible_instances = -1; int visible_instances = -1;
AABB aabb; AABB aabb;
AABB custom_aabb;
bool aabb_dirty = false; bool aabb_dirty = false;
bool buffer_set = false; bool buffer_set = false;
uint32_t stride_cache = 0; uint32_t stride_cache = 0;
@ -505,6 +506,8 @@ public:
virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override; virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override;
virtual RID multimesh_get_mesh(RID p_multimesh) const override; virtual RID multimesh_get_mesh(RID p_multimesh) const override;
virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override;
virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const override;
virtual AABB multimesh_get_aabb(RID p_multimesh) const override; virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override; virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override;

View File

@ -77,9 +77,62 @@ void CPUParticles3DEditor::_menu_option(int p_option) {
ur->commit_action(false); ur->commit_action(false);
} break; } break;
case MENU_OPTION_GENERATE_AABB: {
// Add one second to the default generation lifetime, since the progress is updated every second.
generate_seconds->set_value(MAX(1.0, trunc(node->get_lifetime()) + 1.0));
if (generate_seconds->get_value() >= 11.0 + CMP_EPSILON) {
// Only pop up the time dialog if the particle's lifetime is long enough to warrant shortening it.
generate_aabb->popup_centered();
} else {
// Generate the visibility AABB immediately.
_generate_aabb();
}
} break;
} }
} }
void CPUParticles3DEditor::_generate_aabb() {
double time = generate_seconds->get_value();
double running = 0.0;
EditorProgress ep("gen_aabb", TTR("Generating Visibility AABB (Waiting for Particle Simulation)"), int(time));
bool was_emitting = node->is_emitting();
if (!was_emitting) {
node->set_emitting(true);
OS::get_singleton()->delay_usec(1000);
}
AABB rect;
while (running < time) {
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
ep.step("Generating...", int(running), true);
OS::get_singleton()->delay_usec(1000);
AABB capture = node->capture_aabb();
if (rect == AABB()) {
rect = capture;
} else {
rect.merge_with(capture);
}
running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0;
}
if (!was_emitting) {
node->set_emitting(false);
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Generate Visibility AABB"));
ur->add_do_method(node, "set_visibility_aabb", rect);
ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
ur->commit_action();
}
void CPUParticles3DEditor::edit(CPUParticles3D *p_particles) { void CPUParticles3DEditor::edit(CPUParticles3D *p_particles) {
base_node = p_particles; base_node = p_particles;
node = p_particles; node = p_particles;
@ -117,9 +170,24 @@ CPUParticles3DEditor::CPUParticles3DEditor() {
options->set_text(TTR("CPUParticles3D")); options->set_text(TTR("CPUParticles3D"));
options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART);
options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB);
options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE);
options->get_popup()->add_item(TTR("Convert to GPUParticles3D"), MENU_OPTION_CONVERT_TO_GPU_PARTICLES); options->get_popup()->add_item(TTR("Convert to GPUParticles3D"), MENU_OPTION_CONVERT_TO_GPU_PARTICLES);
options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option)); options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option));
generate_aabb = memnew(ConfirmationDialog);
generate_aabb->set_title(TTR("Generate Visibility AABB"));
VBoxContainer *genvb = memnew(VBoxContainer);
generate_aabb->add_child(genvb);
generate_seconds = memnew(SpinBox);
genvb->add_margin_child(TTR("Generation Time (sec):"), generate_seconds);
generate_seconds->set_min(0.1);
generate_seconds->set_max(25);
generate_seconds->set_value(2);
add_child(generate_aabb);
generate_aabb->connect("confirmed", callable_mp(this, &CPUParticles3DEditor::_generate_aabb));
} }
void CPUParticles3DEditorPlugin::edit(Object *p_object) { void CPUParticles3DEditorPlugin::edit(Object *p_object) {

View File

@ -38,14 +38,19 @@ class CPUParticles3DEditor : public GPUParticles3DEditorBase {
GDCLASS(CPUParticles3DEditor, GPUParticles3DEditorBase); GDCLASS(CPUParticles3DEditor, GPUParticles3DEditorBase);
enum Menu { enum Menu {
MENU_OPTION_GENERATE_AABB,
MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE, MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE,
MENU_OPTION_CLEAR_EMISSION_VOLUME, MENU_OPTION_CLEAR_EMISSION_VOLUME,
MENU_OPTION_RESTART, MENU_OPTION_RESTART,
MENU_OPTION_CONVERT_TO_GPU_PARTICLES, MENU_OPTION_CONVERT_TO_GPU_PARTICLES,
}; };
ConfirmationDialog *generate_aabb = nullptr;
SpinBox *generate_seconds = nullptr;
CPUParticles3D *node = nullptr; CPUParticles3D *node = nullptr;
void _generate_aabb();
void _menu_option(int); void _menu_option(int);
friend class CPUParticles3DEditorPlugin; friend class CPUParticles3DEditorPlugin;

View File

@ -31,11 +31,16 @@
#include "cpu_particles_3d_gizmo_plugin.h" #include "cpu_particles_3d_gizmo_plugin.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h" #include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/cpu_particles_3d.h" #include "scene/3d/cpu_particles_3d.h"
CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() { CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
create_material("particles_material", gizmo_color);
gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0);
create_material("particles_solid_material", gizmo_color);
create_icon_material("particles_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoCPUParticles3D"), EditorStringName(EditorIcons))); create_icon_material("particles_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoCPUParticles3D"), EditorStringName(EditorIcons)));
} }
@ -56,6 +61,48 @@ bool CPUParticles3DGizmoPlugin::is_selectable_when_hidden() const {
} }
void CPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { void CPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
CPUParticles3D *particles = Object::cast_to<CPUParticles3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
Vector<Vector3> lines;
AABB aabb = particles->get_visibility_aabb();
for (int i = 0; i < 12; i++) {
Vector3 a, b;
aabb.get_edge(i, a, b);
lines.push_back(a);
lines.push_back(b);
}
Vector<Vector3> handles;
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = aabb.position[i] + aabb.size[i];
ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
handles.push_back(ax);
}
Vector3 center = aabb.get_center();
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = 1.0;
handles.push_back(center + ax);
lines.push_back(center);
lines.push_back(center + ax);
}
Ref<Material> material = get_material("particles_material", p_gizmo);
p_gizmo->add_lines(lines, material);
if (p_gizmo->is_selected()) {
Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
}
Ref<Material> icon = get_material("particles_icon", p_gizmo); Ref<Material> icon = get_material("particles_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05); p_gizmo->add_unscaled_billboard(icon, 0.05);
} }

View File

@ -101,6 +101,12 @@ void CPUParticles3D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio; randomness_ratio = p_ratio;
} }
void CPUParticles3D::set_visibility_aabb(const AABB &p_aabb) {
RS::get_singleton()->multimesh_set_custom_aabb(multimesh, p_aabb);
visibility_aabb = p_aabb;
update_gizmos();
}
void CPUParticles3D::set_lifetime_randomness(double p_random) { void CPUParticles3D::set_lifetime_randomness(double p_random) {
lifetime_randomness = p_random; lifetime_randomness = p_random;
} }
@ -141,6 +147,10 @@ real_t CPUParticles3D::get_randomness_ratio() const {
return randomness_ratio; return randomness_ratio;
} }
AABB CPUParticles3D::get_visibility_aabb() const {
return visibility_aabb;
}
double CPUParticles3D::get_lifetime_randomness() const { double CPUParticles3D::get_lifetime_randomness() const {
return lifetime_randomness; return lifetime_randomness;
} }
@ -520,6 +530,11 @@ bool CPUParticles3D::get_split_scale() {
return split_scale; return split_scale;
} }
AABB CPUParticles3D::capture_aabb() const {
RS::get_singleton()->multimesh_set_custom_aabb(multimesh, AABB());
return RS::get_singleton()->multimesh_get_aabb(multimesh);
}
void CPUParticles3D::_validate_property(PropertyInfo &p_property) const { void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
p_property.usage = PROPERTY_USAGE_NONE; p_property.usage = PROPERTY_USAGE_NONE;
@ -1341,6 +1356,7 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_pre_process_time(gpu_particles->get_pre_process_time()); set_pre_process_time(gpu_particles->get_pre_process_time());
set_explosiveness_ratio(gpu_particles->get_explosiveness_ratio()); set_explosiveness_ratio(gpu_particles->get_explosiveness_ratio());
set_randomness_ratio(gpu_particles->get_randomness_ratio()); set_randomness_ratio(gpu_particles->get_randomness_ratio());
set_visibility_aabb(gpu_particles->get_visibility_aabb());
set_use_local_coordinates(gpu_particles->get_use_local_coordinates()); set_use_local_coordinates(gpu_particles->get_use_local_coordinates());
set_fixed_fps(gpu_particles->get_fixed_fps()); set_fixed_fps(gpu_particles->get_fixed_fps());
set_fractional_delta(gpu_particles->get_fractional_delta()); set_fractional_delta(gpu_particles->get_fractional_delta());
@ -1420,6 +1436,7 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles3D::set_pre_process_time); ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles3D::set_pre_process_time);
ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles3D::set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles3D::set_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles3D::set_randomness_ratio); ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles3D::set_randomness_ratio);
ClassDB::bind_method(D_METHOD("set_visibility_aabb", "aabb"), &CPUParticles3D::set_visibility_aabb);
ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "random"), &CPUParticles3D::set_lifetime_randomness); ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "random"), &CPUParticles3D::set_lifetime_randomness);
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles3D::set_use_local_coordinates); ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles3D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles3D::set_fixed_fps); ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles3D::set_fixed_fps);
@ -1433,6 +1450,7 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles3D::get_pre_process_time); ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles3D::get_pre_process_time);
ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles3D::get_explosiveness_ratio); ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles3D::get_explosiveness_ratio);
ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles3D::get_randomness_ratio); ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles3D::get_randomness_ratio);
ClassDB::bind_method(D_METHOD("get_visibility_aabb"), &CPUParticles3D::get_visibility_aabb);
ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &CPUParticles3D::get_lifetime_randomness); ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &CPUParticles3D::get_lifetime_randomness);
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles3D::get_use_local_coordinates); ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles3D::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles3D::get_fixed_fps); ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles3D::get_fixed_fps);
@ -1461,6 +1479,7 @@ void CPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Drawing", ""); ADD_GROUP("Drawing", "");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_visibility_aabb", "get_visibility_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
@ -1665,6 +1684,7 @@ CPUParticles3D::CPUParticles3D() {
set_emitting(true); set_emitting(true);
set_amount(8); set_amount(8);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
set_param_min(PARAM_ANGULAR_VELOCITY, 0); set_param_min(PARAM_ANGULAR_VELOCITY, 0);

View File

@ -138,6 +138,7 @@ private:
real_t randomness_ratio = 0.0; real_t randomness_ratio = 0.0;
double lifetime_randomness = 0.0; double lifetime_randomness = 0.0;
double speed_scale = 1.0; double speed_scale = 1.0;
AABB visibility_aabb;
bool local_coords = false; bool local_coords = false;
int fixed_fps = 0; int fixed_fps = 0;
bool fractional_delta = true; bool fractional_delta = true;
@ -210,6 +211,7 @@ public:
void set_pre_process_time(double p_time); void set_pre_process_time(double p_time);
void set_explosiveness_ratio(real_t p_ratio); void set_explosiveness_ratio(real_t p_ratio);
void set_randomness_ratio(real_t p_ratio); void set_randomness_ratio(real_t p_ratio);
void set_visibility_aabb(const AABB &p_aabb);
void set_lifetime_randomness(double p_random); void set_lifetime_randomness(double p_random);
void set_use_local_coordinates(bool p_enable); void set_use_local_coordinates(bool p_enable);
void set_speed_scale(double p_scale); void set_speed_scale(double p_scale);
@ -221,6 +223,7 @@ public:
double get_pre_process_time() const; double get_pre_process_time() const;
real_t get_explosiveness_ratio() const; real_t get_explosiveness_ratio() const;
real_t get_randomness_ratio() const; real_t get_randomness_ratio() const;
AABB get_visibility_aabb() const;
double get_lifetime_randomness() const; double get_lifetime_randomness() const;
bool get_use_local_coordinates() const; bool get_use_local_coordinates() const;
double get_speed_scale() const; double get_speed_scale() const;
@ -308,6 +311,8 @@ public:
void convert_from_particles(Node *p_particles); void convert_from_particles(Node *p_particles);
AABB capture_aabb() const;
CPUParticles3D(); CPUParticles3D();
~CPUParticles3D(); ~CPUParticles3D();
}; };

View File

@ -269,6 +269,16 @@ Color MultiMesh::get_instance_custom_data(int p_instance) const {
return RenderingServer::get_singleton()->multimesh_instance_get_custom_data(multimesh, p_instance); return RenderingServer::get_singleton()->multimesh_instance_get_custom_data(multimesh, p_instance);
} }
void MultiMesh::set_custom_aabb(const AABB &p_custom) {
custom_aabb = p_custom;
RS::get_singleton()->multimesh_set_custom_aabb(multimesh, custom_aabb);
emit_changed();
}
AABB MultiMesh::get_custom_aabb() const {
return custom_aabb;
}
AABB MultiMesh::get_aabb() const { AABB MultiMesh::get_aabb() const {
return RenderingServer::get_singleton()->multimesh_get_aabb(multimesh); return RenderingServer::get_singleton()->multimesh_get_aabb(multimesh);
} }
@ -326,6 +336,8 @@ void MultiMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_instance_color", "instance"), &MultiMesh::get_instance_color); ClassDB::bind_method(D_METHOD("get_instance_color", "instance"), &MultiMesh::get_instance_color);
ClassDB::bind_method(D_METHOD("set_instance_custom_data", "instance", "custom_data"), &MultiMesh::set_instance_custom_data); ClassDB::bind_method(D_METHOD("set_instance_custom_data", "instance", "custom_data"), &MultiMesh::set_instance_custom_data);
ClassDB::bind_method(D_METHOD("get_instance_custom_data", "instance"), &MultiMesh::get_instance_custom_data); ClassDB::bind_method(D_METHOD("get_instance_custom_data", "instance"), &MultiMesh::get_instance_custom_data);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &MultiMesh::set_custom_aabb);
ClassDB::bind_method(D_METHOD("get_custom_aabb"), &MultiMesh::get_custom_aabb);
ClassDB::bind_method(D_METHOD("get_aabb"), &MultiMesh::get_aabb); ClassDB::bind_method(D_METHOD("get_aabb"), &MultiMesh::get_aabb);
ClassDB::bind_method(D_METHOD("get_buffer"), &MultiMesh::get_buffer); ClassDB::bind_method(D_METHOD("get_buffer"), &MultiMesh::get_buffer);
@ -334,6 +346,7 @@ void MultiMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_format", PROPERTY_HINT_ENUM, "2D,3D"), "set_transform_format", "get_transform_format"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_format", PROPERTY_HINT_ENUM, "2D,3D"), "set_transform_format", "get_transform_format");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_colors"), "set_use_colors", "is_using_colors"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_colors"), "set_use_colors", "is_using_colors");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_custom_data"), "set_use_custom_data", "is_using_custom_data"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_custom_data"), "set_use_custom_data", "is_using_custom_data");
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::INT, "instance_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"), "set_instance_count", "get_instance_count"); ADD_PROPERTY(PropertyInfo(Variant::INT, "instance_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"), "set_instance_count", "get_instance_count");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_instance_count", PROPERTY_HINT_RANGE, "-1,16384,1,or_greater"), "set_visible_instance_count", "get_visible_instance_count"); ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_instance_count", PROPERTY_HINT_RANGE, "-1,16384,1,or_greater"), "set_visible_instance_count", "get_visible_instance_count");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");

View File

@ -48,6 +48,7 @@ private:
Ref<Mesh> mesh; Ref<Mesh> mesh;
RID multimesh; RID multimesh;
TransformFormat transform_format = TRANSFORM_2D; TransformFormat transform_format = TRANSFORM_2D;
AABB custom_aabb;
bool use_colors = false; bool use_colors = false;
bool use_custom_data = false; bool use_custom_data = false;
int instance_count = 0; int instance_count = 0;
@ -103,6 +104,9 @@ public:
void set_instance_custom_data(int p_instance, const Color &p_custom_data); void set_instance_custom_data(int p_instance, const Color &p_custom_data);
Color get_instance_custom_data(int p_instance) const; Color get_instance_custom_data(int p_instance) const;
void set_custom_aabb(const AABB &p_custom);
AABB get_custom_aabb() const;
virtual AABB get_aabb() const; virtual AABB get_aabb() const;
virtual RID get_rid() const override; virtual RID get_rid() const override;

View File

@ -153,6 +153,9 @@ public:
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {} virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {}
virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {} virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {}
virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override {}
virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const override { return AABB(); }
virtual RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); } virtual RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); }
virtual AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); } virtual AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); }

View File

@ -1660,6 +1660,9 @@ void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, b
void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) { void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances) {
ERR_FAIL_COND(multimesh->mesh.is_null()); ERR_FAIL_COND(multimesh->mesh.is_null());
if (multimesh->custom_aabb != AABB()) {
return;
}
AABB aabb; AABB aabb;
AABB mesh_aabb = mesh_get_aabb(multimesh->mesh); AABB mesh_aabb = mesh_get_aabb(multimesh->mesh);
for (int i = 0; i < p_instances; i++) { for (int i = 0; i < p_instances; i++) {
@ -1960,8 +1963,10 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
//if we have a mesh set, we need to re-generate the AABB from the new data //if we have a mesh set, we need to re-generate the AABB from the new data
const float *data = p_buffer.ptr(); const float *data = p_buffer.ptr();
_multimesh_re_create_aabb(multimesh, data, multimesh->instances); if (multimesh->custom_aabb != AABB()) {
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); _multimesh_re_create_aabb(multimesh, data, multimesh->instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
} }
} }
@ -2015,9 +2020,26 @@ int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
return multimesh->visible_instances; return multimesh->visible_instances;
} }
void MeshStorage::multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL(multimesh);
multimesh->custom_aabb = p_aabb;
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
AABB MeshStorage::multimesh_get_custom_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, AABB());
return multimesh->custom_aabb;
}
AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const { AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, AABB()); ERR_FAIL_NULL_V(multimesh, AABB());
if (multimesh->custom_aabb != AABB()) {
return multimesh->custom_aabb;
}
if (multimesh->aabb_dirty) { if (multimesh->aabb_dirty) {
const_cast<MeshStorage *>(this)->_update_dirty_multimeshes(); const_cast<MeshStorage *>(this)->_update_dirty_multimeshes();
} }
@ -2064,9 +2086,11 @@ void MeshStorage::_update_dirty_multimeshes() {
if (multimesh->aabb_dirty) { if (multimesh->aabb_dirty) {
//aabb is dirty.. //aabb is dirty..
_multimesh_re_create_aabb(multimesh, data, visible_instances);
multimesh->aabb_dirty = false; multimesh->aabb_dirty = false;
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB); if (multimesh->custom_aabb != AABB()) {
_multimesh_re_create_aabb(multimesh, data, visible_instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
} }
} }

View File

@ -220,6 +220,7 @@ private:
bool uses_custom_data = false; bool uses_custom_data = false;
int visible_instances = -1; int visible_instances = -1;
AABB aabb; AABB aabb;
AABB custom_aabb;
bool aabb_dirty = false; bool aabb_dirty = false;
bool buffer_set = false; bool buffer_set = false;
bool motion_vectors_enabled = false; bool motion_vectors_enabled = false;
@ -646,6 +647,9 @@ public:
virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override; virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
virtual int multimesh_get_visible_instances(RID p_multimesh) const override; virtual int multimesh_get_visible_instances(RID p_multimesh) const override;
virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) override;
virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const override;
virtual AABB multimesh_get_aabb(RID p_multimesh) const override; virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
void _update_dirty_multimeshes(); void _update_dirty_multimeshes();

View File

@ -335,6 +335,9 @@ public:
FUNC3(multimesh_instance_set_color, RID, int, const Color &) FUNC3(multimesh_instance_set_color, RID, int, const Color &)
FUNC3(multimesh_instance_set_custom_data, RID, int, const Color &) FUNC3(multimesh_instance_set_custom_data, RID, int, const Color &)
FUNC2(multimesh_set_custom_aabb, RID, const AABB &)
FUNC1RC(AABB, multimesh_get_custom_aabb, RID)
FUNC1RC(RID, multimesh_get_mesh, RID) FUNC1RC(RID, multimesh_get_mesh, RID)
FUNC1RC(AABB, multimesh_get_aabb, RID) FUNC1RC(AABB, multimesh_get_aabb, RID)

View File

@ -104,6 +104,9 @@ public:
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0;
virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0;
virtual void multimesh_set_custom_aabb(RID p_multimesh, const AABB &p_aabb) = 0;
virtual AABB multimesh_get_custom_aabb(RID p_multimesh) const = 0;
virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;

View File

@ -2427,6 +2427,8 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("multimesh_instance_set_custom_data", "multimesh", "index", "custom_data"), &RenderingServer::multimesh_instance_set_custom_data); ClassDB::bind_method(D_METHOD("multimesh_instance_set_custom_data", "multimesh", "index", "custom_data"), &RenderingServer::multimesh_instance_set_custom_data);
ClassDB::bind_method(D_METHOD("multimesh_get_mesh", "multimesh"), &RenderingServer::multimesh_get_mesh); ClassDB::bind_method(D_METHOD("multimesh_get_mesh", "multimesh"), &RenderingServer::multimesh_get_mesh);
ClassDB::bind_method(D_METHOD("multimesh_get_aabb", "multimesh"), &RenderingServer::multimesh_get_aabb); ClassDB::bind_method(D_METHOD("multimesh_get_aabb", "multimesh"), &RenderingServer::multimesh_get_aabb);
ClassDB::bind_method(D_METHOD("multimesh_set_custom_aabb", "multimesh", "aabb"), &RenderingServer::multimesh_set_custom_aabb);
ClassDB::bind_method(D_METHOD("multimesh_get_custom_aabb", "multimesh"), &RenderingServer::multimesh_get_custom_aabb);
ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform); ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform);
ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform_2d", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform_2d); ClassDB::bind_method(D_METHOD("multimesh_instance_get_transform_2d", "multimesh", "index"), &RenderingServer::multimesh_instance_get_transform_2d);
ClassDB::bind_method(D_METHOD("multimesh_instance_get_color", "multimesh", "index"), &RenderingServer::multimesh_instance_get_color); ClassDB::bind_method(D_METHOD("multimesh_instance_get_color", "multimesh", "index"), &RenderingServer::multimesh_instance_get_color);

View File

@ -413,6 +413,9 @@ public:
virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; virtual RID multimesh_get_mesh(RID p_multimesh) const = 0;
virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0;
virtual void multimesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) = 0;
virtual AABB multimesh_get_custom_aabb(RID p_mesh) const = 0;
virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0;
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0;
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0;