diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2017-08-14 09:58:02 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2017-08-14 09:58:02 +0300 |
commit | b0717ad91eedb64fa23a7ac16403d3fc166e447a (patch) | |
tree | eed9d3061d44ef55fb131140710f10017621424d /source/blender/draw | |
parent | 91fd0a487d95e604c1c245905895123eeaf2ca0e (diff) |
Hair drawing data based on the new DNA hair groups.
Diffstat (limited to 'source/blender/draw')
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 332 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/hair_lib.glsl | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 10 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 6 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 9 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_hair.c | 310 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_strands.c | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_hair.c | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 6 |
10 files changed, 577 insertions, 115 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c6b07c76d83..bcedcfc0f0a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -57,6 +57,7 @@ set(SRC intern/draw_cache.c intern/draw_cache_impl_curve.c intern/draw_cache_impl_displist.c + intern/draw_cache_impl_hair.c intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.c intern/draw_cache_impl_particles.c diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index e91ffeaa6b8..3cc6ca81171 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -25,19 +25,23 @@ #include "DRW_render.h" -#include "DNA_world_types.h" +#include "DNA_hair_types.h" #include "DNA_modifier_types.h" #include "DNA_view3d_types.h" +#include "DNA_world_types.h" #include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_alloca.h" +#include "BKE_DerivedMesh.h" #include "BKE_editstrands.h" #include "BKE_particle.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "DEG_depsgraph.h" + #include "GPU_material.h" #include "GPU_texture.h" @@ -1003,6 +1007,219 @@ static void material_transparent( } } +static void material_particle_hair(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, + Object *ob, ParticleSystem *psys, ModifierData *md) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + GHash *material_hash = stl->g_data->hair_material_hash; + + if (!psys_check_enabled(ob, psys, false)) { + return; + } + + ParticleSettings *part = psys->part; + bool use_hair = false; + bool use_fibers = false; + float mat[4][4]; + struct Gwn_Batch *hair_geom = NULL; + const DRWHairFiberTextureBuffer *fiber_buffer = NULL; + GPUTexture **fiber_texture = NULL; + + if (ob->mode & OB_MODE_HAIR_EDIT) { + BMEditStrands *edit = psys->hairedit; + const HairEditSettings *tsettings = &scene->toolsettings->hair_edit; + if (edit &&tsettings->hair_draw_mode == HAIR_DRAW_FIBERS && edit->hair_group) { + use_hair = true; + use_fibers = true; + copy_m4_m4(mat, ob->obmat); + + hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer); + + if (!edit->texture) { + edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, + DRW_TEX_RG_32, 0, fiber_buffer->data); + } + fiber_texture = (GPUTexture **)(&edit->texture); + } + } + else { + int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) { + use_hair = true; + unit_m4(mat); + hair_geom = DRW_cache_particles_get_hair(psys, md); + } + } + + if (use_hair) { + Material *ma = give_current_material(ob, part->omat); + if (ma == NULL) { + ma = &defmaterial; + } + + if (!use_fibers) { + DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat); + DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat); + } + else { + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene, + fiber_texture, fiber_buffer); + + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene, + fiber_texture, fiber_buffer); + } + + DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); + if (!shgrp) { + float *color_p = &ma->r; + float *metal_p = &ma->ray_mirror; + float *spec_p = &ma->spec; + float *rough_p = &ma->gloss_mir; + + if (ma->use_nodes && ma->nodetree) { + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, + use_fibers, stl->effects->use_ao, stl->effects->use_bent_normals); + + shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); + if (shgrp) { + add_standard_uniforms(shgrp, sldata, vedata, NULL); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + else { + /* Shader failed : pink color */ + static float col[3] = {1.0f, 0.0f, 1.0f}; + static float half = 0.5f; + + color_p = col; + metal_p = spec_p = rough_p = ½ + } + } + + /* Fallback to default shader */ + if (shgrp == NULL) { + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, use_fibers, + false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr); + DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + } + + if (shgrp) { + DRW_shgroup_call_add(shgrp, hair_geom, mat); + + if (use_fibers) { + DRW_hair_shader_uniforms(shgrp, scene, + fiber_texture, fiber_buffer); + } + } + } +} + +static void material_hair(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, Object *ob, HairGroup *group) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + GHash *material_hash = stl->g_data->hair_material_hash; + const HairEditSettings *tsettings = &scene->toolsettings->hair_edit; + + float mat[4][4]; + copy_m4_m4(mat, ob->obmat); + + const DRWHairFiberTextureBuffer *fiber_buffer = NULL; + struct Gwn_Batch *hair_geom; + { + DerivedMesh *scalp = NULL; + if (ob->derivedFinal) { + scalp = ob->derivedFinal; + } + else { + EvaluationContext eval_ctx = {0}; + DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_VIEWPORT); + scalp = mesh_get_derived_final(&eval_ctx, scene, ob, CD_MASK_BAREMESH); + } + hair_geom = DRW_cache_hair_get_fibers(group, tsettings->hair_draw_subdiv, scalp, &fiber_buffer); + } + + if (!group->draw_texture_cache) { + group->draw_texture_cache = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, + DRW_TEX_RG_32, 0, fiber_buffer->data); + } + GPUTexture **fiber_texture = (GPUTexture **)(&group->draw_texture_cache); + + // TODO + Material *ma = NULL;/*give_current_material(ob, omat);*/ + if (ma == NULL) { + ma = &defmaterial; + } + + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene, + fiber_texture, fiber_buffer); + + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene, + fiber_texture, fiber_buffer); + + DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); + if (!shgrp) { + float *color_p = &ma->r; + float *metal_p = &ma->ray_mirror; + float *spec_p = &ma->spec; + float *rough_p = &ma->gloss_mir; + + if (ma->use_nodes && ma->nodetree) { + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, + true, stl->effects->use_ao, stl->effects->use_bent_normals); + + shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); + if (shgrp) { + add_standard_uniforms(shgrp, sldata, vedata, NULL); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + else { + /* Shader failed : pink color */ + static float col[3] = {1.0f, 0.0f, 1.0f}; + static float half = 0.5f; + + color_p = col; + metal_p = spec_p = rough_p = ½ + } + } + + /* Fallback to default shader */ + if (shgrp == NULL) { + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, true, + false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr); + DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + } + + if (shgrp) { + DRW_shgroup_call_add(shgrp, hair_geom, mat); + + DRW_hair_shader_uniforms(shgrp, scene, + fiber_texture, fiber_buffer); + } +} + void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -1132,116 +1349,15 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl if (ob->type == OB_MESH) { if (ob != draw_ctx->scene->obedit) { - material_hash = stl->g_data->hair_material_hash; - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - - if (psys_check_enabled(ob, psys, false)) { - ParticleSettings *part = psys->part; - bool use_hair = false; - bool use_fibers = false; - float mat[4][4]; - struct Gwn_Batch *hair_geom = NULL; - const DRWHairFiberTextureBuffer *fiber_buffer = NULL; - GPUTexture **fiber_texture = NULL; - - if (ob->mode & OB_MODE_HAIR_EDIT) { - BMEditStrands *edit = psys->hairedit; - const HairEditSettings *tsettings = &scene->toolsettings->hair_edit; - if (edit &&tsettings->hair_draw_mode == HAIR_DRAW_FIBERS && BKE_editstrands_hair_ensure(edit)) { - use_hair = true; - use_fibers = true; - copy_m4_m4(mat, ob->obmat); - - hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer); - - if (!edit->texture) { - edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, - DRW_TEX_RG_32, 0, fiber_buffer->data); - } - fiber_texture = (GPUTexture **)(&edit->texture); - } - } - else { - int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) { - use_hair = true; - unit_m4(mat); - hair_geom = DRW_cache_particles_get_hair(psys, md); - } - } - - if (use_hair) { - Material *ma = give_current_material(ob, part->omat); - if (ma == NULL) { - ma = &defmaterial; - } - - if (!use_fibers) { - DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat); - DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat); - } - else { - DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat); - DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene, - fiber_texture, fiber_buffer); - - DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat); - DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene, - fiber_texture, fiber_buffer); - } - - DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); - if (!shgrp) { - float *color_p = &ma->r; - float *metal_p = &ma->ray_mirror; - float *spec_p = &ma->spec; - float *rough_p = &ma->gloss_mir; - - if (ma->use_nodes && ma->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, - use_fibers, stl->effects->use_ao, stl->effects->use_bent_normals); - - shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); - if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL); - - BLI_ghash_insert(material_hash, ma, shgrp); - } - else { - /* Shader failed : pink color */ - static float col[3] = {1.0f, 0.0f, 1.0f}; - static float half = 0.5f; - - color_p = col; - metal_p = spec_p = rough_p = ½ - } - } - - /* Fallback to default shader */ - if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, use_fibers, - false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - - BLI_ghash_insert(material_hash, ma, shgrp); - } - } - - if (shgrp) { - DRW_shgroup_call_add(shgrp, hair_geom, mat); - - if (use_fibers) { - DRW_hair_shader_uniforms(shgrp, scene, - fiber_texture, fiber_buffer); - } - } - } + material_particle_hair(sldata, vedata, ob, psys, md); + } + else if (md->type == eModifierType_Hair) { + HairModifierData *hmd = (HairModifierData *)md; + for (HairGroup *group = hmd->hair->groups.first; group; group = group->next) { + material_hair(sldata, vedata, ob, group); } } } diff --git a/source/blender/draw/engines/eevee/shaders/hair_lib.glsl b/source/blender/draw/engines/eevee/shaders/hair_lib.glsl index 0611ea5d2d9..c6a4950839b 100644 --- a/source/blender/draw/engines/eevee/shaders/hair_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/hair_lib.glsl @@ -147,10 +147,12 @@ void deform_fiber(DeformParams params, #define FIBER_RIBBON -uniform sampler2D strand_data; +uniform sampler2D fiber_data; + +uniform int fiber_start; uniform int strand_map_start; uniform int strand_vertex_start; -uniform int fiber_start; + uniform float ribbon_width; uniform vec2 viewport_size; @@ -159,7 +161,7 @@ uniform vec2 viewport_size; vec2 read_texdata(int offset) { ivec2 offset2 = ivec2(offset % HAIR_SHADER_TEX_WIDTH, offset / HAIR_SHADER_TEX_WIDTH); - return texelFetch(strand_data, offset2, 0).rg; + return texelFetch(fiber_data, offset2, 0).rg; } mat4 mat4_from_vectors(vec3 nor, vec3 tang, vec3 co) diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 7981b565089..9a4000cc0f2 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -2615,3 +2615,13 @@ Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool { return DRW_editstrands_batch_cache_get_hair_fibers(es, use_ribbons, subdiv, r_buffer); } + +/* -------------------------------------------------------------------- */ + +/** \name Hair */ + +Gwn_Batch *DRW_cache_hair_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const struct DRWHairFiberTextureBuffer **r_buffer) +{ + return DRW_hair_batch_cache_get_fibers(group, subdiv, scalp, r_buffer); +} diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index c536bd81084..b6853c1fd3c 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -31,7 +31,9 @@ struct GPUMaterial; struct Object; struct ModifierData; struct BMEditStrands; +struct HairGroup; struct DRWHairFiberTextureBuffer; +struct DerivedMesh; void DRW_shape_cache_free(void); @@ -167,4 +169,8 @@ struct Gwn_Batch *DRW_cache_editstrands_get_wires(struct BMEditStrands *es); struct Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv, const struct DRWHairFiberTextureBuffer **r_buffer); +/* Hair */ +struct Gwn_Batch *DRW_cache_hair_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const struct DRWHairFiberTextureBuffer **r_buffer); + #endif /* __DRAW_CACHE_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index a6f4c486e2f..f026b7452df 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -33,7 +33,9 @@ struct CurveCache; struct ParticleSystem; struct ModifierData; struct BMEditStrands; +struct HairGroup; struct DRWHairFiberTextureBuffer; +struct DerivedMesh; struct Curve; struct Lattice; @@ -52,6 +54,9 @@ void DRW_lattice_batch_cache_free(struct Lattice *lt); void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode); void DRW_particle_batch_cache_free(struct ParticleSystem *psys); +void DRW_hair_batch_cache_dirty(struct HairGroup *group, int mode); +void DRW_hair_batch_cache_free(struct HairGroup *group); + void DRW_editstrands_batch_cache_dirty(struct BMEditStrands *es, int mode); void DRW_editstrands_batch_cache_free(struct BMEditStrands *es); @@ -115,4 +120,8 @@ struct Gwn_Batch *DRW_editstrands_batch_cache_get_points(struct BMEditStrands *e struct Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv, const struct DRWHairFiberTextureBuffer **r_buffer); +/* Hair */ +struct Gwn_Batch *DRW_hair_batch_cache_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const struct DRWHairFiberTextureBuffer **r_buffer); + #endif /* __DRAW_CACHE_IMPL_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c new file mode 100644 index 00000000000..94a22a610e1 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_hair.c @@ -0,0 +1,310 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file draw_cache_impl_strands.c + * \ingroup draw + * + * \brief Strands API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_ghash.h" + +#include "DNA_hair_types.h" +#include "DNA_scene_types.h" + +#include "BKE_hair.h" + +#include "GPU_batch.h" +#include "GPU_extensions.h" +#include "GPU_texture.h" + +#include "draw_common.h" +#include "draw_cache_impl.h" /* own include */ +#include "DRW_render.h" + +// timing +//#define DEBUG_TIME +#ifdef DEBUG_TIME +# include "PIL_time_utildefines.h" +#else +# define TIMEIT_START(var) +# define TIMEIT_VALUE(var) +# define TIMEIT_VALUE_PRINT(var) +# define TIMEIT_END(var) +# define TIMEIT_BENCH(expr, id) (expr) +# define TIMEIT_BLOCK_INIT(var) +# define TIMEIT_BLOCK_START(var) +# define TIMEIT_BLOCK_END(var) +# define TIMEIT_BLOCK_STATS(var) +#endif + +/* ---------------------------------------------------------------------- */ +/* Hair Gwn_Batch Cache */ + +typedef struct HairBatchCache { + Gwn_VertBuf *verts; + Gwn_IndexBuf *segments; + + Gwn_Batch *fibers; + + DRWHairFiberTextureBuffer texbuffer; + + /* settings to determine if cache is invalid */ + bool is_dirty; +} HairBatchCache; + +/* Gwn_Batch cache management. */ + +static void hair_batch_cache_clear(HairGroup *group); + +static bool hair_batch_cache_valid(HairGroup *group) +{ + HairBatchCache *cache = group->draw_batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_dirty) { + return false; + } + + return true; +} + +static void hair_batch_cache_init(HairGroup *group) +{ + HairBatchCache *cache = group->draw_batch_cache; + + if (!cache) { + cache = group->draw_batch_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->is_dirty = false; +} + +static HairBatchCache *hair_batch_cache_get(HairGroup *group) +{ + if (!hair_batch_cache_valid(group)) { + hair_batch_cache_clear(group); + hair_batch_cache_init(group); + } + return group->draw_batch_cache; +} + +void DRW_hair_batch_cache_dirty(HairGroup *group, int mode) +{ + HairBatchCache *cache = group->draw_batch_cache; + if (cache == NULL) { + return; + } + switch (mode) { + case BKE_HAIR_BATCH_DIRTY_ALL: + cache->is_dirty = true; + break; + default: + BLI_assert(0); + } +} + +static void hair_batch_cache_clear(HairGroup *group) +{ + HairBatchCache *cache = group->draw_batch_cache; + + if (group->draw_texture_cache) { + GPU_texture_free(group->draw_texture_cache); + group->draw_texture_cache = NULL; + } + + if (cache) { + GWN_BATCH_DISCARD_SAFE(cache->fibers); + GWN_VERTBUF_DISCARD_SAFE(cache->verts); + GWN_INDEXBUF_DISCARD_SAFE(cache->segments); + + { + DRWHairFiberTextureBuffer *buffer = &cache->texbuffer; + if (buffer->data) { + MEM_freeN(buffer->data); + buffer->data = NULL; + } + buffer->fiber_start = 0; + buffer->strand_map_start = 0; + buffer->strand_vertex_start = 0; + buffer->width = 0; + buffer->height = 0; + } + } +} + +void DRW_hair_batch_cache_free(HairGroup *group) +{ + hair_batch_cache_clear(group); + MEM_SAFE_FREE(group->draw_batch_cache); +} + +static void hair_batch_cache_ensure_fibers(HairGroup *group, HairBatchCache *cache, int subdiv) +{ + TIMEIT_START(hair_batch_cache_ensure_fibers); + + GWN_VERTBUF_DISCARD_SAFE(cache->verts); + GWN_INDEXBUF_DISCARD_SAFE(cache->segments); + + const int totfibers = group->num_follicles; + int *fiber_lengths = BKE_hair_group_get_fiber_lengths(group, subdiv); + int totpoint = 0; + for (int i = 0; i < totfibers; ++i) { + totpoint += fiber_lengths[i]; + } + const int totseg = totpoint - totfibers; + + static Gwn_VertFormat format = { 0 }; + static unsigned curve_param_id, fiber_index_id; + + /* initialize vertex format */ + if (format.attrib_ct == 0) { + fiber_index_id = GWN_vertformat_attr_add(&format, "fiber_index", GWN_COMP_I32, 1, GWN_FETCH_INT); + curve_param_id = GWN_vertformat_attr_add(&format, "curve_param", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); + } + + cache->verts = GWN_vertbuf_create_with_format(&format); + + Gwn_IndexBufBuilder elb; + { + TIMEIT_START(data_alloc); + Gwn_PrimType prim_type; + unsigned prim_ct, vert_ct; + prim_type = GWN_PRIM_TRIS; + prim_ct = 2 * totseg; + vert_ct = 2 * totpoint; + + GWN_vertbuf_data_alloc(cache->verts, vert_ct); + GWN_indexbuf_init(&elb, prim_type, prim_ct, vert_ct); + TIMEIT_END(data_alloc); + } + + TIMEIT_START(data_fill); + TIMEIT_BLOCK_INIT(GWN_vertbuf_attr_set); + TIMEIT_BLOCK_INIT(GWN_indexbuf_add_tri_verts); + int vi = 0; + for (int i = 0; i < totfibers; ++i) { + const int fiblen = fiber_lengths[i]; + const float da = fiblen > 1 ? 1.0f / (fiblen-1) : 0.0f; + + float a = 0.0f; + for (int k = 0; k < fiblen; ++k) { + TIMEIT_BLOCK_START(GWN_vertbuf_attr_set); + GWN_vertbuf_attr_set(cache->verts, fiber_index_id, vi, &i); + GWN_vertbuf_attr_set(cache->verts, curve_param_id, vi, &a); + GWN_vertbuf_attr_set(cache->verts, fiber_index_id, vi+1, &i); + GWN_vertbuf_attr_set(cache->verts, curve_param_id, vi+1, &a); + TIMEIT_BLOCK_END(GWN_vertbuf_attr_set); + + if (k > 0) { + TIMEIT_BLOCK_START(GWN_indexbuf_add_tri_verts); + GWN_indexbuf_add_tri_verts(&elb, vi-2, vi-1, vi+1); + GWN_indexbuf_add_tri_verts(&elb, vi+1, vi, vi-2); + TIMEIT_BLOCK_END(GWN_indexbuf_add_tri_verts); + } + + vi += 2; + a += da; + } + } + TIMEIT_BLOCK_STATS(GWN_vertbuf_attr_set); + TIMEIT_BLOCK_STATS(GWN_indexbuf_add_tri_verts); +#ifdef DEBUG_TIME + printf("Total GWN time: %f\n", _timeit_var_GWN_vertbuf_attr_set + _timeit_var_GWN_indexbuf_add_tri_verts); +#endif + fflush(stdout); + TIMEIT_END(data_fill); + + MEM_freeN(fiber_lengths); + + TIMEIT_BENCH(cache->segments = GWN_indexbuf_build(&elb), indexbuf_build); + + TIMEIT_END(hair_batch_cache_ensure_fibers); +} + +static void hair_batch_cache_ensure_texbuffer(HairGroup *group, HairBatchCache *cache, int subdiv, struct DerivedMesh *scalp) +{ + DRWHairFiberTextureBuffer *buffer = &cache->texbuffer; + static const int elemsize = 8; + const int width = GPU_max_texture_size(); + const int align = width * elemsize; + + // Offsets in bytes + int b_size, b_strand_map_start, b_strand_vertex_start, b_fiber_start; + BKE_hair_group_get_texture_buffer_size(group, subdiv, &b_size, + &b_strand_map_start, &b_strand_vertex_start, &b_fiber_start); + // Pad for alignment + b_size += align - b_size % align; + + // Convert to element size as texture offsets + const int size = b_size / elemsize; + const int height = size / width; + + buffer->data = MEM_mallocN(b_size, "hair fiber texture buffer"); + BKE_hair_group_get_texture_buffer(group, subdiv, scalp, buffer->data); + + buffer->width = width; + buffer->height = height; + buffer->strand_map_start = b_strand_map_start / elemsize; + buffer->strand_vertex_start = b_strand_vertex_start / elemsize; + buffer->fiber_start = b_fiber_start / elemsize; +} + +Gwn_Batch *DRW_hair_batch_cache_get_fibers(HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const DRWHairFiberTextureBuffer **r_buffer) +{ + HairBatchCache *cache = hair_batch_cache_get(group); + + TIMEIT_START(DRW_hair_batch_cache_get_fibers); + + if (cache->fibers == NULL) { + TIMEIT_BENCH(hair_batch_cache_ensure_fibers(group, cache, subdiv), + hair_batch_cache_ensure_fibers); + + TIMEIT_BENCH(cache->fibers = GWN_batch_create(GWN_PRIM_TRIS, cache->verts, cache->segments), + GWN_batch_create); + + TIMEIT_BENCH(hair_batch_cache_ensure_texbuffer(group, cache, subdiv, scalp), + hair_batch_cache_ensure_texbuffer); + } + + if (r_buffer) { + *r_buffer = &cache->texbuffer; + } + + TIMEIT_END(DRW_hair_batch_cache_get_fibers); + + return cache->fibers; +} diff --git a/source/blender/draw/intern/draw_cache_impl_strands.c b/source/blender/draw/intern/draw_cache_impl_strands.c index fc87e765001..fdf401c3641 100644 --- a/source/blender/draw/intern/draw_cache_impl_strands.c +++ b/source/blender/draw/intern/draw_cache_impl_strands.c @@ -35,6 +35,7 @@ #include "BLI_math_vector.h" #include "BLI_ghash.h" +#include "DNA_hair_types.h" #include "DNA_scene_types.h" #include "BKE_editstrands.h" @@ -390,12 +391,13 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand GWN_VERTBUF_DISCARD_SAFE(cache->hair.verts); GWN_INDEXBUF_DISCARD_SAFE(cache->hair.segments); + const int totfibers = es->hair_group->num_follicles; int *fiber_lengths = BKE_editstrands_hair_get_fiber_lengths(es, subdiv); int totpoint = 0; - for (int i = 0; i < es->hair_totfibers; ++i) { + for (int i = 0; i < totfibers; ++i) { totpoint += fiber_lengths[i]; } - const int totseg = totpoint - es->hair_totfibers; + const int totseg = totpoint - totfibers; static Gwn_VertFormat format = { 0 }; static unsigned curve_param_id, fiber_index_id; @@ -433,7 +435,7 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand TIMEIT_BLOCK_INIT(GWN_vertbuf_attr_set); TIMEIT_BLOCK_INIT(GWN_indexbuf_add_tri_verts); int vi = 0; - for (int i = 0; i < es->hair_totfibers; ++i) { + for (int i = 0; i < totfibers; ++i) { const int fiblen = fiber_lengths[i]; const float da = fiblen > 1 ? 1.0f / (fiblen-1) : 0.0f; diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 0a357518381..f4e5f211efe 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -52,7 +52,7 @@ void DRW_hair_shader_uniforms(DRWShadingGroup *shgrp, Scene *scene, DRW_shgroup_uniform_vec2(shgrp, "viewport_size", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_float(shgrp, "ribbon_width", &tsettings->hair_draw_size, 1); - DRW_shgroup_uniform_buffer(shgrp, "strand_data", fibertex); + DRW_shgroup_uniform_buffer(shgrp, "fiber_data", fibertex); DRW_shgroup_uniform_int(shgrp, "strand_map_start", &texbuffer->strand_map_start, 1); DRW_shgroup_uniform_int(shgrp, "strand_vertex_start", &texbuffer->strand_vertex_start, 1); DRW_shgroup_uniform_int(shgrp, "fiber_start", &texbuffer->fiber_start, 1); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index df08053c0b5..40f136a07f0 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -3614,6 +3614,9 @@ void DRW_engines_register(void) /* BKE: editstrands.c */ extern void *BKE_editstrands_batch_cache_dirty_cb; extern void *BKE_editstrands_batch_cache_free_cb; + /* BKE: hair.c */ + extern void *BKE_hair_batch_cache_dirty_cb; + extern void *BKE_hair_batch_cache_free_cb; BKE_curve_batch_cache_dirty_cb = DRW_curve_batch_cache_dirty; BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free; @@ -3629,6 +3632,9 @@ void DRW_engines_register(void) BKE_editstrands_batch_cache_dirty_cb = DRW_editstrands_batch_cache_dirty; BKE_editstrands_batch_cache_free_cb = DRW_editstrands_batch_cache_free; + + BKE_hair_batch_cache_dirty_cb = DRW_hair_batch_cache_dirty; + BKE_hair_batch_cache_free_cb = DRW_hair_batch_cache_free; } } |