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:
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.
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue