Curves: Split curve EEVEE/workbench functions from particle hair

The GPU evaluation for curves will have to change significantly from the
current particle hair drawing code, due to its more general use cases
and support for more curve types. To simplify that process and avoid
introducing regressions for the rendering of hair particle systems,
this commit splits drawing functions for the curves object and
particle hair.

The changes are just inlining of functions and copying code
where necessary.

Differential Revision: https://developer.blender.org/D14576
This commit is contained in:
Hans Goudey 2022-04-13 22:07:31 -05:00
parent f84f9eb8ed
commit f31c3f8114
Notes: blender-bot 2023-02-14 05:50:03 +01:00
Referenced by commit 5b87862ddc, Curves: Further split of curves draw code from particles
Referenced by commit 180163c4e4, Cleanup: Further hair to curves renaming
Referenced by issue #96455, Render engine support for curves data-block
9 changed files with 237 additions and 69 deletions

View File

@ -160,7 +160,7 @@ EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb
{
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_CURVES) ? BLI_listbase_count(&ob->modifiers) : 1;
int psys_len = BLI_listbase_count(&ob->modifiers);
EEVEE_HairMotionData *hair_step = MEM_callocN(
sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]) * psys_len, __func__);
hair_step->psys_len = psys_len;
@ -170,6 +170,19 @@ EEVEE_HairMotionData *EEVEE_motion_blur_hair_data_get(EEVEE_ObjectMotionData *mb
return mb_data->hair_data;
}
EEVEE_HairMotionData *EEVEE_motion_blur_curves_data_get(EEVEE_ObjectMotionData *mb_data,
Object *ob)
{
if (mb_data->hair_data == NULL) {
EEVEE_HairMotionData *hair_step = MEM_callocN(
sizeof(EEVEE_HairMotionData) + sizeof(hair_step->psys[0]), __func__);
hair_step->psys_len = 1;
hair_step->type = EEVEE_MOTION_DATA_HAIR;
mb_data->hair_data = hair_step;
}
return mb_data->hair_data;
}
/* View Layer data. */
void EEVEE_view_layer_data_free(void *storage)

View File

@ -111,7 +111,7 @@ void EEVEE_cache_populate(void *vedata, Object *ob)
EEVEE_materials_cache_populate(vedata, sldata, ob, &cast_shadow);
}
else if (ob->type == OB_CURVES) {
EEVEE_object_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
EEVEE_object_curves_cache_populate(vedata, sldata, ob, &cast_shadow);
}
else if (ob->type == OB_VOLUME) {
EEVEE_volumes_cache_object_add(sldata, vedata, draw_ctx->scene, ob);

View File

@ -740,34 +740,6 @@ BLI_INLINE EeveeMaterialCache eevee_material_cache_get(
return matcache;
}
static void eevee_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
ParticleSystem *psys,
ModifierData *md,
int matnr,
bool *cast_shadow)
{
EeveeMaterialCache matcache = eevee_material_cache_get(vedata, sldata, ob, matnr - 1, true);
if (matcache.depth_grp) {
*matcache.depth_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.depth_grp, NULL);
DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat);
}
if (matcache.shading_grp) {
*matcache.shading_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.shading_grp, matcache.shading_gpumat);
DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat);
}
if (matcache.shadow_grp) {
*matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp, NULL);
DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat);
*cast_shadow = true;
}
EEVEE_motion_blur_hair_cache_populate(sldata, vedata, ob, psys, md);
}
#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \
do { \
if (oedata) { \
@ -899,18 +871,56 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata,
if (draw_as != PART_DRAW_PATH) {
continue;
}
eevee_hair_cache_populate(vedata, sldata, ob, psys, md, part->omat, cast_shadow);
EeveeMaterialCache matcache = eevee_material_cache_get(
vedata, sldata, ob, part->omat - 1, true);
if (matcache.depth_grp) {
*matcache.depth_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.depth_grp, NULL);
DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat);
}
if (matcache.shading_grp) {
*matcache.shading_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.shading_grp, matcache.shading_gpumat);
DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat);
}
if (matcache.shadow_grp) {
*matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(
ob, psys, md, matcache.shadow_grp, NULL);
DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat);
*cast_shadow = true;
}
EEVEE_motion_blur_hair_cache_populate(sldata, vedata, ob, psys, md);
}
}
}
}
void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
bool *cast_shadow)
void EEVEE_object_curves_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
bool *cast_shadow)
{
eevee_hair_cache_populate(vedata, sldata, ob, NULL, NULL, CURVES_MATERIAL_NR, cast_shadow);
EeveeMaterialCache matcache = eevee_material_cache_get(
vedata, sldata, ob, CURVES_MATERIAL_NR - 1, true);
if (matcache.depth_grp) {
*matcache.depth_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.depth_grp, NULL);
DRW_shgroup_add_material_resources(*matcache.depth_grp_p, matcache.shading_gpumat);
}
if (matcache.shading_grp) {
*matcache.shading_grp_p = DRW_shgroup_curves_create_sub(
ob, matcache.shading_grp, matcache.shading_gpumat);
DRW_shgroup_add_material_resources(*matcache.shading_grp_p, matcache.shading_gpumat);
}
if (matcache.shadow_grp) {
*matcache.shadow_grp_p = DRW_shgroup_curves_create_sub(ob, matcache.shadow_grp, NULL);
DRW_shgroup_add_material_resources(*matcache.shadow_grp_p, matcache.shading_gpumat);
*cast_shadow = true;
}
EEVEE_motion_blur_curves_cache_populate(sldata, vedata, ob);
}
void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)

View File

@ -270,6 +270,57 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
}
}
void EEVEE_motion_blur_curves_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
Object *ob)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
if (!DRW_state_is_scene_render() || psl->velocity_hair == NULL) {
return;
}
/* For now we assume curves objects are always moving. */
EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get(&effects->motion_blur, ob);
if (mb_data == NULL) {
return;
}
int mb_step = effects->motion_blur_step;
/* Store transform. */
copy_m4_m4(mb_data->obmat[mb_step], ob->obmat);
EEVEE_HairMotionData *mb_curves = EEVEE_motion_blur_curves_data_get(mb_data, ob);
if (mb_step == MB_CURR) {
/* Fill missing matrices if the object was hidden in previous or next frame. */
if (is_zero_m4(mb_data->obmat[MB_PREV])) {
copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]);
}
if (is_zero_m4(mb_data->obmat[MB_NEXT])) {
copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]);
}
GPUTexture *tex_prev = mb_curves->psys[0].step_data[MB_PREV].hair_pos_tx;
GPUTexture *tex_next = mb_curves->psys[0].step_data[MB_NEXT].hair_pos_tx;
DRWShadingGroup *grp = DRW_shgroup_curves_create_sub(ob, effects->motion_blur.hair_grp, NULL);
DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]);
DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]);
DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]);
DRW_shgroup_uniform_texture(grp, "prvBuffer", tex_prev);
DRW_shgroup_uniform_texture(grp, "nxtBuffer", tex_next);
DRW_shgroup_uniform_bool(grp, "useDeform", &mb_curves->use_deform, 1);
}
else {
/* Store vertex position buffer. */
mb_curves->psys[0].step_data[mb_step].hair_pos = DRW_curves_pos_buffer_get(ob);
mb_curves->use_deform = true;
}
}
void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
Object *ob)

View File

@ -1095,6 +1095,8 @@ EEVEE_ObjectEngineData *EEVEE_object_data_ensure(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_HairMotionData *EEVEE_motion_blur_curves_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);
@ -1120,10 +1122,10 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
bool *cast_shadow);
void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
bool *cast_shadow);
void EEVEE_object_curves_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
bool *cast_shadow);
void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_materials_free(void);
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
@ -1463,6 +1465,9 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *sldata,
Object *ob,
struct ParticleSystem *psys,
struct ModifierData *md);
void EEVEE_motion_blur_curves_cache_populate(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
Object *ob);
void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata);
void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata);
void EEVEE_motion_blur_draw(EEVEE_Data *vedata);

View File

@ -230,7 +230,7 @@ void EEVEE_render_cache(void *vedata,
}
}
else if (ob->type == OB_CURVES) {
EEVEE_object_hair_cache_populate(vedata, sldata, ob, &cast_shadow);
EEVEE_object_curves_cache_populate(vedata, sldata, ob, &cast_shadow);
if (do_cryptomatte) {
EEVEE_cryptomatte_object_curves_cache_populate(data, sldata, ob);
}

View File

@ -425,7 +425,8 @@ void workbench_cache_populate(void *ved, Object *ob)
}
else if (ob->type == OB_CURVES) {
int color_type = workbench_color_type_get(wpd, ob, NULL, NULL, NULL);
workbench_cache_hair_populate(wpd, ob, NULL, NULL, color_type, false, CURVES_MATERIAL_NR);
DRWShadingGroup *grp = workbench_material_hair_setup(wpd, ob, CURVES_MATERIAL_NR, color_type);
DRW_shgroup_curves_create_sub(ob, grp, NULL);
}
else if (ob->type == OB_VOLUME) {
if (wpd->shading.type != OB_WIRE) {

View File

@ -53,12 +53,17 @@ struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
struct ModifierData *md,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
struct DRWShadingGroup *DRW_shgroup_curves_create_sub(struct Object *object,
struct DRWShadingGroup *shgrp,
struct GPUMaterial *gpu_material);
/**
* \note Only valid after #DRW_hair_update().
*/
struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md);
struct GPUVertBuf *DRW_curves_pos_buffer_get(struct Object *object);
void DRW_hair_duplimat_get(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,

View File

@ -164,17 +164,28 @@ static ParticleHairCache *drw_hair_particle_cache_get(Object *object,
int subdiv,
int thickness_res)
{
bool update;
ParticleHairCache *cache;
if (psys) {
/* Old particle hair. */
update = particles_ensure_procedural_data(
object, psys, md, &cache, gpu_material, subdiv, thickness_res);
}
else {
/* New curves object. */
update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res);
bool update = particles_ensure_procedural_data(
object, psys, md, &cache, gpu_material, subdiv, thickness_res);
if (update) {
if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
drw_hair_particle_cache_update_compute(cache, subdiv);
}
else {
drw_hair_particle_cache_update_transform_feedback(cache, subdiv);
}
}
return cache;
}
static ParticleHairCache *drw_curves_cache_get(Object *object,
GPUMaterial *gpu_material,
int subdiv,
int thickness_res)
{
ParticleHairCache *cache;
bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res);
if (update) {
if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
@ -201,37 +212,44 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi
return cache->final[subdiv].proc_buf;
}
GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
int subdiv = scene->r.hair_subdiv;
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
ParticleHairCache *cache = drw_curves_cache_get(object, NULL, subdiv, thickness_res);
return cache->final[subdiv].proc_buf;
}
void DRW_hair_duplimat_get(Object *object,
ParticleSystem *psys,
ParticleSystem *UNUSED(psys),
ModifierData *UNUSED(md),
float (*dupli_mat)[4])
{
Object *dupli_parent = DRW_object_get_dupli_parent(object);
DupliObject *dupli_object = DRW_object_get_dupli(object);
if (psys) {
if ((dupli_parent != NULL) && (dupli_object != NULL)) {
if (dupli_object->type & OB_DUPLICOLLECTION) {
unit_m4(dupli_mat);
Collection *collection = dupli_parent->instance_collection;
if (collection != NULL) {
sub_v3_v3(dupli_mat[3], collection->instance_offset);
}
mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat);
}
else {
copy_m4_m4(dupli_mat, dupli_object->ob->obmat);
invert_m4(dupli_mat);
mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat);
if ((dupli_parent != NULL) && (dupli_object != NULL)) {
if (dupli_object->type & OB_DUPLICOLLECTION) {
unit_m4(dupli_mat);
Collection *collection = dupli_parent->instance_collection;
if (collection != NULL) {
sub_v3_v3(dupli_mat[3], collection->instance_offset);
}
mul_m4_m4m4(dupli_mat, dupli_parent->obmat, dupli_mat);
}
else {
unit_m4(dupli_mat);
copy_m4_m4(dupli_mat, dupli_object->ob->obmat);
invert_m4(dupli_mat);
mul_m4_m4m4(dupli_mat, object->obmat, dupli_mat);
}
}
else {
/* New curves object. */
copy_m4_m4(dupli_mat, object->obmat);
unit_m4(dupli_mat);
}
}
@ -317,6 +335,71 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
return shgrp;
}
DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
DRWShadingGroup *shgrp_parent,
GPUMaterial *gpu_material)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
int subdiv = scene->r.hair_subdiv;
int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
ParticleHairCache *curves_cache = drw_curves_cache_get(
object, gpu_material, subdiv, thickness_res);
DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
/* TODO: optimize this. Only bind the ones GPUMaterial needs. */
for (int i = 0; i < curves_cache->num_uv_layers; i++) {
for (int n = 0; n < MAX_LAYER_NAME_CT && curves_cache->uv_layer_names[i][n][0] != '\0'; n++) {
DRW_shgroup_uniform_texture(
shgrp, curves_cache->uv_layer_names[i][n], curves_cache->uv_tex[i]);
}
}
for (int i = 0; i < curves_cache->num_col_layers; i++) {
for (int n = 0; n < MAX_LAYER_NAME_CT && curves_cache->col_layer_names[i][n][0] != '\0'; n++) {
DRW_shgroup_uniform_texture(
shgrp, curves_cache->col_layer_names[i][n], curves_cache->col_tex[i]);
}
}
/* Fix issue with certain driver not drawing anything if there is no texture bound to
* "ac", "au", "u" or "c". */
if (curves_cache->num_uv_layers == 0) {
DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture);
}
if (curves_cache->num_col_layers == 0) {
DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture);
DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture);
}
/* TODO: Generalize radius implementation for curves data type. */
float hair_rad_shape = 1.0f;
float hair_rad_root = 0.005f;
float hair_rad_tip = 0.0f;
bool hair_close_tip = true;
DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex);
if (curves_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
}
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &curves_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
DRW_shgroup_uniform_mat4_copy(shgrp, "hairDupliMatrix", object->obmat);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
/* TODO(fclem): Until we have a better way to cull the curves and render with orco, bypass
* culling test. */
GPUBatch *geom = curves_cache->final[subdiv].proc_hairs[thickness_res - 1];
DRW_shgroup_call_no_cull(shgrp, geom, object);
return shgrp;
}
void DRW_hair_update(void)
{
#ifndef USE_TRANSFORM_FEEDBACK