Geometry Nodes: Simulation calculate to frame operator #107627

Merged
Lukas Tönne merged 3 commits from LukasTonne/blender:cache-to-frame-op into main 2023-05-08 13:41:28 +02:00
5 changed files with 169 additions and 0 deletions

View File

@ -27,10 +27,14 @@ class PHYSICS_PT_geometry_nodes(Panel):
layout = self.layout
if len(context.selected_editable_objects) > 1:
calc_text = iface_("Calculate Selected to Frame")
bake_text = iface_("Bake Selected")
else:
calc_text = iface_("Calculate to Frame")
bake_text = iface_("Bake")
layout.operator("object.simulation_nodes_cache_calculate_to_frame", text=calc_text).selected = True
row = layout.row(align=True)
row.operator("object.simulation_nodes_cache_bake", text=bake_text).selected = True
row.operator("object.simulation_nodes_cache_delete", text="", icon='TRASH').selected = True

View File

@ -51,6 +51,148 @@
namespace blender::ed::object::bake_simulation {
static bool calculate_to_frame_poll(bContext *C)
{
if (!ED_operator_object_active(C)) {
return false;
}
return true;
}
struct CalculateSimulationJob {
LukasTonne marked this conversation as resolved
Review

Unused struct here

Unused struct here
wmWindowManager *wm;
Main *bmain;
Depsgraph *depsgraph;
Scene *scene;
Vector<Object *> objects;
LukasTonne marked this conversation as resolved
Review

Might as well just use Object * instead of adding a new struct, that can be easily changed later if necessary.

Might as well just use `Object *` instead of adding a new struct, that can be easily changed later if necessary.
int start_frame;
int end_frame;
};
static void calculate_simulation_job_startjob(void *customdata,
bool *stop,
bool *do_update,
float *progress)
{
using namespace bke::sim;
CalculateSimulationJob &job = *static_cast<CalculateSimulationJob *>(customdata);
G.is_rendering = true;
G.is_break = false;
WM_set_locked_interface(job.wm, true);
Vector<Object *> objects_to_calc;
for (Object *object : job.objects) {
if (!BKE_id_is_editable(job.bmain, &object->id)) {
continue;
}
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Nodes) {
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (nmd->simulation_cache != nullptr) {
nmd->simulation_cache->reset();
}
}
}
objects_to_calc.append(object);
}
*progress = 0.0f;
*do_update = true;
const float frame_step_size = 1.0f;
const float progress_per_frame = 1.0f /
(float(job.end_frame - job.start_frame + 1) / frame_step_size);
const int old_frame = job.scene->r.cfra;
for (float frame_f = job.start_frame; frame_f <= job.end_frame; frame_f += frame_step_size) {
const SubFrame frame{frame_f};
if (G.is_break || (stop != nullptr && *stop)) {
break;
}
job.scene->r.cfra = frame.frame();
job.scene->r.subframe = frame.subframe();
BKE_scene_graph_update_for_newframe(job.depsgraph);
*progress += progress_per_frame;
*do_update = true;
}
job.scene->r.cfra = old_frame;
DEG_time_tag_update(job.bmain);
*progress = 1.0f;
*do_update = true;
}
static void calculate_simulation_job_endjob(void *customdata)
{
CalculateSimulationJob &job = *static_cast<CalculateSimulationJob *>(customdata);
WM_set_locked_interface(job.wm, false);
G.is_rendering = false;
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, nullptr);
}
static int calculate_to_frame_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Main *bmain = CTX_data_main(C);
CalculateSimulationJob *job = MEM_new<CalculateSimulationJob>(__func__);
job->wm = wm;
job->bmain = bmain;
job->depsgraph = depsgraph;
job->scene = scene;
job->start_frame = scene->r.sfra;
job->end_frame = scene->r.cfra;
if (RNA_boolean_get(op->ptr, "selected")) {
CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
job->objects.append(object);
}
CTX_DATA_END;
}
else {
if (Object *object = CTX_data_active_object(C)) {
job->objects.append(object);
}
}
wmJob *wm_job = WM_jobs_get(wm,
CTX_wm_window(C),
CTX_data_scene(C),
"Bake Simulation Nodes",
WM_JOB_PROGRESS,
WM_JOB_TYPE_CALCULATE_SIMULATION_NODES);
WM_jobs_customdata_set(
wm_job, job, [](void *job) { MEM_delete(static_cast<CalculateSimulationJob *>(job)); });
WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
WM_jobs_callbacks(wm_job,
calculate_simulation_job_startjob,
nullptr,
nullptr,
calculate_simulation_job_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int calculate_to_frame_modal(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
{
if (!WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_CALCULATE_SIMULATION_NODES))
{
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
return OPERATOR_PASS_THROUGH;
}
static bool bake_simulation_poll(bContext *C)
{
if (!ED_operator_object_active(C)) {
@ -315,6 +457,26 @@ static int delete_baked_simulation_exec(bContext *C, wmOperator *op)
} // namespace blender::ed::object::bake_simulation
void OBJECT_OT_simulation_nodes_cache_calculate_to_frame(wmOperatorType *ot)
{
using namespace blender::ed::object::bake_simulation;
ot->name = "Calculate Simulation to Frame";
ot->description =
"Calculate simulations in geometry nodes modifiers from the start to current frame";
ot->idname = __func__;
ot->invoke = calculate_to_frame_invoke;
ot->modal = calculate_to_frame_modal;
ot->poll = calculate_to_frame_poll;
RNA_def_boolean(ot->srna,
"selected",
false,
"Selected",
"Calculate all selected objects instead of just the active object");

from start -> from the start

`from start` -> `from the start`
}
void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot)
{
using namespace blender::ed::object::bake_simulation;

View File

@ -340,6 +340,7 @@ void OBJECT_OT_bake(wmOperatorType *ot);
/* object_bake_simulation.cc */
void OBJECT_OT_simulation_nodes_cache_calculate_to_frame(wmOperatorType *ot);
void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot);
void OBJECT_OT_simulation_nodes_cache_delete(wmOperatorType *ot);

View File

@ -260,6 +260,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_bake_image);
WM_operatortype_append(OBJECT_OT_bake);
WM_operatortype_append(OBJECT_OT_simulation_nodes_cache_calculate_to_frame);
WM_operatortype_append(OBJECT_OT_simulation_nodes_cache_bake);
WM_operatortype_append(OBJECT_OT_simulation_nodes_cache_delete);
WM_operatortype_append(OBJECT_OT_drop_named_material);

View File

@ -1516,6 +1516,7 @@ typedef enum eWM_JobType {
WM_JOB_TYPE_LINEART,
WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL,
WM_JOB_TYPE_SEQ_DRAG_DROP_PREVIEW,
WM_JOB_TYPE_CALCULATE_SIMULATION_NODES,
WM_JOB_TYPE_BAKE_SIMULATION_NODES,
/* add as needed, bake, seq proxy build
* if having hard coded values is a problem */