Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jbakker>2021-09-24 08:42:36 +0300
committerJeroen Bakker <jeroen@blender.org>2021-09-24 08:44:22 +0300
commit6a88f83d679f281d7adb3798ab4770069a63c2da (patch)
tree02b6e3870e7651c40c63eb23285e7f2ff3f2507e
parent0f764ade1a2fd8aa9c462dd5850e8be52aa203f5 (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
-rw-r--r--intern/cycles/blender/blender_curves.cpp18
-rw-r--r--intern/cycles/kernel/kernel_types.h1
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp1
-rw-r--r--intern/cycles/kernel/osl/osl_services.h1
-rw-r--r--intern/cycles/kernel/shaders/node_hair_info.osl2
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h2
-rw-r--r--intern/cycles/kernel/svm/svm_types.h1
-rw-r--r--intern/cycles/render/attribute.cpp5
-rw-r--r--intern/cycles/render/nodes.cpp10
-rw-r--r--source/blender/blenkernel/intern/customdata.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc3
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.c59
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c87
-rw-r--r--source/blender/draw/intern/draw_common.h4
-rw-r--r--source/blender/draw/intern/draw_hair.c16
-rw-r--r--source/blender/draw/intern/draw_hair_private.h6
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl6
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl5
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hair_info.c7
26 files changed, 223 insertions, 63 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 6fe5ea41fff..c7851e40543 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -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));
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 66b7310ab65..3cc42bf7a85 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -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,
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 396f42080e4..4fc46a255a8 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -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");
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 58accb46e7d..2a5400282b3 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -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;
diff --git a/intern/cycles/kernel/shaders/node_hair_info.osl b/intern/cycles/kernel/shaders/node_hair_info.osl
index ee08ea57e68..ddc2e28b83a 100644
--- a/intern/cycles/kernel/shaders/node_hair_info.osl
+++ b/intern/cycles/kernel/shaders/node_hair_info.osl
@@ -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);
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index 10e9f291d0e..432529eb061 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -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: {
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index c053be96c51..313bc3235b9 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -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,
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index ea5a5f50f2d..aaf21ad9fd2 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -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;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 03b79d7de3e..e5071c25730 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -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));
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 */