diff options
author | Jeroen Bakker <jbakker> | 2021-09-24 08:42:36 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2021-09-24 08:44:22 +0300 |
commit | 6a88f83d679f281d7adb3798ab4770069a63c2da (patch) | |
tree | 02b6e3870e7651c40c63eb23285e7f2ff3f2507e /source/blender/draw/intern | |
parent | 0f764ade1a2fd8aa9c462dd5850e8be52aa203f5 (diff) |
Hair Info Length Attribute
Goal is to add the length attribute to the Hair Info node, for better control over color gradients or similar along the hair.
Reviewed By: #eevee_viewport, brecht
Differential Revision: https://developer.blender.org/D10481
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_curve.cc | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_hair.c | 59 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_particles.c | 87 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_common.h | 4 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_hair.c | 16 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_hair_private.h | 6 | ||||
-rw-r--r-- | source/blender/draw/intern/shaders/common_hair_lib.glsl | 6 |
7 files changed, 129 insertions, 52 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc index 0804745fab5..dc8f382b7f8 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.cc +++ b/source/blender/draw/intern/draw_cache_impl_curve.cc @@ -342,6 +342,9 @@ static void curve_cd_calc_used_gpu_layers(CustomDataMask *cd_layers, case CD_ORCO: *cd_layers |= CD_MASK_ORCO; break; + case CD_HAIRLENGTH: + *cd_layers |= CD_MASK_HAIRLENGTH; + break; } } } diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c index 6424b21666d..82af32c4c9f 100644 --- a/source/blender/draw/intern/draw_cache_impl_hair.c +++ b/source/blender/draw/intern/draw_cache_impl_hair.c @@ -30,6 +30,7 @@ #include "BLI_math_base.h" #include "BLI_math_vector.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "DNA_hair_types.h" #include "DNA_object_types.h" @@ -38,6 +39,7 @@ #include "GPU_batch.h" #include "GPU_texture.h" +#include "GPU_material.h" #include "draw_cache_impl.h" /* own include */ #include "draw_hair_private.h" /* own include */ @@ -141,7 +143,7 @@ static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache) } } -static void hair_batch_cache_fill_segments_proc_pos(Hair *hair, GPUVertBufRaw *attr_step) +static void hair_batch_cache_fill_segments_proc_pos(Hair *hair, GPUVertBufRaw *attr_step, GPUVertBufRaw *length_step) { /* TODO: use hair radius layer if available. */ HairCurve *curve = hair->curves; @@ -162,6 +164,8 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair, GPUVertBufRaw *a seg_data[3] = total_len; co_prev = curve_co[j]; } + /* Assign length value*/ + *(float *)GPU_vertbuf_raw_step(length_step) = total_len; if (total_len > 0.0f) { /* Divide by total length to have a [0-1] number. */ for (int j = 0; j < curve->numpoints; j++, seg_data_first += 4) { @@ -171,28 +175,48 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair, GPUVertBufRaw *a } } -static void hair_batch_cache_ensure_procedural_pos(Hair *hair, ParticleHairCache *cache) +static void hair_batch_cache_ensure_procedural_pos(Hair *hair, + ParticleHairCache *cache, + GPUMaterial *gpu_material) { - if (cache->proc_point_buf != NULL) { - return; - } + if (cache->proc_point_buf == NULL) { + /* initialize vertex format */ + GPUVertFormat format = {0}; + uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* initialize vertex format */ - GPUVertFormat format = {0}; - uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + cache->proc_point_buf = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len); - cache->proc_point_buf = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len); + GPUVertBufRaw point_step; + GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &point_step); - GPUVertBufRaw pos_step; - GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step); + GPUVertFormat length_format = {0}; + uint length_id = GPU_vertformat_attr_add( + &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - hair_batch_cache_fill_segments_proc_pos(hair, &pos_step); + cache->proc_length_buf = GPU_vertbuf_create_with_format(&length_format); + GPU_vertbuf_data_alloc(cache->proc_length_buf, cache->strands_len); - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_point_buf); + GPUVertBufRaw length_step; + GPU_vertbuf_attr_get_raw_data(cache->proc_length_buf, length_id, &length_step); + + hair_batch_cache_fill_segments_proc_pos(hair, &point_step, &length_step); - cache->point_tex = GPU_texture_create_from_vertbuf("hair_point", cache->proc_point_buf); + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(cache->proc_point_buf); + cache->point_tex = GPU_texture_create_from_vertbuf("hair_point", cache->proc_point_buf); + } + + if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex) { + ListBase gpu_attrs = GPU_material_attributes(gpu_material); + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { + if (attr->type == CD_HAIRLENGTH) { + GPU_vertbuf_use(cache->proc_length_buf); + cache->length_tex = GPU_texture_create_from_vertbuf("hair_length", cache->proc_length_buf); + break; + } + } + } } static void hair_batch_cache_fill_strands_data(Hair *hair, @@ -310,6 +334,7 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair, /* Ensure all textures and buffers needed for GPU accelerated drawing. */ bool hair_ensure_procedural_data(Object *object, ParticleHairCache **r_hair_cache, + GPUMaterial *gpu_material, int subdiv, int thickness_res) { @@ -325,7 +350,7 @@ bool hair_ensure_procedural_data(Object *object, /* Refreshed on combing and simulation. */ if ((*r_hair_cache)->proc_point_buf == NULL) { ensure_seg_pt_count(hair, &cache->hair); - hair_batch_cache_ensure_procedural_pos(hair, &cache->hair); + hair_batch_cache_ensure_procedural_pos(hair, &cache->hair, gpu_material); need_ft_update = true; } diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 5c51f24a435..387c43741f7 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -46,6 +46,7 @@ #include "ED_particle.h" #include "GPU_batch.h" +#include "GPU_material.h" #include "DEG_depsgraph_query.h" @@ -183,7 +184,9 @@ void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) { /* TODO: more granular update tagging. */ GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); + GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_length_buf); DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); + DRW_TEXTURE_FREE_SAFE(hair_cache->length_tex); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); GPU_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_seg_buf); @@ -609,7 +612,8 @@ static int particle_batch_cache_fill_segments(ParticleSystem *psys, static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_cache, const int num_path_keys, - GPUVertBufRaw *attr_step) + GPUVertBufRaw *attr_step, + GPUVertBufRaw *length_step) { for (int i = 0; i < num_path_keys; i++) { ParticleCacheKey *path = path_cache[i]; @@ -630,6 +634,8 @@ static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_ seg_data[3] = total_len; co_prev = path[j].co; } + /* Assign length value*/ + *(float *)GPU_vertbuf_raw_step(length_step) = total_len; if (total_len > 0.0f) { /* Divide by total length to have a [0-1] number. */ for (int j = 0; j <= path->segments; j++, seg_data_first += 4) { @@ -1079,40 +1085,64 @@ static void particle_batch_cache_ensure_procedural_indices(PTCacheEdit *edit, static void particle_batch_cache_ensure_procedural_pos(PTCacheEdit *edit, ParticleSystem *psys, - ParticleHairCache *cache) + ParticleHairCache *cache, + GPUMaterial *gpu_material) { - if (cache->proc_point_buf != NULL) { - return; - } + if (cache->proc_point_buf == NULL) { + /* initialize vertex format */ + GPUVertFormat pos_format = {0}; + uint pos_id = GPU_vertformat_attr_add( + &pos_format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - /* initialize vertex format */ - GPUVertFormat format = {0}; - uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + cache->proc_point_buf = GPU_vertbuf_create_with_format(&pos_format); + GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len); - cache->proc_point_buf = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(cache->proc_point_buf, cache->point_len); + GPUVertBufRaw pos_step; + GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step); - GPUVertBufRaw pos_step; - GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step); + GPUVertFormat length_format = {0}; + uint length_id = GPU_vertformat_attr_add( + &length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - if (edit != NULL && edit->pathcache != NULL) { - particle_batch_cache_fill_segments_proc_pos(edit->pathcache, edit->totcached, &pos_step); - } - else { - if ((psys->pathcache != NULL) && - (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { - particle_batch_cache_fill_segments_proc_pos(psys->pathcache, psys->totpart, &pos_step); + cache->proc_length_buf = GPU_vertbuf_create_with_format(&length_format); + GPU_vertbuf_data_alloc(cache->proc_length_buf, cache->strands_len); + + GPUVertBufRaw length_step; + GPU_vertbuf_attr_get_raw_data(cache->proc_length_buf, length_id, &length_step); + + if (edit != NULL && edit->pathcache != NULL) { + particle_batch_cache_fill_segments_proc_pos( + edit->pathcache, edit->totcached, &pos_step, &length_step); } - if (psys->childcache) { - const int child_count = psys->totchild * psys->part->disp / 100; - particle_batch_cache_fill_segments_proc_pos(psys->childcache, child_count, &pos_step); + else { + if ((psys->pathcache != NULL) && + (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { + particle_batch_cache_fill_segments_proc_pos( + psys->pathcache, psys->totpart, &pos_step, &length_step); + } + if (psys->childcache) { + const int child_count = psys->totchild * psys->part->disp / 100; + particle_batch_cache_fill_segments_proc_pos( + psys->childcache, child_count, &pos_step, &length_step); + } } - } - /* Create vbo immediately to bind to texture buffer. */ - GPU_vertbuf_use(cache->proc_point_buf); + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(cache->proc_point_buf); + cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf); + } - cache->point_tex = GPU_texture_create_from_vertbuf("part_point", cache->proc_point_buf); + /* Checking hair length seperatly, only allocating gpu memory when needed */ + if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex == NULL) { + ListBase gpu_attrs = GPU_material_attributes(gpu_material); + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { + if (attr->type == CD_HAIRLENGTH) { + GPU_vertbuf_use(cache->proc_length_buf); + cache->length_tex = GPU_texture_create_from_vertbuf("hair_length", cache->proc_length_buf); + break; + } + } + } } static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit, @@ -1649,6 +1679,7 @@ bool particles_ensure_procedural_data(Object *object, ParticleSystem *psys, ModifierData *md, ParticleHairCache **r_hair_cache, + GPUMaterial *gpu_material, int subdiv, int thickness_res) { @@ -1666,9 +1697,9 @@ bool particles_ensure_procedural_data(Object *object, (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv); /* Refreshed on combing and simulation. */ - if ((*r_hair_cache)->proc_point_buf == NULL) { + if ((*r_hair_cache)->proc_point_buf == NULL || (gpu_material && (*r_hair_cache)->length_tex == NULL)) { ensure_seg_pt_count(source.edit, source.psys, &cache->hair); - particle_batch_cache_ensure_procedural_pos(source.edit, source.psys, &cache->hair); + particle_batch_cache_ensure_procedural_pos(source.edit, source.psys, &cache->hair, gpu_material); need_ft_update = true; } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 1eaf2bee236..2913877c9c1 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -29,6 +29,7 @@ struct Object; struct ParticleSystem; struct RegionView3D; struct ViewLayer; +struct GPUMaterial; #define UBO_FIRST_COLOR colorWire #define UBO_LAST_COLOR colorUVShadow @@ -175,7 +176,8 @@ bool DRW_object_axis_orthogonal_to_view(struct Object *ob, int axis); struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, - struct DRWShadingGroup *shgrp); + struct DRWShadingGroup *shgrp, + struct GPUMaterial *gpu_material); struct GPUVertBuf *DRW_hair_pos_buffer_get(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md); diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index c2e25389091..75bef12285b 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -41,6 +41,7 @@ #include "GPU_shader.h" #include "GPU_texture.h" #include "GPU_vertex_buffer.h" +#include "GPU_material.h" #include "draw_hair_private.h" #include "draw_shader.h" @@ -173,17 +174,17 @@ static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache } static ParticleHairCache *drw_hair_particle_cache_get( - Object *object, ParticleSystem *psys, ModifierData *md, int subdiv, int thickness_res) + Object *object, ParticleSystem *psys, ModifierData *md, GPUMaterial* gpu_material, int subdiv, int thickness_res) { bool update; ParticleHairCache *cache; if (psys) { /* Old particle hair. */ - update = particles_ensure_procedural_data(object, psys, md, &cache, subdiv, thickness_res); + update = particles_ensure_procedural_data(object, psys, md, &cache, gpu_material, subdiv, thickness_res); } else { /* New hair object. */ - update = hair_ensure_procedural_data(object, &cache, subdiv, thickness_res); + update = hair_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res); } if (update) { @@ -206,7 +207,7 @@ GPUVertBuf *DRW_hair_pos_buffer_get(Object *object, ParticleSystem *psys, Modifi int subdiv = scene->r.hair_subdiv; int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; - ParticleHairCache *cache = drw_hair_particle_cache_get(object, psys, md, subdiv, thickness_res); + ParticleHairCache *cache = drw_hair_particle_cache_get(object, psys, md, NULL, subdiv, thickness_res); return cache->final[subdiv].proc_buf; } @@ -248,7 +249,8 @@ void DRW_hair_duplimat_get(Object *object, DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, ParticleSystem *psys, ModifierData *md, - DRWShadingGroup *shgrp_parent) + DRWShadingGroup *shgrp_parent, + GPUMaterial* gpu_material) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; @@ -258,7 +260,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; ParticleHairCache *hair_cache = drw_hair_particle_cache_get( - object, psys, md, subdiv, thickness_res); + object, psys, md, gpu_material, subdiv, thickness_res); DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent); @@ -308,6 +310,8 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, } DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex); + if (hair_cache->length_tex) + DRW_shgroup_uniform_texture(shgrp, "hairLen", hair_cache->length_tex); DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_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); diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index 1f58d8d0ead..289a1690fc6 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -66,6 +66,10 @@ typedef struct ParticleHairCache { GPUVertBuf *proc_strand_buf; GPUTexture *strand_tex; + /* Hair Length */ + GPUVertBuf *proc_length_buf; + GPUTexture *length_tex; + GPUVertBuf *proc_strand_seg_buf; GPUTexture *strand_seg_tex; @@ -93,11 +97,13 @@ bool particles_ensure_procedural_data(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct ParticleHairCache **r_hair_cache, + struct GPUMaterial *gpu_material, int subdiv, int thickness_res); bool hair_ensure_procedural_data(struct Object *object, struct ParticleHairCache **r_hair_cache, + struct GPUMaterial *gpu_material, int subdiv, int thickness_res); diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index 02c335ddae2..6cc7f09a852 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -210,6 +210,12 @@ void hair_get_pos_tan_binor_time(bool is_persp, } } +float hair_get_customdata_float(const samplerBuffer cd_buf) +{ + int id = hair_get_strand_id(); + return texelFetch(cd_buf, id).r; +} + vec2 hair_get_customdata_vec2(const samplerBuffer cd_buf) { int id = hair_get_strand_id(); |