Fix T38801: Dupli objects with modifiers exhibit bad transform artifacts

in Blender Internal renderer.

The BI renderer applies modifiers //after// changing the obmat of the
respective object (for the first instance it encounters). Before
rB6940bf0 the original obmat (omat) was stored inside dupli object data,
which was removed in favor of local omat variables due to hackishness
and redundancy. Problem with BI is that all the obmats have to be
overridden in relation to each other to produce the correct modifier
results (here: offset object for the array modifier).

The patch restores the old (messy) behavior for BI by first overriding
**all** the obmats at once from duplis, then creating render instances,
then cleaning up.

A better solution would be to avoid these modifier hacks in BI
altogether and properly evaluate them in the original object space, but
that requires far greater changes to the old code base, and is out of
scope for bugfixing.
This commit is contained in:
Lukas Tönne 2014-02-24 18:53:35 +01:00
parent 036d35dd24
commit 188f8d0935
Notes: blender-bot 2023-02-14 11:09:42 +01:00
Referenced by issue #38801, Linked groups explode when moved/rotated
Referenced by issue #38744, Linked group object with modifier texture projector doesn't render correctly in blender internal.
1 changed files with 35 additions and 14 deletions

View File

@ -4930,6 +4930,13 @@ static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, in
}
}
/* additional data for dupli objects outside
* of the main dupli list
*/
typedef struct DupliObjectExtra {
float omat[4][4];
} DupliObjectExtra;
static void database_init_objects(Render *re, unsigned int renderlay, int nolamps, int onlyselected, Object *actob, int timeoffset)
{
Base *base;
@ -4988,20 +4995,28 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
else if ((base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->lay)) ) {
if ((ob->transflag & OB_DUPLI) && (ob->type!=OB_MBALL)) {
DupliObject *dob;
ListBase *lb;
ListBase *duplilist;
DupliObjectExtra *duplilist_extra = NULL;
int totdob, i;
/* create list of duplis generated by this object, particle
* system need to have render settings set for dupli particles */
dupli_render_particle_set(re, ob, timeoffset, 0, 1);
lb= object_duplilist(re->eval_ctx, re->scene, ob);
duplilist = object_duplilist(re->eval_ctx, re->scene, ob);
totdob = BLI_countlist(duplilist);
if (totdob > 0)
duplilist_extra = MEM_mallocN(sizeof(DupliObjectExtra) * totdob, "DupliObject extra data");
dupli_render_particle_set(re, ob, timeoffset, 0, 0);
for (dob= lb->first; dob; dob= dob->next) {
/* set dupli obmats */
for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
copy_m4_m4(duplilist_extra[i].omat, dob->ob->obmat);
copy_m4_m4(dob->ob->obmat, dob->mat);
}
for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
DupliObjectExtra *dob_extra = &duplilist_extra[i];
Object *obd= dob->ob;
float omat[4][4];
copy_m4_m4(omat, obd->obmat);
copy_m4_m4(obd->obmat, dob->mat);
/* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
if (!(obd->transflag & OB_RENDER_DUPLI) && dob->no_draw)
@ -5033,7 +5048,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay);
/* fill in instance variables for texturing */
set_dupli_tex_mat(re, obi, dob, omat);
set_dupli_tex_mat(re, obi, dob, dob_extra->omat);
if (dob->type != OB_DUPLIGROUP) {
copy_v3_v3(obi->dupliorco, dob->orco);
obi->dupliuv[0]= dob->uv[0];
@ -5059,7 +5074,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
mul_m4_m4m4(mat, re->viewmat, dob->mat);
obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay);
set_dupli_tex_mat(re, obi, dob, omat);
set_dupli_tex_mat(re, obi, dob, dob_extra->omat);
if (dob->type != OB_DUPLIGROUP) {
copy_v3_v3(obi->dupliorco, dob->orco);
obi->dupliuv[0]= dob->uv[0];
@ -5075,7 +5090,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
if (obi==NULL)
/* can't instance, just create the object */
init_render_object(re, obd, ob, dob, omat, timeoffset);
init_render_object(re, obd, ob, dob, dob_extra->omat, timeoffset);
if (dob->type != OB_DUPLIGROUP) {
obd->flag |= OB_DONE;
@ -5083,13 +5098,19 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
}
}
else
init_render_object(re, obd, ob, dob, omat, timeoffset);
copy_m4_m4(obd->obmat, omat);
init_render_object(re, obd, ob, dob, dob_extra->omat, timeoffset);
if (re->test_break(re->tbh)) break;
}
free_object_duplilist(lb);
/* restore obmats */
for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
copy_m4_m4(dob->ob->obmat, duplilist_extra[i].omat);
}
free_object_duplilist(duplilist);
if (duplilist_extra)
MEM_freeN(duplilist_extra);
if (allow_render_object(re, ob, nolamps, onlyselected, actob))
init_render_object(re, ob, NULL, NULL, NULL, timeoffset);