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 | |
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')
17 files changed, 182 insertions, 63 deletions
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index ad2d5d267d5..3bb02e1856b 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1856,6 +1856,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { NULL, NULL, NULL}, + /* 51: CD_HAIRLENGTH */ + {sizeof(float), "float", 1, NULL, NULL, NULL, NULL, NULL, NULL}, }; static const char *LAYERTYPENAMES[CD_NUMTYPES] = { @@ -1912,6 +1914,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDPropFloat3", "CDPropFloat2", "CDPropBoolean", + "CDHairLength", }; const CustomData_MeshMasks CD_MASK_BAREMESH = { diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 49780abc6f4..ea60dd0753e 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -255,7 +255,7 @@ static void eevee_cryptomatte_hair_cache_populate(EEVEE_Data *vedata, { DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create( vedata, sldata, ob, material, true); - DRW_shgroup_hair_create_sub(ob, psys, md, grp); + DRW_shgroup_hair_create_sub(ob, psys, md, grp, NULL); } void EEVEE_cryptomatte_object_hair_cache_populate(EEVEE_Data *vedata, diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 9ecb737192e..5f45e2184aa 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -769,15 +769,15 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, 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); + *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_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); + *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; } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index 2e200c8e053..e8c2514d908 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -269,7 +269,7 @@ void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), 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]; - grp = DRW_shgroup_hair_create_sub(ob, psys, md, effects->motion_blur.hair_grp); + 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]); DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 635aa7cef25..a5281427fa8 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -238,7 +238,7 @@ static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, workbench_image_hair_setup(wpd, ob, matnr, ima, NULL, state) : workbench_material_hair_setup(wpd, ob, matnr, color_type); - DRW_shgroup_hair_create_sub(ob, psys, md, grp); + DRW_shgroup_hair_create_sub(ob, psys, md, grp, NULL); } /** 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(); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index bb1ebc0e85d..bbe939b546b 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -656,6 +656,8 @@ static const char *attr_prefix_get(CustomDataType type) return "c"; case CD_AUTO_FROM_NAME: return "a"; + case CD_HAIRLENGTH: + return "hl"; default: BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!"); return ""; @@ -675,7 +677,12 @@ static char *code_generate_interface(GPUNodeGraph *graph, int builtins) BLI_dynstr_append(ds, "\n"); LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { - BLI_dynstr_appendf(ds, "%s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id); + if (attr->type == CD_HAIRLENGTH) { + BLI_dynstr_appendf(ds, "float var%d;\n", attr->id); + } + else { + BLI_dynstr_appendf(ds, "%s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id); + } } if (builtins & GPU_BARYCENTRIC_TEXCO) { BLI_dynstr_append(ds, "vec2 barycentricTexCo;\n"); @@ -711,6 +718,11 @@ static char *code_generate_vertex(GPUNodeGraph *graph, BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n"); } + if (attr->type == CD_HAIRLENGTH) + { + BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl); + BLI_dynstr_append(ds, "DEFINE_ATTR(float, hairLen);\n"); + } else if (attr->name[0] == '\0') { BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s);\n", type_str, prefix); BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, prefix); @@ -755,6 +767,10 @@ static char *code_generate_vertex(GPUNodeGraph *graph, BLI_dynstr_appendf( ds, " var%d = orco_get(position, modelmatinv, OrcoTexCoFactors, orco);\n", attr->id); } + else if (attr->type == CD_HAIRLENGTH) { + BLI_dynstr_appendf( + ds, " var%d = hair_len_get(hair_get_strand_id(), hairLen);\n", attr->id); + } else { const char *type_str = gpu_data_type_to_string(attr->gputype); BLI_dynstr_appendf(ds, " var%d = GET_ATTR(%s, att%d);\n", attr->id, type_str, attr->id); diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl index f7bf3d33361..193a4190cbf 100644 --- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl @@ -42,6 +42,11 @@ vec3 orco_get(vec3 local_pos, mat4 modelmatinv, vec4 orco_madd[2], const sampler return orco_madd[0].xyz + orco * orco_madd[1].xyz; } +float hair_len_get(int id, const samplerBuffer len) +{ + return texelFetch(len, id).x; +} + vec4 tangent_get(const samplerBuffer attr, mat3 normalmat) { /* Unsupported */ @@ -71,6 +76,11 @@ vec3 orco_get(vec3 local_pos, mat4 modelmatinv, vec4 orco_madd[2], vec4 orco) } } +float hair_len_get(int id, const float len) +{ + return len; +} + vec4 tangent_get(vec4 attr, mat3 normalmat) { vec4 tangent; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl index 6330daa4391..6ffa6b59572 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl @@ -10,12 +10,15 @@ float wang_hash_noise(uint s) return fract(float(s) / 4294967296.0); } -void node_hair_info(out float is_strand, +void node_hair_info(float hair_length, + out float is_strand, out float intercept, + out float length, out float thickness, out vec3 tangent, out float random) { + length = hair_length; #ifdef HAIR_SHADER is_strand = 1.0; intercept = hairTime; diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 6acea8da15f..36bdd4915ff 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -84,7 +84,8 @@ typedef struct CustomData { * MUST be >= CD_NUMTYPES, but we can't use a define here. * Correct size is ensured in CustomData_update_typemap assert(). */ - int typemap[51]; + int typemap[52]; + char _pad[4]; /** Number of layers, size of layers array. */ int totlayer, maxlayer; /** In editmode, total size of all data layers. */ @@ -166,7 +167,9 @@ typedef enum CustomDataType { CD_PROP_BOOL = 50, - CD_NUMTYPES = 51, + CD_HAIRLENGTH = 51, + + CD_NUMTYPES = 52, } CustomDataType; /* Bits for CustomDataMask */ @@ -220,6 +223,8 @@ typedef enum CustomDataType { #define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) #define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL) +#define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH) + /** Multires loop data. */ #define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.c index 843185befb6..559c5cf7ae8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.c @@ -22,6 +22,7 @@ static bNodeSocketTemplate outputs[] = { {SOCK_FLOAT, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, {SOCK_FLOAT, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + {SOCK_FLOAT, N_("Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, {SOCK_FLOAT, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, {SOCK_VECTOR, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, // { SOCK_FLOAT, 0, N_("Fade"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, @@ -35,7 +36,11 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, node, "node_hair_info", in, out); + /* Length: don't request length if not needed. */ + const static float zero = 0; + GPUNodeLink *length_link = (!out[2].hasoutput) ? GPU_constant(&zero) : + GPU_attribute(mat, CD_HAIRLENGTH, ""); + return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link); } /* node type definition */ |