diff options
Diffstat (limited to 'source/blender/blenkernel/intern/hair_draw.c')
-rw-r--r-- | source/blender/blenkernel/intern/hair_draw.c | 222 |
1 files changed, 77 insertions, 145 deletions
diff --git a/source/blender/blenkernel/intern/hair_draw.c b/source/blender/blenkernel/intern/hair_draw.c index 18b81b243d2..e88e3cdb3ca 100644 --- a/source/blender/blenkernel/intern/hair_draw.c +++ b/source/blender/blenkernel/intern/hair_draw.c @@ -49,7 +49,7 @@ HairDrawSettings* BKE_hair_draw_settings_new(void) HairDrawSettings *draw_settings = MEM_callocN(sizeof(HairDrawSettings), "hair draw settings"); draw_settings->follicle_mode = HAIR_DRAW_FOLLICLE_POINTS; - draw_settings->guide_mode = HAIR_DRAW_GUIDE_CURVES; + draw_settings->fiber_mode = HAIR_DRAW_FIBER_CURVES; draw_settings->shape_flag = HAIR_DRAW_CLOSE_TIP; draw_settings->shape = 0.0f; draw_settings->root_radius = 1.0f; @@ -103,11 +103,11 @@ static void hair_get_strand_buffer( HairStrandMapTextureBuffer *strand_map_buffer, HairStrandVertexTextureBuffer *strand_vertex_buffer) { - for (int i = 0; i < cache->totguidecurves; ++i) { - const HairGuideCurve *curve = &cache->guide_curves[i]; - const HairGuideVertex *verts = &cache->guide_verts[curve->vertstart]; - const float (*tangents)[3] = &cache->guide_tangents[curve->vertstart]; - const float (*normals)[3] = &cache->guide_normals[curve->vertstart]; + for (int i = 0; i < cache->totcurves; ++i) { + const HairFiberCurve *curve = &cache->fiber_curves[i]; + const HairFiberVertex *verts = &cache->fiber_verts[curve->vertstart]; + const float (*tangents)[3] = &cache->fiber_tangents[curve->vertstart]; + const float (*normals)[3] = &cache->fiber_normals[curve->vertstart]; HairStrandMapTextureBuffer *smap = &strand_map_buffer[i]; HairStrandVertexTextureBuffer *svert = &strand_vertex_buffer[curve->vertstart]; @@ -135,17 +135,20 @@ static void hair_get_strand_buffer( static void hair_get_fiber_buffer(const HairExportCache *cache, HairFiberTextureBuffer *fiber_buf) { - const int totfibers = cache->totfibercurves; + const int totfibers = cache->totfollicles; const HairFollicle *follicle = cache->follicles; HairFiberTextureBuffer *fb = fiber_buf; for (int i = 0; i < totfibers; ++i, ++fb, ++follicle) { - copy_v3_v3(fb->root_position, cache->fiber_root_position[i]); + copy_v3_v3(fb->root_position, cache->follicle_root_position[i]); - for (int k = 0; k < 4; ++k) - { - fb->parent_index[k] = follicle->parent_index[k]; - fb->parent_weight[k] = follicle->parent_weight[k]; - } + fb->parent_index[0] = follicle->curve; + fb->parent_index[1] = HAIR_CURVE_INDEX_NONE; + fb->parent_index[2] = HAIR_CURVE_INDEX_NONE; + fb->parent_index[3] = HAIR_CURVE_INDEX_NONE; + fb->parent_weight[0] = 1.0f; + fb->parent_weight[1] = 0.0f; + fb->parent_weight[2] = 0.0f; + fb->parent_weight[3] = 0.0f; } } @@ -157,9 +160,9 @@ void BKE_hair_get_texture_buffer_size( int *r_fiber_start) { *r_strand_map_start = 0; - *r_strand_vertex_start = *r_strand_map_start + cache->totguidecurves * sizeof(HairStrandMapTextureBuffer); - *r_fiber_start = *r_strand_vertex_start + cache->totguideverts * sizeof(HairStrandVertexTextureBuffer); - *r_size = *r_fiber_start + cache->totfibercurves * sizeof(HairFiberTextureBuffer); + *r_strand_vertex_start = *r_strand_map_start + cache->totcurves * sizeof(HairStrandMapTextureBuffer); + *r_fiber_start = *r_strand_vertex_start + cache->totverts * sizeof(HairStrandVertexTextureBuffer); + *r_size = *r_fiber_start + cache->totfollicles * sizeof(HairFiberTextureBuffer); } void BKE_hair_get_texture_buffer( @@ -202,146 +205,65 @@ void BKE_hair_batch_cache_free(HairSystem* hsys) /* === Fiber Curve Interpolation === */ /* NOTE: Keep this code in sync with the GLSL version! - * see common_hair_guides_lib.glsl + * see common_hair_fibers_lib.glsl */ -static void interpolate_parent_curve( - float curve_param, - int numverts, - const HairGuideVertex *verts, - const float (*tangents)[3], - const float (*normals)[3], - float r_co[3], - float r_tang[3], - float r_nor[3]) -{ - float maxlen = (float)(numverts - 1); - float arclength = curve_param * maxlen; - int segment = (int)(arclength); - float lerpfac; - if (segment < numverts-1) - { - lerpfac = arclength - floor(arclength); - } - else - { - segment = numverts-2; - lerpfac = 1.0f; - } - - mul_v3_v3fl(r_co, verts[segment].co, 1.0f - lerpfac); - madd_v3_v3fl(r_co, verts[segment + 1].co, lerpfac); - // Make relative to the parent root - sub_v3_v3(r_co, verts[0].co); - - mul_v3_v3fl(r_tang, tangents[segment], 1.0f - lerpfac); - madd_v3_v3fl(r_tang, tangents[segment + 1], lerpfac); - - mul_v3_v3fl(r_nor, normals[segment], 1.0f - lerpfac); - madd_v3_v3fl(r_nor, normals[segment + 1], lerpfac); -} - -static void hair_fiber_interpolate_vertex( - float curve_param, - int parent_numverts, - const HairGuideVertex *parent_verts, - const float (*parent_tangents)[3], - const float (*parent_normals)[3], - float parent_weight, - float r_co[3], - float r_tangent[3], - float r_target_matrix[3][3]) -{ - float pco[3], ptang[3], pnor[3]; - interpolate_parent_curve( - curve_param, - parent_numverts, - parent_verts, - parent_tangents, - parent_normals, - pco, - ptang, - pnor); - - madd_v3_v3fl(r_co, pco, parent_weight); - normalize_v3(ptang); - madd_v3_v3fl(r_tangent, ptang, parent_weight); - - if (r_target_matrix) - { - copy_v3_v3(r_target_matrix[0], pnor); - copy_v3_v3(r_target_matrix[1], ptang); - add_v3_v3v3(r_target_matrix[2], pco, parent_verts[0].co); - } -} - -static void hair_fiber_interpolate( - const HairExportCache* cache, - int fiber_index, +/* Subdivide a curve */ +static int hair_curve_subdivide( + const HairFiberCurve* curve, + const HairFiberVertex* verts, + int subdiv, int vertco_stride, float *r_vertco) { - const int numverts = cache->fiber_numverts[fiber_index]; - BLI_assert(numverts >= 2); - const float dcurve_param = 1.0f / (numverts - 1); - const float *rootco = cache->fiber_root_position[fiber_index]; - - // Initialize { - float *vert = r_vertco; - for (int i = 0; i < numverts; ++i, vert = POINTER_OFFSET(vert, vertco_stride)) - { - zero_v3(vert); + /* Move vertex positions from the dense array to their initial configuration for subdivision. + * Also add offset to ensure the curve starts on the scalp surface. + */ + const int step = (1 << subdiv) * vertco_stride; + BLI_assert(curve->numverts > 0); + + float *dst = r_vertco; + for (int i = 0; i < curve->numverts; ++i) { + copy_v3_v3(dst, verts[i].co); + dst = POINTER_OFFSET(dst, step); } } - // Add weighted data from each parent - for (int k = 0; k < 4; ++k) - { - const unsigned int parent_index = cache->follicles[fiber_index].parent_index[k]; - if (parent_index == HAIR_STRAND_INDEX_NONE) + /* Subdivide */ + for (int d = 0; d < subdiv; ++d) { + const int num_edges = (curve->numverts - 1) << d; + const int hstep = (1 << (subdiv - d - 1)) * vertco_stride; + const int step = (1 << (subdiv - d)) * vertco_stride; + + /* Calculate edge points */ { - continue; + float *p = r_vertco; + for (int k = 0; k < num_edges; ++k) { + float *ps = POINTER_OFFSET(p, step); + float *ph = POINTER_OFFSET(p, hstep); + add_v3_v3v3(ph, p, ps); + mul_v3_fl(ph, 0.5f); + p = ps; + } } - const float parent_weight = cache->follicles[fiber_index].parent_weight[k]; - const int parent_numverts = cache->guide_curves[parent_index].numverts; - const int parent_vertstart = cache->guide_curves[parent_index].vertstart; - const HairGuideVertex *parent_verts = &cache->guide_verts[parent_vertstart]; - const float (*parent_tangents)[3] = &cache->guide_tangents[parent_vertstart]; - const float (*parent_normals)[3] = &cache->guide_normals[parent_vertstart]; - - float *vert = r_vertco; - float curve_param = 0.0f; - for (int i = 0; i < numverts; ++i, vert = POINTER_OFFSET(vert, vertco_stride)) + /* Move original points */ { - float tangent[3]; - float target_matrix[3][3]; - - hair_fiber_interpolate_vertex( - curve_param, - parent_numverts, - parent_verts, - parent_tangents, - parent_normals, - parent_weight, - vert, - tangent, - target_matrix); - - curve_param += dcurve_param; + float *p = r_vertco; + for (int k = 1; k < num_edges; ++k) { + float *ps = POINTER_OFFSET(p, step); + float *ph = POINTER_OFFSET(p, hstep); + float *hp = POINTER_OFFSET(p, -hstep); + add_v3_v3v3(p, hp, ph); + mul_v3_fl(p, 0.5f); + p = ps; + } } } - /* Offset to the root - * Normalize tangents - */ - float *vert = r_vertco; - for (int i = 0; i < numverts; ++i, vert = POINTER_OFFSET(vert, vertco_stride)) - { - add_v3_v3(vert, rootco); -// r_tangent = normalize(r_tangent); - } + const int num_verts = ((curve->numverts - 1) << subdiv) + 1; + return num_verts; } /* === Render API === */ @@ -349,11 +271,18 @@ static void hair_fiber_interpolate( /* Calculate required size for render buffers. */ void BKE_hair_render_get_buffer_size( const HairExportCache* cache, + int subdiv, int *r_totcurves, int *r_totverts) { - *r_totcurves = cache->totfibercurves; - *r_totverts = cache->totfiberverts; + *r_totcurves = cache->totfollicles; + + const int subdiv_factor = 1 << subdiv; + for (int i = 0; i < cache->totfollicles; ++i) + { + const int numverts = cache->fiber_curves[cache->follicles[i].curve].numverts; + *r_totverts = (numverts - 1) * subdiv_factor + 1; + } } /* Create render data in existing buffers. @@ -361,6 +290,7 @@ void BKE_hair_render_get_buffer_size( */ void BKE_hair_render_fill_buffers( const HairExportCache* cache, + int subdiv, int vertco_stride, int *r_curvestart, int *r_curvelen, @@ -368,13 +298,15 @@ void BKE_hair_render_fill_buffers( { int vertstart = 0; float *vert = r_vertco; - for (int i = 0; i < cache->totfibercurves; ++i) + for (int i = 0; i < cache->totfollicles; ++i) { - const int numverts = cache->fiber_numverts[i]; + const HairFiberCurve *curve = &cache->fiber_curves[cache->follicles[i].curve]; + const HairFiberVertex *verts = &cache->fiber_verts[curve->vertstart]; + const int numverts = curve->numverts; r_curvestart[i] = vertstart; r_curvelen[i] = numverts; - hair_fiber_interpolate(cache, i, vertco_stride, vert); + hair_curve_subdivide(curve, verts, subdiv, vertco_stride, vert); vertstart += numverts; vert = POINTER_OFFSET(vert, vertco_stride * numverts); |