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
This commit is contained in:
parent
0f764ade1a
commit
6a88f83d67
Notes:
blender-bot
2023-02-14 09:48:23 +01:00
Referenced by issue #91734, Crash snapping mesh if a beveled curve is present Referenced by issue #91697, EEVEE regression: Generated texture coordinates completly missing
|
@ -283,10 +283,13 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
|
|||
return;
|
||||
|
||||
Attribute *attr_intercept = NULL;
|
||||
Attribute *attr_length = NULL;
|
||||
Attribute *attr_random = NULL;
|
||||
|
||||
if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
|
||||
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
|
||||
if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH))
|
||||
attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
|
||||
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM))
|
||||
attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
|
||||
|
||||
|
@ -336,6 +339,11 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
|
|||
num_curve_keys++;
|
||||
}
|
||||
|
||||
if (attr_length != NULL)
|
||||
{
|
||||
attr_length->add(CData->curve_length[curve]);
|
||||
}
|
||||
|
||||
if (attr_random != NULL) {
|
||||
attr_random->add(hash_uint2_to_float(num_curves, 0));
|
||||
}
|
||||
|
@ -657,11 +665,16 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
|||
|
||||
/* Add requested attributes. */
|
||||
Attribute *attr_intercept = NULL;
|
||||
Attribute *attr_length = NULL;
|
||||
Attribute *attr_random = NULL;
|
||||
|
||||
if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) {
|
||||
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
|
||||
}
|
||||
if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH))
|
||||
{
|
||||
attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
|
||||
}
|
||||
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
|
||||
attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
|
||||
}
|
||||
|
@ -714,6 +727,11 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
|
|||
}
|
||||
}
|
||||
|
||||
if (attr_length)
|
||||
{
|
||||
attr_length->add(length);
|
||||
}
|
||||
|
||||
/* Random number per curve. */
|
||||
if (attr_random != NULL) {
|
||||
attr_random->add(hash_uint2_to_float(b_curve.index(), 0));
|
||||
|
|
|
@ -572,6 +572,7 @@ typedef enum AttributeStandard {
|
|||
ATTR_STD_MOTION_VERTEX_NORMAL,
|
||||
ATTR_STD_PARTICLE,
|
||||
ATTR_STD_CURVE_INTERCEPT,
|
||||
ATTR_STD_CURVE_LENGTH,
|
||||
ATTR_STD_CURVE_RANDOM,
|
||||
ATTR_STD_PTEX_FACE_ID,
|
||||
ATTR_STD_PTEX_UV,
|
||||
|
|
|
@ -107,6 +107,7 @@ ustring OSLRenderServices::u_geom_undisplaced("geom:undisplaced");
|
|||
ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
|
||||
ustring OSLRenderServices::u_is_curve("geom:is_curve");
|
||||
ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
|
||||
ustring OSLRenderServices::u_curve_length("geom:curve_length");
|
||||
ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
|
||||
ustring OSLRenderServices::u_curve_random("geom:curve_random");
|
||||
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
|
||||
|
|
|
@ -294,6 +294,7 @@ class OSLRenderServices : public OSL::RendererServices {
|
|||
static ustring u_is_smooth;
|
||||
static ustring u_is_curve;
|
||||
static ustring u_curve_thickness;
|
||||
static ustring u_curve_length;
|
||||
static ustring u_curve_tangent_normal;
|
||||
static ustring u_curve_random;
|
||||
static ustring u_path_ray_length;
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
|
||||
shader node_hair_info(output float IsStrand = 0.0,
|
||||
output float Intercept = 0.0,
|
||||
output float Length = 0.0,
|
||||
output float Thickness = 0.0,
|
||||
output normal TangentNormal = N,
|
||||
output float Random = 0)
|
||||
{
|
||||
getattribute("geom:is_curve", IsStrand);
|
||||
getattribute("geom:curve_intercept", Intercept);
|
||||
getattribute("geom:curve_length", Length);
|
||||
getattribute("geom:curve_thickness", Thickness);
|
||||
getattribute("geom:curve_tangent_normal", TangentNormal);
|
||||
getattribute("geom:curve_random", Random);
|
||||
|
|
|
@ -213,6 +213,8 @@ ccl_device_noinline void svm_node_hair_info(
|
|||
}
|
||||
case NODE_INFO_CURVE_INTERCEPT:
|
||||
break; /* handled as attribute */
|
||||
case NODE_INFO_CURVE_LENGTH:
|
||||
break; /* handled as attribute */
|
||||
case NODE_INFO_CURVE_RANDOM:
|
||||
break; /* handled as attribute */
|
||||
case NODE_INFO_CURVE_THICKNESS: {
|
||||
|
|
|
@ -173,6 +173,7 @@ typedef enum NodeParticleInfo {
|
|||
typedef enum NodeHairInfo {
|
||||
NODE_INFO_CURVE_IS_STRAND,
|
||||
NODE_INFO_CURVE_INTERCEPT,
|
||||
NODE_INFO_CURVE_LENGTH,
|
||||
NODE_INFO_CURVE_THICKNESS,
|
||||
/* Fade for minimum hair width transiency. */
|
||||
// NODE_INFO_CURVE_FADE,
|
||||
|
|
|
@ -342,6 +342,8 @@ const char *Attribute::standard_name(AttributeStandard std)
|
|||
return "particle";
|
||||
case ATTR_STD_CURVE_INTERCEPT:
|
||||
return "curve_intercept";
|
||||
case ATTR_STD_CURVE_LENGTH:
|
||||
return "curve_length";
|
||||
case ATTR_STD_CURVE_RANDOM:
|
||||
return "curve_random";
|
||||
case ATTR_STD_PTEX_FACE_ID:
|
||||
|
@ -586,6 +588,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
|
|||
case ATTR_STD_CURVE_INTERCEPT:
|
||||
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
|
||||
break;
|
||||
case ATTR_STD_CURVE_LENGTH:
|
||||
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
|
||||
break;
|
||||
case ATTR_STD_CURVE_RANDOM:
|
||||
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE);
|
||||
break;
|
||||
|
|
|
@ -4368,6 +4368,7 @@ NODE_DEFINE(HairInfoNode)
|
|||
|
||||
SOCKET_OUT_FLOAT(is_strand, "Is Strand");
|
||||
SOCKET_OUT_FLOAT(intercept, "Intercept");
|
||||
SOCKET_OUT_FLOAT(size, "Length");
|
||||
SOCKET_OUT_FLOAT(thickness, "Thickness");
|
||||
SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
|
||||
#if 0 /* Output for minimum hair width transparency - deactivated. */
|
||||
|
@ -4390,6 +4391,9 @@ void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|||
if (!intercept_out->links.empty())
|
||||
attributes->add(ATTR_STD_CURVE_INTERCEPT);
|
||||
|
||||
if (!output("Length")->links.empty())
|
||||
attributes->add(ATTR_STD_CURVE_LENGTH);
|
||||
|
||||
if (!output("Random")->links.empty())
|
||||
attributes->add(ATTR_STD_CURVE_RANDOM);
|
||||
}
|
||||
|
@ -4412,6 +4416,12 @@ void HairInfoNode::compile(SVMCompiler &compiler)
|
|||
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
||||
}
|
||||
|
||||
out = output("Length");
|
||||
if (!out->links.empty()) {
|
||||
int attr = compiler.attribute(ATTR_STD_CURVE_LENGTH);
|
||||
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
||||
}
|
||||
|
||||
out = output("Thickness");
|
||||
if (!out->links.empty()) {
|
||||
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
GPUVertFormat length_format = {0};
|
||||
uint length_id = GPU_vertformat_attr_add(
|
||||
&length_format, "hairLength", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
|
||||
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);
|
||||
|
||||
hair_batch_cache_fill_segments_proc_pos(hair, &point_step, &length_step);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
GPUVertBufRaw pos_step;
|
||||
GPU_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step);
|
||||
|
||||
hair_batch_cache_fill_segments_proc_pos(hair, &pos_step);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue