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:
authorLukas Tönne <lukas.toenne@gmail.com>2017-08-03 22:27:33 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2017-08-03 22:27:33 +0300
commit9feec51214d811537f7fb9fe0af579117ee007f7 (patch)
treef26dbb36e074751dae69c74b55daa1dc93a87bcd
parente34ba9fb7a91ef9be9109eaae5242cd4b3d7a22c (diff)
Subdivision of hair fibers for smoother shading.
Subdivision works on the parent strands for efficiency. The fibers lengths are based on the final subdivided length of parents, so no changes to the shader are required. This would be nicer with a tesselation shader, but this feature is not available in Blender 2.8.
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py1
-rw-r--r--source/blender/blenkernel/BKE_editstrands.h10
-rw-r--r--source/blender/blenkernel/BKE_hair.h6
-rw-r--r--source/blender/blenkernel/intern/editstrands.c18
-rw-r--r--source/blender/blenkernel/intern/hair.c124
-rw-r--r--source/blender/blenkernel/intern/scene.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c2
-rw-r--r--source/blender/draw/intern/draw_cache.c4
-rw-r--r--source/blender/draw/intern/draw_cache.h2
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_strands.c16
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c7
13 files changed, 141 insertions, 54 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 8056b14dc70..8a438cf9802 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -57,6 +57,7 @@ class VIEW3D_HT_header(Header):
row.prop(toolsettings.hair_edit, "hair_draw_mode", text="", expand=True)
if toolsettings.hair_edit.hair_draw_mode == 'FIBERS':
row.prop(toolsettings.hair_edit, "hair_draw_size", text="Size")
+ row.prop(toolsettings.hair_edit, "hair_draw_subdivision", text="Subdivide")
# Occlude geometry
if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or
diff --git a/source/blender/blenkernel/BKE_editstrands.h b/source/blender/blenkernel/BKE_editstrands.h
index e5858160f65..1e0ed8cf3c4 100644
--- a/source/blender/blenkernel/BKE_editstrands.h
+++ b/source/blender/blenkernel/BKE_editstrands.h
@@ -84,12 +84,10 @@ void BKE_editstrands_free(struct BMEditStrands *es);
bool BKE_editstrands_hair_ensure(struct BMEditStrands *es);
void BKE_editstrands_hair_free(struct BMEditStrands *es);
-int* BKE_editstrands_hair_get_fiber_lengths(struct BMEditStrands *es);
-void BKE_editstrands_hair_get_texture_buffer_size(struct BMEditStrands *es, int *r_size,
- int *r_strand_map_start,
- int *r_strand_vertex_start,
- int *r_fiber_start);
-void BKE_editstrands_hair_get_texture_buffer(struct BMEditStrands *es, void *texbuffer);
+int* BKE_editstrands_hair_get_fiber_lengths(struct BMEditStrands *es, int subdiv);
+void BKE_editstrands_hair_get_texture_buffer_size(struct BMEditStrands *es, int subdiv, int *r_size,
+ int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start);
+void BKE_editstrands_hair_get_texture_buffer(struct BMEditStrands *es, int subdiv, void *texbuffer);
/* === Constraints === */
diff --git a/source/blender/blenkernel/BKE_hair.h b/source/blender/blenkernel/BKE_hair.h
index 5eafc14e66f..367741fb4fe 100644
--- a/source/blender/blenkernel/BKE_hair.h
+++ b/source/blender/blenkernel/BKE_hair.h
@@ -66,13 +66,13 @@ struct HairFiber* BKE_hair_fibers_create(const struct StrandsView *strands,
unsigned int seed);
int* BKE_hair_get_fiber_lengths(const struct HairFiber *fibers, int totfibers,
- const struct StrandsView *strands);
+ const struct StrandsView *strands, int subdiv);
-void BKE_hair_get_texture_buffer_size(const struct StrandsView *strands, int totfibers,
+void BKE_hair_get_texture_buffer_size(const struct StrandsView *strands, int totfibers, int subdiv,
int *r_size, int *r_strand_map_start,
int *r_strand_vertex_start, int *r_fiber_start);
void BKE_hair_get_texture_buffer(const struct StrandsView *strands, struct DerivedMesh *scalp,
- const struct HairFiber *fibers, int totfibers,
+ const struct HairFiber *fibers, int totfibers, int subdiv,
void *texbuffer);
#endif
diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c
index 0fe286a5d3a..8cfc0bb606c 100644
--- a/source/blender/blenkernel/intern/editstrands.c
+++ b/source/blender/blenkernel/intern/editstrands.c
@@ -233,26 +233,24 @@ void BKE_editstrands_hair_free(BMEditStrands *es)
}
}
-int* BKE_editstrands_hair_get_fiber_lengths(BMEditStrands *es)
+int* BKE_editstrands_hair_get_fiber_lengths(BMEditStrands *es, int subdiv)
{
EditStrandsView strands = editstrands_get_view(es);
- return BKE_hair_get_fiber_lengths(es->hair_fibers, es->hair_totfibers, &strands.base);
+ return BKE_hair_get_fiber_lengths(es->hair_fibers, es->hair_totfibers, &strands.base, subdiv);
}
-void BKE_editstrands_hair_get_texture_buffer_size(BMEditStrands *es, int *r_size,
- int *r_strand_map_start,
- int *r_strand_vertex_start,
- int *r_fiber_start)
+void BKE_editstrands_hair_get_texture_buffer_size(BMEditStrands *es, int subdiv, int *r_size,
+ int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start)
{
EditStrandsView strands = editstrands_get_view(es);
- BKE_hair_get_texture_buffer_size(&strands.base, es->hair_totfibers,
- r_size, r_strand_map_start, r_strand_vertex_start, r_fiber_start);
+ BKE_hair_get_texture_buffer_size(&strands.base, es->hair_totfibers, subdiv, r_size,
+ r_strand_map_start, r_strand_vertex_start, r_fiber_start);
}
-void BKE_editstrands_hair_get_texture_buffer(BMEditStrands *es, void *texbuffer)
+void BKE_editstrands_hair_get_texture_buffer(BMEditStrands *es, int subdiv, void *texbuffer)
{
EditStrandsView strands = editstrands_get_view(es);
- BKE_hair_get_texture_buffer(&strands.base, es->root_dm, es->hair_fibers, es->hair_totfibers, texbuffer);
+ BKE_hair_get_texture_buffer(&strands.base, es->root_dm, es->hair_fibers, es->hair_totfibers, subdiv, texbuffer);
}
/* === Constraints === */
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index 59677a25bc1..ee02d92c193 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -256,13 +256,26 @@ HairFiber* BKE_hair_fibers_create(const StrandsView *strands,
return fibers;
}
-int* BKE_hair_get_fiber_lengths(const HairFiber *fibers, int totfibers, const StrandsView *strands)
+static int hair_get_strand_subdiv_numverts(int numstrands, int numverts, int subdiv)
+{
+ return ((numverts - numstrands) << subdiv) + numstrands;
+}
+
+static void hair_get_strand_subdiv_lengths(int *lengths, const int *orig_lengths, int num_strands, int subdiv)
+{
+ for (int i = 0; i < num_strands; ++i) {
+ lengths[i] = ((orig_lengths[i] - 1) << subdiv) + 1;
+ }
+}
+
+int* BKE_hair_get_fiber_lengths(const HairFiber *fibers, int totfibers, const StrandsView *strands, int subdiv)
{
int *fiber_length = MEM_mallocN(sizeof(int) * totfibers, "fiber length");
const int num_strands = strands->get_num_strands(strands);
- int *strand_length = MEM_mallocN(sizeof(int) * num_strands, "strand length");
- strands->get_strand_lengths(strands, strand_length);
+ int *lengths = MEM_mallocN(sizeof(int) * num_strands, "strand length");
+ strands->get_strand_lengths(strands, lengths);
+ hair_get_strand_subdiv_lengths(lengths, lengths, num_strands, subdiv);
for (int i = 0; i < totfibers; ++i) {
@@ -276,14 +289,14 @@ int* BKE_hair_get_fiber_lengths(const HairFiber *fibers, int totfibers, const St
}
BLI_assert(si < num_strands);
- fiblen += (float)strand_length[si] * sw;
+ fiblen += (float)lengths[si] * sw;
}
// use rounded number of segments
fiber_length[i] = (int)(fiblen + 0.5f);
}
- MEM_freeN(strand_length);
+ MEM_freeN(lengths);
return fiber_length;
}
@@ -328,8 +341,8 @@ static void hair_strand_transport_frame(const float co1[3], const float co2[3],
copy_v3_v3(prev_nor, r_nor);
}
-static void hair_strand_calc_verts(const float (*positions)[3], int num_verts, float rootmat[3][3],
- HairStrandVertexTextureBuffer *strand)
+static void hair_strand_calc_vectors(const float (*positions)[3], int num_verts, float rootmat[3][3],
+ HairStrandVertexTextureBuffer *strand)
{
for (int i = 0; i < num_verts; ++i) {
copy_v3_v3(strand[i].co, positions[i]);
@@ -360,6 +373,50 @@ static void hair_strand_calc_verts(const float (*positions)[3], int num_verts, f
}
}
+static int hair_strand_subdivide(float (*verts)[3], const float (*verts_orig)[3], int numverts_orig, int subdiv)
+{
+ {
+ /* Move vertex positions from the dense array to their initial configuration for subdivision. */
+ const int step = (1 << subdiv);
+ const float (*src)[3] = verts_orig;
+ float (*dst)[3] = verts;
+ for (int i = 0; i < numverts_orig; ++i) {
+ copy_v3_v3(*dst, *src);
+
+ ++src;
+ dst += step;
+ }
+ }
+
+ /* Subdivide */
+ for (int d = 0; d < subdiv; ++d) {
+ const int num_edges = (numverts_orig - 1) << d;
+ const int hstep = 1 << (subdiv - d - 1);
+ const int step = 1 << (subdiv - d);
+
+ /* Calculate edge points */
+ {
+ int index = 0;
+ for (int k = 0; k < num_edges; ++k, index += step) {
+ add_v3_v3v3(verts[index + hstep], verts[index], verts[index + step]);
+ mul_v3_fl(verts[index + hstep], 0.5f);
+ }
+ }
+
+ /* Move original points */
+ {
+ int index = step;
+ for (int k = 1; k < num_edges; ++k, index += step) {
+ add_v3_v3v3(verts[index], verts[index - hstep], verts[index + hstep]);
+ mul_v3_fl(verts[index], 0.5f);
+ }
+ }
+ }
+
+ const int num_verts = ((numverts_orig - 1) << subdiv) + 1;
+ return num_verts;
+}
+
static void hair_get_fiber_buffer(const HairFiber *fibers, int totfibers, DerivedMesh *scalp,
HairFiberTextureBuffer *fiber_buf)
{
@@ -374,60 +431,85 @@ static void hair_get_fiber_buffer(const HairFiber *fibers, int totfibers, Derive
}
}
-void BKE_hair_get_texture_buffer_size(const StrandsView *strands, int totfibers,
+void BKE_hair_get_texture_buffer_size(const StrandsView *strands, int totfibers, int subdiv,
int *r_size, int *r_strand_map_start,
int *r_strand_vertex_start, int *r_fiber_start)
{
const int totstrands = strands->get_num_strands(strands);
const int totverts = strands->get_num_verts(strands);
+ const int totverts_subdiv = hair_get_strand_subdiv_numverts(totstrands, totverts, subdiv);
*r_strand_map_start = 0;
*r_strand_vertex_start = *r_strand_map_start + totstrands * sizeof(HairStrandMapTextureBuffer);
- *r_fiber_start = *r_strand_vertex_start + totverts * sizeof(HairStrandVertexTextureBuffer);
+ *r_fiber_start = *r_strand_vertex_start + totverts_subdiv * sizeof(HairStrandVertexTextureBuffer);
*r_size = *r_fiber_start + totfibers * sizeof(HairFiberTextureBuffer);
}
void BKE_hair_get_texture_buffer(const StrandsView *strands, DerivedMesh *scalp,
- const HairFiber *fibers, int totfibers,
+ const HairFiber *fibers, int totfibers, int subdiv,
void *buffer)
{
const int totstrands = strands->get_num_strands(strands);
- const int totverts = strands->get_num_verts(strands);
+ const int totverts_orig = strands->get_num_verts(strands);
+ const int totverts = hair_get_strand_subdiv_numverts(totstrands, totverts_orig, subdiv);
const int strand_map_start = 0;
const int strand_vertex_start = strand_map_start + totstrands * sizeof(HairStrandMapTextureBuffer);
const int fiber_start = strand_vertex_start + totverts * sizeof(HairStrandVertexTextureBuffer);
- int *lengths = MEM_mallocN(sizeof(int) * totstrands, "strand lengths");
+ int *lengths_orig = MEM_mallocN(sizeof(int) * totstrands, "strand lengths");
+ float (*positions_orig)[3] = MEM_mallocN(sizeof(float[3]) * totverts_orig, "strand vertex positions");
MeshSample *roots = MEM_mallocN(sizeof(MeshSample) * totstrands, "strand roots");
- float (*positions)[3] = MEM_mallocN(sizeof(float[3]) * totverts, "strand vertex positions");
-
- strands->get_strand_lengths(strands, lengths);
+ strands->get_strand_lengths(strands, lengths_orig);
+ strands->get_strand_vertices(strands, positions_orig);
strands->get_strand_roots(strands, roots);
- strands->get_strand_vertices(strands, positions);
+
+ int *lengths;
+ float (*positions)[3];
+ if (subdiv > 0) {
+ lengths = MEM_mallocN(sizeof(int) * totstrands, "strand lengths subdivided");
+ hair_get_strand_subdiv_lengths(lengths, lengths_orig, totstrands, subdiv);
+
+ positions = MEM_mallocN(sizeof(float[3]) * totverts, "strand vertex positions subdivided");
+ }
+ else {
+ lengths = lengths_orig;
+ positions = positions_orig;
+ }
HairStrandMapTextureBuffer *smap = (HairStrandMapTextureBuffer*)((char*)buffer + strand_map_start);
HairStrandVertexTextureBuffer *svert = (HairStrandVertexTextureBuffer*)((char*)buffer + strand_vertex_start);
- unsigned int vertex_start = 0;
+ int vertex_orig_start = 0;
+ int vertex_start = 0;
for (int i = 0; i < totstrands; ++i) {
- const unsigned int len = lengths[i];
+ const int len_orig = lengths_orig[i];
+ const int len = lengths[i];
smap->vertex_start = vertex_start;
smap->vertex_count = len;
+ if (subdiv > 0) {
+ hair_strand_subdivide(positions + vertex_start, positions_orig + vertex_orig_start, len_orig, subdiv);
+ }
+
{
float pos[3];
float matrix[3][3];
BKE_mesh_sample_eval(scalp, &roots[i], pos, matrix[2], matrix[0]);
cross_v3_v3v3(matrix[1], matrix[2], matrix[0]);
- hair_strand_calc_verts(positions + vertex_start, len, matrix, svert);
+ hair_strand_calc_vectors(positions + vertex_start, len, matrix, svert);
}
+ vertex_orig_start += len_orig;
vertex_start += len;
++smap;
svert += len;
}
- MEM_freeN(lengths);
+ MEM_freeN(lengths_orig);
+ MEM_freeN(positions_orig);
MEM_freeN(roots);
- MEM_freeN(positions);
+ if (subdiv > 0) {
+ MEM_freeN(lengths);
+ MEM_freeN(positions);
+ }
hair_get_fiber_buffer(fibers, totfibers, scalp, (HairFiberTextureBuffer*)((char*)buffer + fiber_start));
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index e2fcef83abb..eada47fbb5f 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -802,6 +802,7 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->hair_edit.select_mode = HAIR_SELECT_VERTEX;
sce->toolsettings->hair_edit.hair_draw_mode = HAIR_DRAW_FIBERS;
sce->toolsettings->hair_edit.hair_draw_size = 2.5f;
+ sce->toolsettings->hair_edit.hair_draw_subdiv = 2;
sce->physics_settings.gravity[0] = 0.0f;
sce->physics_settings.gravity[1] = 0.0f;
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index a50b5b62e62..9772666d3ae 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -1136,7 +1136,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
use_fibers = true;
copy_m4_m4(mat, ob->obmat);
- hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, &fiber_buffer);
+ hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer);
if (!edit->texture) {
edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height,
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index f2772c47d67..a4753c9b55b 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -2610,8 +2610,8 @@ Gwn_Batch *DRW_cache_editstrands_get_wires(struct BMEditStrands *es)
return DRW_editstrands_batch_cache_get_wires(es);
}
-Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons,
+Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv,
const struct DRWHairFiberTextureBuffer **r_buffer)
{
- return DRW_editstrands_batch_cache_get_hair_fibers(es, use_ribbons, r_buffer);
+ return DRW_editstrands_batch_cache_get_hair_fibers(es, use_ribbons, subdiv, r_buffer);
}
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index ebf4dbafe2c..c536bd81084 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -164,7 +164,7 @@ struct Gwn_Batch *DRW_cache_editstrands_get_roots(struct BMEditStrands *es);
struct Gwn_Batch *DRW_cache_editstrands_get_points(struct BMEditStrands *es);
struct Gwn_Batch *DRW_cache_editstrands_get_wires(struct BMEditStrands *es);
-struct Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons,
+struct Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv,
const struct DRWHairFiberTextureBuffer **r_buffer);
#endif /* __DRAW_CACHE_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 9c1ad374de1..a6f4c486e2f 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -112,7 +112,7 @@ struct Gwn_Batch *DRW_editstrands_batch_cache_get_wires(struct BMEditStrands *es
struct Gwn_Batch *DRW_editstrands_batch_cache_get_tips(struct BMEditStrands *es);
struct Gwn_Batch *DRW_editstrands_batch_cache_get_roots(struct BMEditStrands *es);
struct Gwn_Batch *DRW_editstrands_batch_cache_get_points(struct BMEditStrands *es);
-struct Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons,
+struct Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv,
const struct DRWHairFiberTextureBuffer **r_buffer);
#endif /* __DRAW_CACHE_IMPL_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl_strands.c b/source/blender/draw/intern/draw_cache_impl_strands.c
index 2d57d7e20ac..d3e9406fcfb 100644
--- a/source/blender/draw/intern/draw_cache_impl_strands.c
+++ b/source/blender/draw/intern/draw_cache_impl_strands.c
@@ -364,12 +364,12 @@ Gwn_Batch *DRW_editstrands_batch_cache_get_points(BMEditStrands *es)
return cache->points;
}
-static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, StrandsBatchCache *cache, bool use_ribbons)
+static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, StrandsBatchCache *cache, bool use_ribbons, int subdiv)
{
GWN_VERTBUF_DISCARD_SAFE(cache->hair.verts);
GWN_INDEXBUF_DISCARD_SAFE(cache->hair.segments);
- int *fiber_lengths = BKE_editstrands_hair_get_fiber_lengths(es);
+ int *fiber_lengths = BKE_editstrands_hair_get_fiber_lengths(es, subdiv);
int totpoint = 0;
for (int i = 0; i < es->hair_totfibers; ++i) {
totpoint += fiber_lengths[i];
@@ -446,7 +446,7 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand
cache->hair.segments = GWN_indexbuf_build(&elb);
}
-static void editstrands_batch_cache_ensure_hair_fiber_texbuffer(BMEditStrands *es, StrandsBatchCache *cache, bool UNUSED(use_ribbons))
+static void editstrands_batch_cache_ensure_hair_fiber_texbuffer(BMEditStrands *es, StrandsBatchCache *cache, bool UNUSED(use_ribbons), int subdiv)
{
DRWHairFiberTextureBuffer *buffer = &cache->hair.texbuffer;
static const int elemsize = 8;
@@ -455,7 +455,7 @@ static void editstrands_batch_cache_ensure_hair_fiber_texbuffer(BMEditStrands *e
// Offsets in bytes
int b_size, b_strand_map_start, b_strand_vertex_start, b_fiber_start;
- BKE_editstrands_hair_get_texture_buffer_size(es, &b_size,
+ BKE_editstrands_hair_get_texture_buffer_size(es, subdiv, &b_size,
&b_strand_map_start, &b_strand_vertex_start, &b_fiber_start);
// Pad for alignment
b_size += align - b_size % align;
@@ -465,7 +465,7 @@ static void editstrands_batch_cache_ensure_hair_fiber_texbuffer(BMEditStrands *e
const int height = size / width;
buffer->data = MEM_mallocN(b_size, "hair fiber texture buffer");
- BKE_editstrands_hair_get_texture_buffer(es, buffer->data);
+ BKE_editstrands_hair_get_texture_buffer(es, subdiv, buffer->data);
buffer->width = width;
buffer->height = height;
@@ -474,7 +474,7 @@ static void editstrands_batch_cache_ensure_hair_fiber_texbuffer(BMEditStrands *e
buffer->fiber_start = b_fiber_start / elemsize;
}
-Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(BMEditStrands *es, bool use_ribbons,
+Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(BMEditStrands *es, bool use_ribbons, int subdiv,
const DRWHairFiberTextureBuffer **r_buffer)
{
StrandsBatchCache *cache = editstrands_batch_cache_get(es);
@@ -484,13 +484,13 @@ Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(BMEditStrands *es, bool u
}
if (cache->hair.fibers == NULL) {
- editstrands_batch_cache_ensure_hair_fibers(es, cache, use_ribbons);
+ editstrands_batch_cache_ensure_hair_fibers(es, cache, use_ribbons, subdiv);
Gwn_PrimType prim_type = use_ribbons ? GWN_PRIM_TRIS : GWN_PRIM_LINES;
cache->hair.fibers = GWN_batch_create(prim_type, cache->hair.verts, cache->hair.segments);
cache->hair.use_ribbons = use_ribbons;
- editstrands_batch_cache_ensure_hair_fiber_texbuffer(es, cache, use_ribbons);
+ editstrands_batch_cache_ensure_hair_fiber_texbuffer(es, cache, use_ribbons, subdiv);
}
if (r_buffer) {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index b73c1aa63a6..83747527432 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1145,7 +1145,7 @@ typedef struct HairEditSettings {
short select_mode;
short hair_draw_mode;
float hair_draw_size;
- int pad;
+ int hair_draw_subdiv;
struct Brush *brush;
struct Object *shape_object;
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 83c47be3496..b72e88cd79f 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -1206,6 +1206,13 @@ static void rna_def_hair_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hair Draw Size", "Width of hair fibers in pixels");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_HairEdit_update");
+ prop = RNA_def_property(srna, "hair_draw_subdivision", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "hair_draw_subdiv");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_range(prop, 0, 5, 1, -1);
+ RNA_def_property_ui_text(prop, "Hair Draw Subdivision", "Subdivide hair fibers");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_HairEdit_update");
+
prop = RNA_def_property(srna, "shape_object", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Shape Object", "Outer shape to use for tools");