Geometry Nodes: Simulation calculate to frame operator #107627
|
@ -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
|
||||
|
|
|
@ -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
|
||||
wmWindowManager *wm;
|
||||
Main *bmain;
|
||||
Depsgraph *depsgraph;
|
||||
Scene *scene;
|
||||
Vector<Object *> objects;
|
||||
LukasTonne marked this conversation as resolved
Hans Goudey
commented
Might as well just use 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");
|
||||
}
|
||||
|
||||
void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot)
|
||||
{
|
||||
using namespace blender::ed::object::bake_simulation;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue
Unused struct here