rigidbody: Add point cache support

Add read/write/interpolate functions.

In order to get rigid body point cache id from object it's now required to pass the
scene to BKE_ptcache_ids_from_object().

Rigid body cache is drawn in the orange color of the bullet logo.
This commit is contained in:
Sergej Reich 2013-01-23 05:56:34 +00:00
parent fc377c17e3
commit 089cf12435
12 changed files with 190 additions and 5 deletions

@ -152,6 +152,7 @@ class TIME_MT_cache(Menu):
col.prop(st, "cache_cloth")
col.prop(st, "cache_smoke")
col.prop(st, "cache_dynamicpaint")
col.prop(st, "cache_rigidbody")
class TIME_MT_frame(Menu):

@ -67,6 +67,7 @@
#define PTCACHE_TYPE_SMOKE_DOMAIN 3
#define PTCACHE_TYPE_SMOKE_HIGHRES 4
#define PTCACHE_TYPE_DYNAMICPAINT 5
#define PTCACHE_TYPE_RIGIDBODY 6
/* high bits reserved for flags that need to be stored in file */
#define PTCACHE_TYPEFLAG_COMPRESS (1 << 16)
@ -91,6 +92,7 @@ struct PointCache;
struct Scene;
struct SmokeModifierData;
struct SoftBody;
struct RigidBodyWorld;
/* temp structure for read/write */
typedef struct PTCacheData {
@ -260,6 +262,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct Par
void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd);
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd);
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);

@ -43,6 +43,7 @@
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_particle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_smoke_types.h"
@ -72,6 +73,8 @@
#include "BIK_api.h"
#include "RBI_api.h"
/* both in intern */
#ifdef WITH_SMOKE
#include "smoke_API.h"
@ -867,6 +870,97 @@ static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
return 1;
}
/* Rigid Body functions */
static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSED(cfra))
{
RigidBodyWorld *rbw = rb_v;
Object *ob = NULL;
if (rbw->objects)
ob = rbw->objects[index];
if (ob && ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo->type == RBO_TYPE_ACTIVE) {
RB_body_get_position(rbo->physics_object, rbo->pos);
RB_body_get_orientation(rbo->physics_object, rbo->orn);
PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
}
}
return 1;
}
static void ptcache_rigidbody_read(int index, void *rb_v, void **data, float UNUSED(cfra), float *old_data)
{
RigidBodyWorld *rbw = rb_v;
Object *ob = NULL;
if (rbw->objects)
ob = rbw->objects[index];
if (ob && ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo->type == RBO_TYPE_ACTIVE) {
if (old_data) {
memcpy(rbo->pos, data, 3 * sizeof(float));
memcpy(rbo->orn, data + 3, 4 * sizeof(float));
}
else {
PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, rbo->pos);
PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, 0, rbo->orn);
}
}
}
}
static void ptcache_rigidbody_interpolate(int index, void *rb_v, void **data, float cfra, float cfra1, float cfra2, float *old_data)
{
RigidBodyWorld *rbw = rb_v;
Object *ob = NULL;
ParticleKey keys[4];
float dfra;
if (rbw->objects)
ob = rbw->objects[index];
if (ob && ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo->type == RBO_TYPE_ACTIVE) {
copy_v3_v3(keys[1].co, rbo->pos);
copy_v3_v3(keys[1].rot, rbo->orn);
if (old_data) {
memcpy(keys[2].co, data, 3 * sizeof(float));
memcpy(keys[2].rot, data + 3, 4 * sizeof(float));
}
else {
BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
}
dfra = cfra2 - cfra1;
psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1);
interp_qt_qtqt(keys->rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
copy_v3_v3(rbo->pos, keys->co);
copy_v3_v3(rbo->orn, keys->rot);
}
}
}
static int ptcache_rigidbody_totpoint(void *rb_v, int UNUSED(cfra))
{
RigidBodyWorld *rbw = rb_v;
return rbw->numbodies;
}
/* Creating ID's */
void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
{
@ -1072,6 +1166,42 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
pid->max_step = 1;
}
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw)
{
memset(pid, 0, sizeof(PTCacheID));
pid->ob= ob;
pid->calldata= rbw;
pid->type= PTCACHE_TYPE_RIGIDBODY;
pid->cache= rbw->pointcache;
pid->cache_ptr= &rbw->pointcache;
pid->ptcaches= &rbw->ptcaches;
pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint;
pid->write_point = ptcache_rigidbody_write;
pid->read_point = ptcache_rigidbody_read;
pid->interpolate_point = ptcache_rigidbody_interpolate;
pid->write_stream = NULL;
pid->read_stream = NULL;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
pid->write_header = ptcache_basic_header_write;
pid->read_header = ptcache_basic_header_read;
pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_ROTATION);
pid->info_types= 0;
pid->stack_index = pid->cache->index;
pid->default_step = 1;
pid->max_step = 1;
}
void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
{
PTCacheID *pid;
@ -1133,6 +1263,12 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
}
}
}
if (scene && ob->rigidbody_object && scene->rigidbody_world) {
pid = MEM_callocN(sizeof(PTCacheID), "PTCacheID");
BKE_ptcache_id_from_rigidbody(pid, ob, scene->rigidbody_world);
BLI_addtail(lb, pid);
}
if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
ListBase *lb_dupli_ob;
@ -2641,6 +2777,14 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
}
}
if (scene->rigidbody_world && ob->rigidbody_object) {
if (ob->rigidbody_object)
ob->rigidbody_object->flag |= RBO_FLAG_NEEDS_RESHAPE;
BKE_ptcache_id_from_rigidbody(&pid, ob, scene->rigidbody_world);
/* only flag as outdated, resetting should happen on start frame */
pid.cache->flag |= PTCACHE_OUTDATED;
}
if (ob->type == OB_ARMATURE)
BIK_clear_cache(ob->pose);

@ -97,6 +97,10 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
if (rbw->objects)
free(rbw->objects);
/* free cache */
BKE_ptcache_free_list(&(rbw->ptcaches));
rbw->pointcache = NULL;
/* free effector weights */
if (rbw->effector_weights)
MEM_freeN(rbw->effector_weights);
@ -472,6 +476,9 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
rbw->steps_per_second = 60; /* Bullet default (60 Hz) */
rbw->num_solver_iterations = 10; /* 10 is bullet default */
rbw->pointcache = BKE_ptcache_add(&(rbw->ptcaches));
rbw->pointcache->step = 1;
/* return this sim world */
return rbw;
}
@ -749,7 +756,8 @@ void BKE_rigidbody_sync_transforms(Scene *scene, Object *ob, float ctime)
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
{
// RB_TODO implement this
if (rbw)
rbw->pointcache->flag |= PTCACHE_OUTDATED;
}
/* ------------------ */

@ -5303,6 +5303,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
rbw->effector_weights = newdataadr(fd, rbw->effector_weights);
if (!rbw->effector_weights)
rbw->effector_weights = BKE_add_effector_weights(NULL);
/* link cache */
direct_link_pointcache_list(fd, &rbw->ptcaches, &rbw->pointcache, FALSE);
/* make sure simulation starts from the beginning after loading file */
if (rbw->pointcache)
rbw->ltime = rbw->pointcache->startframe;
}
}

@ -2307,6 +2307,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
if (sce->rigidbody_world) {
writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
}
sce= sce->id.next;

@ -376,7 +376,7 @@ void ED_object_exit_editmode(bContext *C, int flag)
scene->obedit = NULL; // XXX for context
/* flag object caches as outdated */
BKE_ptcache_ids_from_object(&pidlist, obedit, NULL, 0);
BKE_ptcache_ids_from_object(&pidlist, obedit, scene, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */
pid->cache->flag |= PTCACHE_OUTDATED;

@ -92,7 +92,7 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
#define CACHE_DRAW_HEIGHT 3.0f
static void time_draw_cache(SpaceTime *stime, Object *ob)
static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
{
PTCacheID *pid;
ListBase pidlist;
@ -102,7 +102,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob)
if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
return;
BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
BKE_ptcache_ids_from_object(&pidlist, ob, scene, 0);
/* iterate over pointcaches on the active object,
* add spacetimecache and vertex array for each */
@ -128,6 +128,9 @@ static void time_draw_cache(SpaceTime *stime, Object *ob)
case PTCACHE_TYPE_DYNAMICPAINT:
if (!(stime->cache_display & TIME_CACHE_DYNAMICPAINT)) continue;
break;
case PTCACHE_TYPE_RIGIDBODY:
if (!(stime->cache_display & TIME_CACHE_RIGIDBODY)) continue;
break;
}
if (pid->cache->cached_frames == NULL)
@ -193,6 +196,10 @@ static void time_draw_cache(SpaceTime *stime, Object *ob)
col[0] = 1.0; col[1] = 0.1; col[2] = 0.75;
col[3] = 0.1;
break;
case PTCACHE_TYPE_RIGIDBODY:
col[0] = 1.0; col[1] = 0.6; col[2] = 0.0;
col[3] = 0.1;
break;
default:
BLI_assert(0);
col[0] = 1.0; col[1] = 0.0; col[2] = 1.0;
@ -499,7 +506,7 @@ static void time_main_area_draw(const bContext *C, ARegion *ar)
draw_markers_time(C, 0);
/* caches */
time_draw_cache(stime, obact);
time_draw_cache(stime, obact, scene);
/* reset view matrix */
UI_view2d_view_restore(C);
@ -648,6 +655,7 @@ static void time_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
stime->cache_display |= TIME_CACHE_DISPLAY;
stime->cache_display |= (TIME_CACHE_SOFTBODY | TIME_CACHE_PARTICLES);
stime->cache_display |= (TIME_CACHE_CLOTH | TIME_CACHE_SMOKE | TIME_CACHE_DYNAMICPAINT);
stime->cache_display |= TIME_CACHE_RIGIDBODY;
}
static SpaceLink *time_duplicate(SpaceLink *sl)

@ -57,6 +57,8 @@ typedef struct RigidBodyWorld {
float ltime; /* last frame world was evaluated for (internal) */
/* cache */
struct PointCache *pointcache;
struct ListBase ptcaches;
int numbodies; /* number of objects in rigid body group */
short steps_per_second; /* number of simulation steps thaken per second */

@ -447,6 +447,7 @@ typedef enum eTimeline_Cache_Flag {
TIME_CACHE_CLOTH = (1 << 3),
TIME_CACHE_SMOKE = (1 << 4),
TIME_CACHE_DYNAMICPAINT = (1 << 5),
TIME_CACHE_RIGIDBODY = (1 << 6),
} eTimeline_Cache_Flag;

@ -346,6 +346,12 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Split Impulse", "Reduces extra velocity that can build up when objects collide (lowers simulation stabilty a litte so use only when necessary)");
RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset");
/* cache */
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "pointcache");
RNA_def_property_ui_text(prop, "Point Cache", "");
/* effector weights */
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");

@ -2760,6 +2760,11 @@ static void rna_def_space_time(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_DYNAMICPAINT);
RNA_def_property_ui_text(prop, "Dynamic Paint", "Show the active object's Dynamic Paint cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
prop = RNA_def_property(srna, "cache_rigidbody", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_display", TIME_CACHE_RIGIDBODY);
RNA_def_property_ui_text(prop, "Rigid Body", "Show the active object's Rigid Body cache");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, NULL);
}
static void rna_def_console_line(BlenderRNA *brna)