Fix T93784: text and curve objects have no motion blur

Previously, objects and geometries were mapped between frames
using different hash tables in a way that is incompatible with
geometry instances. That is because the geometry mapping happened
without looking at the `persistent_id` of instances, which is not possible
anymore. Now, there is just one mapping that identifies the same
object at multiple points in time.

There are also two new caches for duplicated vbos and textures used for
motion blur. This data has to be duplicated, otherwise it would be freed
when another time step is evaluated. This caching existed before, but is
now a bit more explicit and works for geometry instances as well.

Differential Revision: https://developer.blender.org/D13497
This commit is contained in:
Jacques Lucke 2022-02-22 13:52:15 +01:00
parent 0ad4d2694b
commit 4e78a7360e
Notes: blender-bot 2023-02-13 16:53:34 +01:00
Referenced by issue #97380, Weird motionblur on curves in Eevee
Referenced by issue #96572, Stereoscopy with Motion Blur crashes in Eevee
Referenced by issue #93784, [EEVEE] Blender 3.0 - Bug : Text objects AND CURVE objects have no motion blur.
5 changed files with 228 additions and 211 deletions

View File

@ -42,25 +42,12 @@
static void eevee_motion_blur_mesh_data_free(void *val)
{
EEVEE_GeometryMotionData *geom_mb = (EEVEE_GeometryMotionData *)val;
EEVEE_HairMotionData *hair_mb = (EEVEE_HairMotionData *)val;
switch (geom_mb->type) {
case EEVEE_MOTION_DATA_HAIR:
for (int j = 0; j < hair_mb->psys_len; j++) {
for (int i = 0; i < ARRAY_SIZE(hair_mb->psys[0].hair_pos); i++) {
GPU_VERTBUF_DISCARD_SAFE(hair_mb->psys[j].hair_pos[i]);
}
for (int i = 0; i < ARRAY_SIZE(hair_mb->psys[0].hair_pos); i++) {
DRW_TEXTURE_FREE_SAFE(hair_mb->psys[j].hair_pos_tx[i]);
}
}
break;
case EEVEE_MOTION_DATA_MESH:
for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) {
GPU_VERTBUF_DISCARD_SAFE(geom_mb->vbo[i]);
}
break;
EEVEE_ObjectMotionData *mb_data = (EEVEE_ObjectMotionData *)val;
if (mb_data->hair_data != NULL) {
MEM_freeN(mb_data->hair_data);
}
if (mb_data->geometry_data != NULL) {
MEM_freeN(mb_data->geometry_data);
}
MEM_freeN(val);
}
@ -99,39 +86,57 @@ static bool eevee_object_key_cmp(const void *a, const void *b)
return false;
}
void EEVEE_motion_hair_step_free(EEVEE_HairMotionStepData *step_data)
{
GPU_vertbuf_discard(step_data->hair_pos);
DRW_texture_free(step_data->hair_pos_tx);
MEM_freeN(step_data);
}
void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb)
{
if (mb->object == NULL) {
mb->object = BLI_ghash_new(eevee_object_key_hash, eevee_object_key_cmp, "EEVEE Object Motion");
}
if (mb->geom == NULL) {
mb->geom = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE Mesh Motion");
for (int i = 0; i < 2; i++) {
if (mb->position_vbo_cache[i] == NULL) {
mb->position_vbo_cache[i] = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE duplicate vbo cache");
}
if (mb->hair_motion_step_cache[i] == NULL) {
mb->hair_motion_step_cache[i] = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE hair motion step cache");
}
}
}
void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb)
{
if (mb->object) {
BLI_ghash_free(mb->object, MEM_freeN, MEM_freeN);
BLI_ghash_free(mb->object, MEM_freeN, eevee_motion_blur_mesh_data_free);
mb->object = NULL;
}
if (mb->geom) {
BLI_ghash_free(mb->geom, NULL, eevee_motion_blur_mesh_data_free);
mb->geom = NULL;
for (int i = 0; i < 2; i++) {
if (mb->position_vbo_cache[i]) {
BLI_ghash_free(mb->position_vbo_cache[i], NULL, (GHashValFreeFP)GPU_vertbuf_discard);
}
if (mb->hair_motion_step_cache[i]) {
BLI_ghash_free(
mb->hair_motion_step_cache[i], NULL, (GHashValFreeFP)EEVEE_motion_hair_step_free);
}
}
}
EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb,
Object *ob,
bool hair)
EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob)
{
if (mb->object == NULL) {
return NULL;
}
EEVEE_ObjectKey key, *key_p;
/* Small hack to avoid another comparison. */
key.ob = (Object *)((char *)ob + hair);
/* Assumes that all instances have the same object pointer. This is currently the case because
* instance objects are temporary objects on the stack. */
key.ob = ob;
DupliObject *dup = DRW_object_get_dupli(ob);
if (dup) {
key.parent = DRW_object_get_dupli_parent(ob);
@ -154,53 +159,28 @@ EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *
return ob_step;
}
static void *motion_blur_deform_data_get(EEVEE_MotionBlurData *mb, Object *ob, bool hair)
EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_ObjectMotionData *mb_data)
{
if (mb->geom == NULL) {
return NULL;
if (mb_data->geometry_data == NULL) {
EEVEE_GeometryMotionData *geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__);
geom_step->type = EEVEE_MOTION_DATA_MESH;
mb_data->geometry_data = geom_step;
}
DupliObject *dup = DRW_object_get_dupli(ob);
void *key;
if (dup) {
key = dup->ob;
}
else {
key = ob;
}
/* Only use data for object that have no modifiers. */
if (!BKE_object_is_modified(DRW_context_state_get()->scene, ob)) {
key = ob->data;
}
key = (char *)key + (int)hair;
EEVEE_GeometryMotionData *geom_step = BLI_ghash_lookup(mb->geom, key);
if (geom_step == NULL) {
if (hair) {
EEVEE_HairMotionData *hair_step;
/* Ugly, we allocate for each modifiers and just fill based on modifier index in the list. */
int psys_len = (ob->type != OB_HAIR) ? BLI_listbase_count(&ob->modifiers) : 1;
hair_step = MEM_callocN(sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len,
__func__);
hair_step->psys_len = psys_len;
geom_step = (EEVEE_GeometryMotionData *)hair_step;
geom_step->type = EEVEE_MOTION_DATA_HAIR;
}
else {
geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__);
geom_step->type = EEVEE_MOTION_DATA_MESH;
}
BLI_ghash_insert(mb->geom, key, geom_step);
}
return geom_step;
return mb_data->geometry_data;
}
EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, Object *ob)
EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb_data, Object *ob)
{
return motion_blur_deform_data_get(mb, ob, false);
}
EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, Object *ob)
{
return motion_blur_deform_data_get(mb, ob, true);
if (mb_data->hair_data == NULL) {
/* Ugly, we allocate for each modifiers and just fill based on modifier index in the list. */
int psys_len = (ob->type != OB_HAIR) ? BLI_listbase_count(&ob->modifiers) : 1;
EEVEE_HairMotionData *hair_step = MEM_callocN(
sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len, __func__);
hair_step->psys_len = psys_len;
hair_step->type = EEVEE_MOTION_DATA_HAIR;
mb_data->hair_data = hair_step;
}
return mb_data->hair_data;
}
/* View Layer data. */

View File

@ -241,15 +241,14 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
}
/* For now we assume hair objects are always moving. */
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
&effects->motion_blur, ob, true);
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
if (mb_data) {
int mb_step = effects->motion_blur_step;
/* Store transform. */
DRW_hair_duplimat_get(ob, psys, md, mb_data->obmat[mb_step]);
EEVEE_HairMotionData *mb_hair = EEVEE_motion_blur_hair_data_get(&effects->motion_blur, ob);
EEVEE_HairMotionData *mb_hair = EEVEE_motion_blur_hair_data_get(mb_data, ob);
int psys_id = (md != NULL) ? BLI_findindex(&ob->modifiers, md) : 0;
if (psys_id >= mb_hair->psys_len) {
@ -267,8 +266,8 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]);
}
GPUTexture *tex_prev = mb_hair->psys[psys_id].hair_pos_tx[MB_PREV];
GPUTexture *tex_next = mb_hair->psys[psys_id].hair_pos_tx[MB_NEXT];
GPUTexture *tex_prev = mb_hair->psys[psys_id].step_data[MB_PREV].hair_pos_tx;
GPUTexture *tex_next = mb_hair->psys[psys_id].step_data[MB_NEXT].hair_pos_tx;
grp = DRW_shgroup_hair_create_sub(ob, psys, md, effects->motion_blur.hair_grp, NULL);
DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]);
@ -280,7 +279,7 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
}
else {
/* Store vertex position buffer. */
mb_hair->psys[psys_id].hair_pos[mb_step] = DRW_hair_pos_buffer_get(ob, psys, md);
mb_hair->psys[psys_id].step_data[mb_step].hair_pos = DRW_hair_pos_buffer_get(ob, psys, md);
mb_hair->use_deform = true;
}
}
@ -319,24 +318,14 @@ void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
return;
}
const DupliObject *dup = DRW_object_get_dupli(ob);
if (dup != NULL && dup->ob->data != dup->ob_data) {
/* Geometry instances do not support motion blur correctly yet. The #key used in
* #motion_blur_deform_data_get has to take ids of instances (#DupliObject.persistent_id) into
* account. Otherwise it can't find matching geometry instances at different points in time. */
return;
}
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(
&effects->motion_blur, ob, false);
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
if (mb_data) {
int mb_step = effects->motion_blur_step;
/* Store transform. */
copy_m4_m4(mb_data->obmat[mb_step], ob->obmat);
EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get(&effects->motion_blur,
ob);
EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get(mb_data);
if (mb_step == MB_CURR) {
GPUBatch *batch = DRW_cache_object_surface_get(ob);
@ -422,86 +411,93 @@ void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata)
DRW_cache_restart();
}
for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom);
for (BLI_ghashIterator_init(&ghi, effects->motion_blur.object);
BLI_ghashIterator_done(&ghi) == false;
BLI_ghashIterator_step(&ghi)) {
EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi);
EEVEE_HairMotionData *mb_hair = (EEVEE_HairMotionData *)mb_geom;
if (!mb_geom->use_deform) {
continue;
}
switch (mb_geom->type) {
case EEVEE_MOTION_DATA_HAIR:
if (mb_step == MB_CURR) {
/* TODO(fclem): Check if vertex count mismatch. */
mb_hair->use_deform = true;
}
else {
for (int i = 0; i < mb_hair->psys_len; i++) {
if (mb_hair->psys[i].hair_pos[mb_step] == NULL) {
continue;
}
mb_hair->psys[i].hair_pos[mb_step] = GPU_vertbuf_duplicate(
mb_hair->psys[i].hair_pos[mb_step]);
/* Create vbo immediately to bind to texture buffer. */
GPU_vertbuf_use(mb_hair->psys[i].hair_pos[mb_step]);
mb_hair->psys[i].hair_pos_tx[mb_step] = GPU_texture_create_from_vertbuf(
"hair_pos_motion_blur", mb_hair->psys[i].hair_pos[mb_step]);
EEVEE_ObjectMotionData *mb_data = BLI_ghashIterator_getValue(&ghi);
EEVEE_HairMotionData *mb_hair = mb_data->hair_data;
EEVEE_GeometryMotionData *mb_geom = mb_data->geometry_data;
if (mb_hair != NULL && mb_hair->use_deform) {
if (mb_step == MB_CURR) {
/* TODO(fclem): Check if vertex count mismatch. */
mb_hair->use_deform = true;
}
else {
for (int i = 0; i < mb_hair->psys_len; i++) {
GPUVertBuf *vbo = mb_hair->psys[i].step_data[mb_step].hair_pos;
if (vbo == NULL) {
continue;
}
EEVEE_HairMotionStepData **step_data_cache_ptr;
if (!BLI_ghash_ensure_p(effects->motion_blur.hair_motion_step_cache[mb_step],
vbo,
(void ***)&step_data_cache_ptr)) {
EEVEE_HairMotionStepData *new_step_data = MEM_callocN(sizeof(EEVEE_HairMotionStepData),
__func__);
/* Duplicate the vbo, otherwise it would be lost when evaluating another frame. */
new_step_data->hair_pos = GPU_vertbuf_duplicate(vbo);
/* Create vbo immediately to bind to texture buffer. */
GPU_vertbuf_use(new_step_data->hair_pos);
new_step_data->hair_pos_tx = GPU_texture_create_from_vertbuf("hair_pos_motion_blur",
new_step_data->hair_pos);
*step_data_cache_ptr = new_step_data;
}
mb_hair->psys[i].step_data[mb_step] = **step_data_cache_ptr;
}
break;
case EEVEE_MOTION_DATA_MESH:
if (mb_step == MB_CURR) {
/* Modify batch to have data from adjacent frames. */
GPUBatch *batch = mb_geom->batch;
for (int i = 0; i < MB_CURR; i++) {
GPUVertBuf *vbo = mb_geom->vbo[i];
if (vbo && batch) {
if (GPU_vertbuf_get_vertex_len(vbo) != GPU_vertbuf_get_vertex_len(batch->verts[0])) {
/* Vertex count mismatch, disable deform motion blur. */
mb_geom->use_deform = false;
}
if (mb_geom->use_deform == false) {
motion_blur_remove_vbo_reference_from_batch(
batch, mb_geom->vbo[MB_PREV], mb_geom->vbo[MB_NEXT]);
GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]);
GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]);
break;
}
}
}
if (mb_geom != NULL && mb_geom->use_deform) {
if (mb_step == MB_CURR) {
/* Modify batch to have data from adjacent frames. */
GPUBatch *batch = mb_geom->batch;
for (int i = 0; i < MB_CURR; i++) {
GPUVertBuf *vbo = mb_geom->vbo[i];
if (vbo && batch) {
if (GPU_vertbuf_get_vertex_len(vbo) != GPU_vertbuf_get_vertex_len(batch->verts[0])) {
/* Vertex count mismatch, disable deform motion blur. */
mb_geom->use_deform = false;
}
if (mb_geom->use_deform == false) {
motion_blur_remove_vbo_reference_from_batch(
batch, mb_geom->vbo[MB_PREV], mb_geom->vbo[MB_NEXT]);
break;
}
/* Avoid adding the same vbo more than once when the batch is used by multiple
* instances. */
if (!GPU_batch_vertbuf_has(batch, vbo)) {
/* Currently, the code assumes that all objects that share the same mesh in the
* current frame also share the same mesh on other frames. */
GPU_batch_vertbuf_add_ex(batch, vbo, false);
}
}
}
else {
GPUVertBuf *vbo = mb_geom->vbo[mb_step];
if (vbo) {
/* Use the vbo to perform the copy on the GPU. */
GPU_vertbuf_use(vbo);
/* Perform a copy to avoid losing it after RE_engine_frame_set(). */
mb_geom->vbo[mb_step] = vbo = GPU_vertbuf_duplicate(vbo);
}
else {
GPUVertBuf *vbo = mb_geom->vbo[mb_step];
if (vbo) {
/* Use the vbo to perform the copy on the GPU. */
GPU_vertbuf_use(vbo);
/* Perform a copy to avoid losing it after RE_engine_frame_set(). */
GPUVertBuf **vbo_cache_ptr;
if (!BLI_ghash_ensure_p(effects->motion_blur.position_vbo_cache[mb_step],
vbo,
(void ***)&vbo_cache_ptr)) {
/* Duplicate the vbo, otherwise it would be lost when evaluating another frame. */
GPUVertBuf *duplicated_vbo = GPU_vertbuf_duplicate(vbo);
*vbo_cache_ptr = duplicated_vbo;
/* Find and replace "pos" attrib name. */
GPUVertFormat *format = (GPUVertFormat *)GPU_vertbuf_get_format(vbo);
GPUVertFormat *format = (GPUVertFormat *)GPU_vertbuf_get_format(duplicated_vbo);
int attrib_id = GPU_vertformat_attr_id_get(format, "pos");
GPU_vertformat_attr_rename(format, attrib_id, (mb_step == MB_PREV) ? "prv" : "nxt");
}
else {
/* This might happen if the object visibility has been animated. */
mb_geom->use_deform = false;
}
mb_geom->vbo[mb_step] = vbo = *vbo_cache_ptr;
}
break;
default:
BLI_assert(0);
break;
else {
/* This might happen if the object visibility has been animated. */
mb_geom->use_deform = false;
}
}
}
}
}
@ -518,54 +514,62 @@ void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata)
/* Camera Data. */
effects->motion_blur.camera[MB_PREV] = effects->motion_blur.camera[MB_NEXT];
/* Object Data. */
for (BLI_ghashIterator_init(&ghi, effects->motion_blur.object);
BLI_ghashIterator_done(&ghi) == false;
BLI_ghashIterator_step(&ghi)) {
EEVEE_ObjectMotionData *mb_data = BLI_ghashIterator_getValue(&ghi);
/* Swap #position_vbo_cache pointers. */
if (effects->motion_blur.position_vbo_cache[MB_PREV]) {
BLI_ghash_free(effects->motion_blur.position_vbo_cache[MB_PREV],
NULL,
(GHashValFreeFP)GPU_vertbuf_discard);
}
effects->motion_blur.position_vbo_cache[MB_PREV] =
effects->motion_blur.position_vbo_cache[MB_NEXT];
effects->motion_blur.position_vbo_cache[MB_NEXT] = NULL;
copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_NEXT]);
/* Swap #hair_motion_step_cache pointers. */
if (effects->motion_blur.hair_motion_step_cache[MB_PREV]) {
BLI_ghash_free(effects->motion_blur.hair_motion_step_cache[MB_PREV],
NULL,
(GHashValFreeFP)EEVEE_motion_hair_step_free);
}
effects->motion_blur.hair_motion_step_cache[MB_PREV] =
effects->motion_blur.hair_motion_step_cache[MB_NEXT];
effects->motion_blur.hair_motion_step_cache[MB_NEXT] = NULL;
/* Rename attributes in #position_vbo_cache. */
for (BLI_ghashIterator_init(&ghi, effects->motion_blur.position_vbo_cache[MB_PREV]);
!BLI_ghashIterator_done(&ghi);
BLI_ghashIterator_step(&ghi)) {
GPUVertBuf *vbo = BLI_ghashIterator_getValue(&ghi);
GPUVertFormat *format = (GPUVertFormat *)GPU_vertbuf_get_format(vbo);
int attrib_id = GPU_vertformat_attr_id_get(format, "nxt");
GPU_vertformat_attr_rename(format, attrib_id, "prv");
}
/* Deformation Data. */
for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom);
BLI_ghashIterator_done(&ghi) == false;
/* Object Data. */
for (BLI_ghashIterator_init(&ghi, effects->motion_blur.object); !BLI_ghashIterator_done(&ghi);
BLI_ghashIterator_step(&ghi)) {
EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi);
EEVEE_HairMotionData *mb_hair = (EEVEE_HairMotionData *)mb_geom;
EEVEE_ObjectMotionData *mb_data = BLI_ghashIterator_getValue(&ghi);
EEVEE_GeometryMotionData *mb_geom = mb_data->geometry_data;
EEVEE_HairMotionData *mb_hair = mb_data->hair_data;
switch (mb_geom->type) {
case EEVEE_MOTION_DATA_HAIR:
for (int i = 0; i < mb_hair->psys_len; i++) {
GPU_VERTBUF_DISCARD_SAFE(mb_hair->psys[i].hair_pos[MB_PREV]);
DRW_TEXTURE_FREE_SAFE(mb_hair->psys[i].hair_pos_tx[MB_PREV]);
mb_hair->psys[i].hair_pos[MB_PREV] = mb_hair->psys[i].hair_pos[MB_NEXT];
mb_hair->psys[i].hair_pos_tx[MB_PREV] = mb_hair->psys[i].hair_pos_tx[MB_NEXT];
mb_hair->psys[i].hair_pos[MB_NEXT] = NULL;
mb_hair->psys[i].hair_pos_tx[MB_NEXT] = NULL;
}
break;
copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_NEXT]);
case EEVEE_MOTION_DATA_MESH:
if (mb_geom->batch != NULL) {
motion_blur_remove_vbo_reference_from_batch(
mb_geom->batch, mb_geom->vbo[MB_PREV], mb_geom->vbo[MB_NEXT]);
}
GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]);
mb_geom->vbo[MB_PREV] = mb_geom->vbo[MB_NEXT];
mb_geom->vbo[MB_NEXT] = NULL;
if (mb_geom->vbo[MB_PREV]) {
GPUVertBuf *vbo = mb_geom->vbo[MB_PREV];
GPUVertFormat *format = (GPUVertFormat *)GPU_vertbuf_get_format(vbo);
int attrib_id = GPU_vertformat_attr_id_get(format, "nxt");
GPU_vertformat_attr_rename(format, attrib_id, "prv");
}
break;
default:
BLI_assert(0);
break;
if (mb_hair != NULL) {
for (int i = 0; i < mb_hair->psys_len; i++) {
mb_hair->psys[i].step_data[MB_PREV].hair_pos =
mb_hair->psys[i].step_data[MB_NEXT].hair_pos;
mb_hair->psys[i].step_data[MB_PREV].hair_pos_tx =
mb_hair->psys[i].step_data[MB_NEXT].hair_pos_tx;
mb_hair->psys[i].step_data[MB_NEXT].hair_pos = NULL;
mb_hair->psys[i].step_data[MB_NEXT].hair_pos_tx = NULL;
}
}
if (mb_geom != NULL) {
if (mb_geom->batch != NULL) {
motion_blur_remove_vbo_reference_from_batch(
mb_geom->batch, mb_geom->vbo[MB_PREV], mb_geom->vbo[MB_NEXT]);
}
mb_geom->vbo[MB_PREV] = mb_geom->vbo[MB_NEXT];
mb_geom->vbo[MB_NEXT] = NULL;
}
}
}

View File

@ -633,8 +633,23 @@ enum {
#define MB_CURR 2
typedef struct EEVEE_MotionBlurData {
/**
* Maps #EEVEE_ObjectKey to #EEVEE_ObjectMotionData.
*/
struct GHash *object;
struct GHash *geom;
/**
* Maps original #GPUVertBuf to duplicated #GPUVertBuf.
* There are two maps for #MB_PREV and #MB_NEXT.
* Only the values are owned.
*/
struct GHash *position_vbo_cache[2];
/**
* Maps original #GPUVertBuf to #EEVEE_HairMotionStepData.
* There are two maps for #MB_PREV and #MB_NEXT.
* Only the values are owned.
*/
struct GHash *hair_motion_step_cache[2];
struct {
float viewmat[4][4];
float persmat[4][4];
@ -652,15 +667,16 @@ typedef struct EEVEE_ObjectKey {
int id[8]; /* MAX_DUPLI_RECUR */
} EEVEE_ObjectKey;
typedef struct EEVEE_ObjectMotionData {
float obmat[3][4][4];
} EEVEE_ObjectMotionData;
typedef enum eEEVEEMotionData {
EEVEE_MOTION_DATA_MESH = 0,
EEVEE_MOTION_DATA_HAIR,
} eEEVEEMotionData;
typedef struct EEVEE_HairMotionStepData {
struct GPUVertBuf *hair_pos;
struct GPUTexture *hair_pos_tx;
} EEVEE_HairMotionStepData;
typedef struct EEVEE_HairMotionData {
/** Needs to be first to ensure casting. */
eEEVEEMotionData type;
@ -668,8 +684,8 @@ typedef struct EEVEE_HairMotionData {
/** Allocator will alloc enough slot for all particle systems. Or 1 if it's a hair object. */
int psys_len;
struct {
struct GPUVertBuf *hair_pos[2]; /* Position buffer for time = t +/- step. */
struct GPUTexture *hair_pos_tx[2]; /* Buffer Texture of the corresponding VBO. */
/* The vbos and textures are not owned. */
EEVEE_HairMotionStepData step_data[2]; /* Data for time = t +/- step. */
} psys[0];
} EEVEE_HairMotionData;
@ -679,10 +695,18 @@ typedef struct EEVEE_GeometryMotionData {
/** To disable deform mb if vertcount mismatch. */
int use_deform;
/* The batch and vbos are not owned. */
struct GPUBatch *batch; /* Batch for time = t. */
struct GPUVertBuf *vbo[2]; /* VBO for time = t +/- step. */
} EEVEE_GeometryMotionData;
typedef struct EEVEE_ObjectMotionData {
float obmat[3][4][4];
EEVEE_GeometryMotionData *geometry_data;
EEVEE_HairMotionData *hair_data;
} EEVEE_ObjectMotionData;
/* ************ EFFECTS DATA ************* */
typedef enum EEVEE_EffectsFlag {
@ -1077,17 +1101,15 @@ typedef struct EEVEE_PrivateData {
void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb);
void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb);
void EEVEE_view_layer_data_free(void *storage);
void EEVEE_motion_hair_step_free(EEVEE_HairMotionStepData *step_data);
EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void);
EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer);
EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void);
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob);
EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb,
Object *ob,
bool hair);
EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb,
Object *ob);
EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_MotionBlurData *mb, Object *ob);
EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, Object *ob);
EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_ObjectMotionData *mb_data);
EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb_data, Object *ob);
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob);
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob);
EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob);

View File

@ -135,6 +135,7 @@ int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
* Returns the index of verts in the batch.
*/
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo);
bool GPU_batch_vertbuf_has(GPUBatch *, GPUVertBuf *);
#define GPU_batch_vertbuf_add(batch, verts) GPU_batch_vertbuf_add_ex(batch, verts, false)

View File

@ -207,6 +207,16 @@ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo)
return -1;
}
bool GPU_batch_vertbuf_has(GPUBatch *batch, GPUVertBuf *verts)
{
for (uint v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
if (batch->verts[v] == verts) {
return true;
}
}
return false;
}
/** \} */
/* -------------------------------------------------------------------- */