diff options
35 files changed, 1050 insertions, 1682 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 1518119eadc..88424991e8a 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -42,7 +42,7 @@ _modules = [ "properties_data_lightprobe", "properties_data_speaker", "properties_data_workspace", - "properties_hair", + "properties_hair_common", "properties_mask_common", "properties_material", "properties_object", diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index b6deaa39d9e..cd0617d8f26 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -20,7 +20,7 @@ import bpy from bpy.types import Panel from bpy.app.translations import pgettext_iface as iface_ - +from .properties_hair_common import draw_hair_display_settings class ModifierButtonsPanel: bl_space_type = 'PROPERTIES' @@ -1562,7 +1562,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.rest_source == 'BIND': layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind") - def FUR(self, layout, ob, md): + def HAIR(self, layout, ob, md): hsys = md.hair_system split = layout.split() @@ -1571,7 +1571,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.label("Follicles:") col.prop(md, "follicle_seed") col.prop(md, "follicle_count") - col.operator("object.fur_generate_follicles", text="Generate") + col.operator("object.hair_generate_follicles", text="Generate") col = split.column() @@ -1580,9 +1580,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(hsys, "material_slot", text="") col = layout.column() - col.label("Drawing:") - ds = md.draw_settings - col.prop(ds, "follicle_mode", expand=True) + col.label("Display Settings:") + draw_hair_display_settings(col, md.draw_settings) classes = ( diff --git a/release/scripts/startup/bl_ui/properties_hair.py b/release/scripts/startup/bl_ui/properties_hair_common.py index 2d234bf3f94..4ebfa464923 100644 --- a/release/scripts/startup/bl_ui/properties_hair.py +++ b/release/scripts/startup/bl_ui/properties_hair_common.py @@ -16,22 +16,43 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> + import bpy -from bpy.types import UIList -class HAIR_UL_groups(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): - group = item - if self.layout_type in {'DEFAULT', 'COMPACT'}: - layout.prop(group, "name", text="", emboss=False, icon_value=icon) - elif self.layout_type == 'GRID': - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) + +def draw_hair_display_settings(layout, settings): + col = layout.column(align=True) + col.label("Follicles:") + col.prop(settings, "follicle_mode", expand=True) + + col = layout.column(align=True) + col.label("Guide Curves:") + col.prop(settings, "guide_mode", expand=True) + + layout.prop(settings, "shape") + + col = layout.column(align=True) + col.prop(settings, "root_radius") + col.prop(settings, "tip_radius") + + col = layout.column() + col.prop(settings, "radius_scale") + col.prop(settings, "use_close_tip") + + +class HAIR_PT_display_settings: + # subclasses must define... + # ~ bl_space_type = 'PROPERTIES' + # ~ bl_region_type = 'WINDOW' + bl_label = "Hair Display Settings" + + def draw(self, context): + settings = context.draw_hair_display_settings + draw_hair_display_settings(self.layout, hair_display_settings) classes = ( - HAIR_UL_groups, ) if __name__ == "__main__": # only for live edit. diff --git a/source/blender/blenkernel/BKE_hair.h b/source/blender/blenkernel/BKE_hair.h index 73f8e3d9c12..e24effd9227 100644 --- a/source/blender/blenkernel/BKE_hair.h +++ b/source/blender/blenkernel/BKE_hair.h @@ -34,13 +34,13 @@ #include "BLI_utildefines.h" -static const unsigned int HAIR_STRAND_INDEX_NONE = 0xFFFFFFFF; +static const unsigned int HAIR_CURVE_INDEX_NONE = 0xFFFFFFFF; struct HairFollicle; struct HairPattern; struct HairSystem; struct HairDrawSettings; -struct HairGuideData; +struct HairCurveData; struct Mesh; struct MeshSample; struct MLoop; @@ -53,38 +53,38 @@ struct HairSystem* BKE_hair_copy(struct HairSystem *hsys); /* Delete a hair system */ void BKE_hair_free(struct HairSystem *hsys); -/* === Guide Strands === */ +/* === Fiber curves === */ -/* Allocate buffers for defining guide curves - * \param totcurves Number of guide curves to allocate +/* Allocate buffers for defining fiber curves + * \param totcurves Number of fiber curves to allocate */ -void BKE_hair_guide_curves_begin(struct HairSystem *hsys, int totcurves); +void BKE_hair_fiber_curves_begin(struct HairSystem *hsys, int totcurves); -/* Set properties of a guide curve - * \param index Index of the guide guide curve - * \param mesh_sample Origin of the guide curve on the scalp mesh. - * \param numverts Number of vertices in this guide curve +/* Set properties of a fiber curve + * \param index Index of the fiber curve + * \param mesh_sample Origin of the fiber curve on the scalp mesh. + * \param numverts Number of vertices in this fiber curve */ -void BKE_hair_set_guide_curve(struct HairSystem *hsys, int index, const struct MeshSample *mesh_sample, int numverts, +void BKE_hair_set_fiber_curve(struct HairSystem *hsys, int index, int numverts, float taper_length, float taper_thickness); -/* Finalize guide curve update */ -void BKE_hair_guide_curves_end(struct HairSystem *hsys); +/* Finalize fiber curve update */ +void BKE_hair_fiber_curves_end(struct HairSystem *hsys); -/* Set properties of a guide curve vertex - * \param index Index of the guide curve vertex. +/* Set properties of a fiber curve vertex + * \param index Index of the fiber curve vertex. * \param flag Flags to set on the vertex. * \param co Location of the vertex in object space. */ -void BKE_hair_set_guide_vertex(struct HairSystem *hsys, int index, int flag, const float co[3]); +void BKE_hair_set_fiber_vertex(struct HairSystem *hsys, int index, int flag, const float co[3]); -/* Set the hair guide data used by the hair system. +/* Set the hair fiber curve data used by the hair system. */ -void BKE_hair_set_hair_guides(struct HairSystem *hsys, struct HairGuideData *guides); +void BKE_hair_set_fiber_curves(struct HairSystem *hsys, struct HairCurveData *curves); -/* Remove all guide curves. +/* Remove all fiber curves. */ -void BKE_hair_clear_guides(struct HairSystem *hsys); +void BKE_hair_clear_fiber_curves(struct HairSystem *hsys); /* === Follicles === */ @@ -131,22 +131,19 @@ void BKE_hair_draw_settings_free(struct HairDrawSettings *draw_settings); /* Intermediate data for export */ typedef struct HairExportCache { - /* Per guide curve data */ - int totguidecurves; - struct HairGuideCurve *guide_curves; + /* Per fiber curve data */ + int totcurves; + struct HairFiberCurve *fiber_curves; - /* Per guide vertex data */ - int totguideverts; - struct HairGuideVertex *guide_verts; - float (*guide_tangents)[3]; /* Tangent vectors on guide curves */ - float (*guide_normals)[3]; /* Normal vectors on guide curves */ - - /* Per fiber data */ - int totfibercurves; - int totfiberverts; - int *fiber_numverts; /* Number of vertices in each fiber */ - float (*fiber_root_position)[3]; /* Root position of each fiber */ + /* Per fiber vertex data */ + int totverts; + struct HairFiberVertex *fiber_verts; + float (*fiber_tangents)[3]; /* Tangent vectors on fiber curves */ + float (*fiber_normals)[3]; /* Normal vectors on fiber curves */ + /* Per follicle data */ + int totfollicles; + float (*follicle_root_position)[3]; /* Root position of each follicle */ const struct HairFollicle *follicles; } HairExportCache; @@ -154,28 +151,24 @@ typedef struct HairExportCache typedef enum eHairExportCacheUpdateFlags { /* Follicle placement on the scalp mesh */ - HAIR_EXPORT_FIBER_ROOT_POSITIONS = (1 << 0), - /* Fiber vertex counts */ - HAIR_EXPORT_FIBER_VERTEX_COUNTS = (1 << 1), - /* Follicle parent indices and weights */ - HAIR_EXPORT_FOLLICLE_BINDING = (1 << 2), - /* Guide vertex positions (deform only) */ - HAIR_EXPORT_GUIDE_VERTICES = (1 << 3), - /* Guide curve number and vertex counts (topology changes) */ - HAIR_EXPORT_GUIDE_CURVES = (1 << 4), + HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS = (1 << 0), + /* Follicle curve index */ + HAIR_EXPORT_FOLLICLE_BINDING = (1 << 1), + /* Fiber vertex positions (deform only) */ + HAIR_EXPORT_FIBER_VERTICES = (1 << 2), + /* Fiber curve number and vertex counts (topology changes) */ + HAIR_EXPORT_FIBER_CURVES = (1 << 3), HAIR_EXPORT_ALL = - HAIR_EXPORT_FIBER_ROOT_POSITIONS | - HAIR_EXPORT_FIBER_VERTEX_COUNTS | + HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS | HAIR_EXPORT_FOLLICLE_BINDING | - HAIR_EXPORT_GUIDE_VERTICES | - HAIR_EXPORT_GUIDE_CURVES, - HAIR_EXPORT_GUIDES = - HAIR_EXPORT_GUIDE_VERTICES | - HAIR_EXPORT_GUIDE_CURVES, + HAIR_EXPORT_FIBER_VERTICES | + HAIR_EXPORT_FIBER_CURVES, + HAIR_EXPORT_FIBERS = + HAIR_EXPORT_FIBER_VERTICES | + HAIR_EXPORT_FIBER_CURVES, HAIR_EXPORT_FOLLICLES = - HAIR_EXPORT_FIBER_ROOT_POSITIONS | - HAIR_EXPORT_FIBER_VERTEX_COUNTS | + HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS | HAIR_EXPORT_FOLLICLE_BINDING, } eHairExportCacheUpdateFlags; @@ -227,6 +220,7 @@ void BKE_hair_get_texture_buffer( /* Calculate required size for render buffers. */ void BKE_hair_render_get_buffer_size( const struct HairExportCache* cache, + int subdiv, int *r_totcurves, int *r_totverts); @@ -235,6 +229,7 @@ void BKE_hair_render_get_buffer_size( */ void BKE_hair_render_fill_buffers( const struct HairExportCache* cache, + int subdiv, int vertco_stride, int *r_curvestart, int *r_curvelen, diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index 70ae53b58c8..5020f9774a9 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -73,13 +73,13 @@ HairSystem* BKE_hair_copy(HairSystem *hsys) nhsys->pattern->follicles = MEM_dupallocN(hsys->pattern->follicles); } - if (hsys->guides.curves) + if (hsys->curve_data.curves) { - nhsys->guides.curves = MEM_dupallocN(hsys->guides.curves); + nhsys->curve_data.curves = MEM_dupallocN(hsys->curve_data.curves); } - if (hsys->guides.verts) + if (hsys->curve_data.verts) { - nhsys->guides.verts = MEM_dupallocN(hsys->guides.verts); + nhsys->curve_data.verts = MEM_dupallocN(hsys->curve_data.verts); } nhsys->draw_batch_cache = NULL; @@ -92,13 +92,13 @@ void BKE_hair_free(HairSystem *hsys) { BKE_hair_batch_cache_free(hsys); - if (hsys->guides.curves) + if (hsys->curve_data.curves) { - MEM_freeN(hsys->guides.curves); + MEM_freeN(hsys->curve_data.curves); } - if (hsys->guides.verts) + if (hsys->curve_data.verts) { - MEM_freeN(hsys->guides.verts); + MEM_freeN(hsys->curve_data.verts); } if (hsys->pattern) @@ -216,25 +216,24 @@ void BKE_hair_generate_follicles_ex( /* ================================= */ -void BKE_hair_guide_curves_begin(HairSystem *hsys, int totcurves) +void BKE_hair_fiber_curves_begin(HairSystem *hsys, int totcurves) { - if (totcurves != hsys->guides.totcurves) + if (totcurves != hsys->curve_data.totcurves) { - hsys->guides.curves = MEM_reallocN(hsys->guides.curves, sizeof(HairGuideCurve) * totcurves); - hsys->guides.totcurves = totcurves; + hsys->curve_data.curves = MEM_reallocN(hsys->curve_data.curves, sizeof(HairFiberCurve) * totcurves); + hsys->curve_data.totcurves = totcurves; hsys->flag |= HAIR_SYSTEM_UPDATE_FOLLICLE_BINDING; BKE_hair_batch_cache_dirty(hsys, BKE_HAIR_BATCH_DIRTY_ALL); } } -void BKE_hair_set_guide_curve(HairSystem *hsys, int index, const MeshSample *mesh_sample, int numverts, +void BKE_hair_set_fiber_curve(HairSystem *hsys, int index, int numverts, float taper_length, float taper_thickness) { - BLI_assert(index <= hsys->guides.totcurves); + BLI_assert(index <= hsys->curve_data.totcurves); - HairGuideCurve *curve = &hsys->guides.curves[index]; - memcpy(&curve->mesh_sample, mesh_sample, sizeof(MeshSample)); + HairFiberCurve *curve = &hsys->curve_data.curves[index]; curve->numverts = numverts; curve->taper_length = taper_length; curve->taper_thickness = taper_thickness; @@ -246,83 +245,83 @@ void BKE_hair_set_guide_curve(HairSystem *hsys, int index, const MeshSample *mes /* Calculate vertex start indices on all curves based on length. * Returns the total number of vertices. */ -static int hair_guide_calc_vertstart(HairSystem *hsys) +static int hair_curve_calc_vertstart(HairSystem *hsys) { /* Recalculate vertex count and start offsets in curves */ int vertstart = 0; - for (int i = 0; i < hsys->guides.totcurves; ++i) + for (int i = 0; i < hsys->curve_data.totcurves; ++i) { - hsys->guides.curves[i].vertstart = vertstart; - vertstart += hsys->guides.curves[i].numverts; + hsys->curve_data.curves[i].vertstart = vertstart; + vertstart += hsys->curve_data.curves[i].numverts; } return vertstart; } -void BKE_hair_guide_curves_end(HairSystem *hsys) +void BKE_hair_fiber_curves_end(HairSystem *hsys) { - const int totverts = hair_guide_calc_vertstart(hsys); + const int totverts = hair_curve_calc_vertstart(hsys); - if (totverts != hsys->guides.totverts) + if (totverts != hsys->curve_data.totverts) { - hsys->guides.verts = MEM_reallocN(hsys->guides.verts, sizeof(HairGuideVertex) * totverts); - hsys->guides.totverts = totverts; + hsys->curve_data.verts = MEM_reallocN(hsys->curve_data.verts, sizeof(HairFiberVertex) * totverts); + hsys->curve_data.totverts = totverts; BKE_hair_batch_cache_dirty(hsys, BKE_HAIR_BATCH_DIRTY_ALL); } } -void BKE_hair_set_guide_vertex(HairSystem *hsys, int index, int flag, const float co[3]) +void BKE_hair_set_fiber_vertex(HairSystem *hsys, int index, int flag, const float co[3]) { - BLI_assert(index <= hsys->guides.totverts); + BLI_assert(index <= hsys->curve_data.totverts); - HairGuideVertex *vertex = &hsys->guides.verts[index]; + HairFiberVertex *vertex = &hsys->curve_data.verts[index]; vertex->flag = flag; copy_v3_v3(vertex->co, co); BKE_hair_batch_cache_dirty(hsys, BKE_HAIR_BATCH_DIRTY_ALL); } -void BKE_hair_set_hair_guides(HairSystem *hsys, HairGuideData *guides) +void BKE_hair_set_fiber_curves(HairSystem *hsys, HairCurveData *curves) { - if (hsys->guides.curves) + if (hsys->curve_data.curves) { - MEM_freeN(hsys->guides.curves); + MEM_freeN(hsys->curve_data.curves); } - hsys->guides.curves = MEM_dupallocN(hsys->guides.curves); - hsys->guides.totcurves = guides->totcurves; + hsys->curve_data.curves = MEM_dupallocN(hsys->curve_data.curves); + hsys->curve_data.totcurves = curves->totcurves; - if (hsys->guides.verts) + if (hsys->curve_data.verts) { - MEM_freeN(hsys->guides.verts); + MEM_freeN(hsys->curve_data.verts); } - hsys->guides.verts = MEM_dupallocN(hsys->guides.verts); - hsys->guides.totverts = guides->totverts; + hsys->curve_data.verts = MEM_dupallocN(hsys->curve_data.verts); + hsys->curve_data.totverts = curves->totverts; #ifndef NDEBUG - const int vertcount = hair_guide_calc_vertstart(hsys); - BLI_assert(vertcount <= hsys->guides.totverts); + const int vertcount = hair_curve_calc_vertstart(hsys); + BLI_assert(vertcount <= hsys->curve_data.totverts); #endif hsys->flag |= HAIR_SYSTEM_UPDATE_FOLLICLE_BINDING; BKE_hair_batch_cache_dirty(hsys, BKE_HAIR_BATCH_DIRTY_ALL); } -void BKE_hair_clear_guides(HairSystem *hsys) +void BKE_hair_clear_fiber_curves(HairSystem *hsys) { - if (hsys->guides.curves) + if (hsys->curve_data.curves) { - MEM_freeN(hsys->guides.curves); - hsys->guides.curves = NULL; + MEM_freeN(hsys->curve_data.curves); + hsys->curve_data.curves = NULL; } - hsys->guides.totcurves = 0; + hsys->curve_data.totcurves = 0; - if (hsys->guides.verts) + if (hsys->curve_data.verts) { - MEM_freeN(hsys->guides.verts); - hsys->guides.verts = NULL; + MEM_freeN(hsys->curve_data.verts); + hsys->curve_data.verts = NULL; } - hsys->guides.totverts = 0; + hsys->curve_data.totverts = 0; hsys->flag &= ~HAIR_SYSTEM_UPDATE_FOLLICLE_BINDING; BKE_hair_batch_cache_dirty(hsys, BKE_HAIR_BATCH_DIRTY_ALL); @@ -330,90 +329,6 @@ void BKE_hair_clear_guides(HairSystem *hsys) /* ================================= */ -BLI_INLINE void hair_fiber_verify_weights(HairFollicle *follicle) -{ - const float *w = follicle->parent_weight; - - BLI_assert(w[0] >= 0.0f && w[1] >= 0.0f && w[2] >= 0.0f && w[3] >= 0.0f); - float sum = w[0] + w[1] + w[2] + w[3]; - float epsilon = 1.0e-2; - BLI_assert(sum > 1.0f - epsilon && sum < 1.0f + epsilon); - UNUSED_VARS(sum, epsilon); - - BLI_assert(w[0] >= w[1] && w[1] >= w[2] && w[2] >= w[3]); -} - -static void hair_fiber_sort_weights(HairFollicle *follicle) -{ - unsigned int *idx = follicle->parent_index; - float *w = follicle->parent_weight; - -#define FIBERSWAP(a, b) \ - SWAP(unsigned int, idx[a], idx[b]); \ - SWAP(float, w[a], w[b]); - - for (int k = 0; k < 3; ++k) { - int maxi = k; - float maxw = w[k]; - for (int i = k+1; i < 4; ++i) { - if (w[i] > maxw) { - maxi = i; - maxw = w[i]; - } - } - if (maxi != k) - FIBERSWAP(k, maxi); - } - -#undef FIBERSWAP -} - -static void hair_fiber_find_closest_strand( - HairFollicle *follicle, - const float loc[3], - const KDTree *tree, - const float (*strandloc)[3]) -{ - /* Use the 3 closest strands for interpolation. - * Note that we have up to 4 possible weights, but we - * only look for a triangle with this method. - */ - KDTreeNearest nearest[3]; - const float *sloc[3] = {NULL}; - int k, found = BLI_kdtree_find_nearest_n(tree, loc, nearest, 3); - for (k = 0; k < found; ++k) { - follicle->parent_index[k] = (unsigned int)nearest[k].index; - sloc[k] = strandloc[nearest[k].index]; - } - for (; k < 4; ++k) { - follicle->parent_index[k] = HAIR_STRAND_INDEX_NONE; - follicle->parent_weight[k] = 0.0f; - } - - /* calculate barycentric interpolation weights */ - if (found == 3) { - float closest[3]; - closest_on_tri_to_point_v3(closest, loc, sloc[0], sloc[1], sloc[2]); - - float w[3]; - interp_weights_tri_v3(w, sloc[0], sloc[1], sloc[2], closest); - copy_v3_v3(follicle->parent_weight, w); - /* float precisions issues can cause slightly negative weights */ - CLAMP3(follicle->parent_weight, 0.0f, 1.0f); - } - else if (found == 2) { - follicle->parent_weight[1] = line_point_factor_v3(loc, sloc[0], sloc[1]); - follicle->parent_weight[0] = 1.0f - follicle->parent_weight[1]; - /* float precisions issues can cause slightly negative weights */ - CLAMP2(follicle->parent_weight, 0.0f, 1.0f); - } - else if (found == 1) { - follicle->parent_weight[0] = 1.0f; - } - - hair_fiber_sort_weights(follicle); -} - bool BKE_hair_bind_follicles(HairSystem *hsys, const Mesh *scalp) { if (!(hsys->flag & HAIR_SYSTEM_UPDATE_FOLLICLE_BINDING)) @@ -428,8 +343,8 @@ bool BKE_hair_bind_follicles(HairSystem *hsys, const Mesh *scalp) return true; } - const int num_strands = hsys->guides.totcurves; - /* Need at least one guide curve for binding */ + const int num_strands = hsys->curve_data.totcurves; + /* Need at least one curve for binding */ if (num_strands == 0) { HairFollicle *follicle = pattern->follicles; @@ -437,29 +352,18 @@ bool BKE_hair_bind_follicles(HairSystem *hsys, const Mesh *scalp) { for (int k = 0; k < 4; ++k) { - follicle->parent_index[k] = HAIR_STRAND_INDEX_NONE; - follicle->parent_weight[k] = 0.0f; + follicle->curve = HAIR_CURVE_INDEX_NONE; } } return false; } - float (*strandloc)[3] = MEM_mallocN(sizeof(float) * 3 * num_strands, "strand locations"); - { - for (int i = 0; i < num_strands; ++i) - { - float nor[3], tang[3]; - if (!BKE_mesh_sample_eval(scalp, &hsys->guides.curves[i].mesh_sample, strandloc[i], nor, tang)) - { - zero_v3(strandloc[i]); - } - } - } - KDTree *tree = BLI_kdtree_new(num_strands); for (int c = 0; c < num_strands; ++c) { - BLI_kdtree_insert(tree, c, strandloc[c]); + const int vertstart = hsys->curve_data.curves[c].vertstart; + const float *rootco = hsys->curve_data.verts[vertstart].co; + BLI_kdtree_insert(tree, c, rootco); } BLI_kdtree_balance(tree); @@ -470,14 +374,12 @@ bool BKE_hair_bind_follicles(HairSystem *hsys, const Mesh *scalp) float loc[3], nor[3], tang[3]; if (BKE_mesh_sample_eval(scalp, &follicle->mesh_sample, loc, nor, tang)) { - hair_fiber_find_closest_strand(follicle, loc, tree, strandloc); - hair_fiber_verify_weights(follicle); + follicle->curve = BLI_kdtree_find_nearest(tree, loc, NULL); } } } BLI_kdtree_free(tree); - MEM_freeN(strandloc); return true; } @@ -497,22 +399,19 @@ BLI_INLINE int hair_get_strand_subdiv_numverts(int numstrands, int numverts, int } /* Subdivide a curve */ -static int hair_guide_subdivide(const HairGuideCurve* curve, const HairGuideVertex* verts, - int subdiv, const float rootpos[3], HairGuideVertex *r_verts) +static int hair_curve_subdivide(const HairFiberCurve* curve, const HairFiberVertex* verts, + int subdiv, HairFiberVertex *r_verts) { { /* 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); - BLI_assert(curve->numverts > 0); - float offset[3]; - sub_v3_v3v3(offset, rootpos, verts[0].co); - HairGuideVertex *dst = r_verts; + HairFiberVertex *dst = r_verts; for (int i = 0; i < curve->numverts; ++i) { - add_v3_v3v3(dst->co, verts[i].co, offset); + copy_v3_v3(dst->co, verts[i].co); dst += step; } } @@ -547,7 +446,7 @@ static int hair_guide_subdivide(const HairGuideCurve* curve, const HairGuideVert } /* Calculate tangent and normal vector changes from one segment to the next */ -static void hair_guide_transport_frame(const float co1[3], const float co2[3], +static void hair_curve_transport_frame(const float co1[3], const float co2[3], float prev_tang[3], float prev_nor[3], float r_tang[3], float r_nor[3]) { @@ -565,30 +464,28 @@ static void hair_guide_transport_frame(const float co1[3], const float co2[3], } /* Calculate tangent and normal vectors for all vertices on a curve */ -static void hair_guide_calc_vectors(const HairGuideVertex* verts, int numverts, float rootmat[3][3], +static void hair_curve_calc_vectors(const HairFiberVertex* verts, int numverts, float (*r_tangents)[3], float (*r_normals)[3]) { BLI_assert(numverts >= 2); - float prev_tang[3], prev_nor[3]; - - copy_v3_v3(prev_tang, rootmat[2]); - copy_v3_v3(prev_nor, rootmat[0]); + float prev_tang[3] = {0.0f, 0.0f, 1.0f}; + float prev_nor[3] = {1.0f, 0.0f, 0.0f}; - hair_guide_transport_frame( + hair_curve_transport_frame( verts[0].co, verts[1].co, prev_tang, prev_nor, r_tangents[0], r_normals[0]); for (int i = 1; i < numverts - 1; ++i) { - hair_guide_transport_frame( + hair_curve_transport_frame( verts[i-1].co, verts[i+1].co, prev_tang, prev_nor, r_tangents[i], r_normals[i]); } - hair_guide_transport_frame( + hair_curve_transport_frame( verts[numverts-2].co, verts[numverts-1].co, prev_tang, prev_nor, r_tangents[numverts-1], r_normals[numverts-1]); @@ -609,25 +506,21 @@ HairExportCache* BKE_hair_export_cache_new(void) static int hair_export_cache_get_required_updates(const HairExportCache *cache) { int data = 0; - if (!cache->guide_curves) + if (!cache->fiber_curves) { - data |= HAIR_EXPORT_GUIDE_CURVES; + data |= HAIR_EXPORT_FIBER_CURVES; } - if (!cache->guide_verts || !cache->guide_normals || !cache->guide_tangents) + if (!cache->fiber_verts || !cache->fiber_normals || !cache->fiber_tangents) { - data |= HAIR_EXPORT_GUIDE_VERTICES; + data |= HAIR_EXPORT_FIBER_VERTICES; } if (!cache->follicles) { data |= HAIR_EXPORT_FOLLICLE_BINDING; } - if (!cache->fiber_root_position) - { - data |= HAIR_EXPORT_FIBER_ROOT_POSITIONS; - } - if (!cache->fiber_numverts) + if (!cache->follicle_root_position) { - data |= HAIR_EXPORT_FIBER_VERTEX_COUNTS; + data |= HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS; } return data; } @@ -638,11 +531,11 @@ static int hair_export_cache_get_dependencies(int data) { /* Ordering here is important to account for recursive dependencies */ - if (data & HAIR_EXPORT_GUIDE_CURVES) - data |= HAIR_EXPORT_GUIDE_VERTICES | HAIR_EXPORT_FOLLICLE_BINDING; + if (data & HAIR_EXPORT_FIBER_CURVES) + data |= HAIR_EXPORT_FIBER_VERTICES | HAIR_EXPORT_FOLLICLE_BINDING; if (data & HAIR_EXPORT_FOLLICLE_BINDING) - data |= HAIR_EXPORT_FIBER_ROOT_POSITIONS | HAIR_EXPORT_FIBER_VERTEX_COUNTS; + data |= HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS; return data; } @@ -664,51 +557,45 @@ int BKE_hair_export_cache_update(HairExportCache *cache, const HairSystem *hsys, /* Only update invalidated parts */ data &= uncached; - if (data & HAIR_EXPORT_GUIDE_CURVES) + if (data & HAIR_EXPORT_FIBER_CURVES) { - /* Cache subdivided guide curves */ - const int totguidecurves = cache->totguidecurves = hsys->guides.totcurves; - cache->guide_curves = MEM_reallocN_id(cache->guide_curves, sizeof(HairGuideCurve) * totguidecurves, "hair export guide curves"); + /* Cache subdivided curves */ + const int totcurves = cache->totcurves = hsys->curve_data.totcurves; + cache->fiber_curves = MEM_reallocN_id(cache->fiber_curves, sizeof(HairFiberCurve) * totcurves, "hair export curves"); - int totguideverts = 0; - for (int i = 0; i < totguidecurves; ++i) { - const HairGuideCurve *curve_orig = &hsys->guides.curves[i]; - HairGuideCurve *curve = &cache->guide_curves[i]; + int totverts = 0; + for (int i = 0; i < totcurves; ++i) { + const HairFiberCurve *curve_orig = &hsys->curve_data.curves[i]; + HairFiberCurve *curve = &cache->fiber_curves[i]; - memcpy(curve, curve_orig, sizeof(HairGuideCurve)); + memcpy(curve, curve_orig, sizeof(HairFiberCurve)); curve->numverts = hair_get_strand_subdiv_length(curve_orig->numverts, subdiv); - curve->vertstart = totguideverts; + curve->vertstart = totverts; - totguideverts += curve->numverts; + totverts += curve->numverts; } - cache->totguideverts = totguideverts; + cache->totverts = totverts; } - if (data & HAIR_EXPORT_GUIDE_VERTICES) + if (data & HAIR_EXPORT_FIBER_VERTICES) { - const int totguidecurves = cache->totguidecurves; - const int totguideverts = cache->totguideverts; - cache->guide_verts = MEM_reallocN_id(cache->guide_verts, sizeof(HairGuideVertex) * totguideverts, "hair export guide verts"); - cache->guide_tangents = MEM_reallocN_id(cache->guide_tangents, sizeof(float[3]) * totguideverts, "hair export guide tangents"); - cache->guide_normals = MEM_reallocN_id(cache->guide_normals, sizeof(float[3]) * totguideverts, "hair export guide normals"); + const int totcurves = cache->totcurves; + const int totverts = cache->totverts; + cache->fiber_verts = MEM_reallocN_id(cache->fiber_verts, sizeof(HairFiberVertex) * totverts, "hair export verts"); + cache->fiber_tangents = MEM_reallocN_id(cache->fiber_tangents, sizeof(float[3]) * totverts, "hair export tangents"); + cache->fiber_normals = MEM_reallocN_id(cache->fiber_normals, sizeof(float[3]) * totverts, "hair export normals"); - for (int i = 0; i < totguidecurves; ++i) { - const HairGuideCurve *curve_orig = &hsys->guides.curves[i]; - const HairGuideVertex *verts_orig = &hsys->guides.verts[curve_orig->vertstart]; - const HairGuideCurve *curve = &cache->guide_curves[i]; - HairGuideVertex *verts = &cache->guide_verts[curve->vertstart]; - float (*tangents)[3] = &cache->guide_tangents[curve->vertstart]; - float (*normals)[3] = &cache->guide_normals[curve->vertstart]; - - /* Root matrix for offsetting to the scalp surface and for initial normal direction */ - float rootpos[3]; - float rootmat[3][3]; - BKE_mesh_sample_eval(scalp, &curve->mesh_sample, rootpos, rootmat[2], rootmat[0]); - cross_v3_v3v3(rootmat[1], rootmat[2], rootmat[0]); + for (int i = 0; i < totcurves; ++i) { + const HairFiberCurve *curve_orig = &hsys->curve_data.curves[i]; + const HairFiberVertex *verts_orig = &hsys->curve_data.verts[curve_orig->vertstart]; + const HairFiberCurve *curve = &cache->fiber_curves[i]; + HairFiberVertex *verts = &cache->fiber_verts[curve->vertstart]; + float (*tangents)[3] = &cache->fiber_tangents[curve->vertstart]; + float (*normals)[3] = &cache->fiber_normals[curve->vertstart]; - hair_guide_subdivide(curve_orig, verts_orig, subdiv, rootpos, verts); + hair_curve_subdivide(curve_orig, verts_orig, subdiv, verts); - hair_guide_calc_vectors(verts, curve->numverts, rootmat, tangents, normals); + hair_curve_calc_vectors(verts, curve->numverts, tangents, normals); } } @@ -717,67 +604,31 @@ int BKE_hair_export_cache_update(HairExportCache *cache, const HairSystem *hsys, if (data & HAIR_EXPORT_FOLLICLE_BINDING) { cache->follicles = hsys->pattern->follicles; - cache->totfibercurves = hsys->pattern->num_follicles; - } - - if (data & HAIR_EXPORT_FIBER_VERTEX_COUNTS) - { - /* Calculate the length of each fiber from the weighted average of its guide strands */ - const int totguidecurves = cache->totguidecurves; - const int totfibercurves = cache->totfibercurves; - - cache->fiber_numverts = MEM_reallocN_id(cache->fiber_numverts, sizeof(int) * totfibercurves, "fiber numverts"); - cache->totfiberverts = 0; - - const HairFollicle *follicle = hsys->pattern->follicles; - for (int i = 0; i < totfibercurves; ++i, ++follicle) { - float fiblen = 0.0f; - - for (int k = 0; k < 4; ++k) { - const int si = follicle->parent_index[k]; - const float sw = follicle->parent_weight[k]; - if (si == HAIR_STRAND_INDEX_NONE || sw == 0.0f) { - break; - } - BLI_assert(si < totguidecurves); - - fiblen += (float)cache->guide_curves[si].numverts * sw; - } - - /* Use rounded number of segments */ - const int numverts = (int)(fiblen + 0.5f); - cache->fiber_numverts[i] = numverts; - cache->totfiberverts += numverts; - } + cache->totfollicles = hsys->pattern->num_follicles; } - if (data & HAIR_EXPORT_FIBER_ROOT_POSITIONS) + if (data & HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS) { - const int totfibercurves = cache->totfibercurves; + const int totfibercurves = cache->totfollicles; - cache->fiber_root_position = MEM_reallocN_id(cache->fiber_root_position, sizeof(float[3]) * totfibercurves, "fiber root position"); + cache->follicle_root_position = MEM_reallocN_id(cache->follicle_root_position, sizeof(float[3]) * totfibercurves, "fiber root position"); const HairFollicle *follicle = hsys->pattern->follicles; for (int i = 0; i < totfibercurves; ++i, ++follicle) { /* Cache fiber root position */ float nor[3], tang[3]; - BKE_mesh_sample_eval(scalp, &follicle->mesh_sample, cache->fiber_root_position[i], nor, tang); + BKE_mesh_sample_eval(scalp, &follicle->mesh_sample, cache->follicle_root_position[i], nor, tang); } } } else { cache->follicles = NULL; - cache->totfibercurves = 0; + cache->totfollicles = 0; - if (cache->fiber_numverts) - { - MEM_freeN(cache->fiber_numverts); - cache->fiber_numverts = NULL; - } - if (cache->fiber_root_position) + if (cache->follicle_root_position) { - MEM_freeN(cache->fiber_root_position); - cache->fiber_root_position = NULL; + MEM_freeN(cache->follicle_root_position); + cache->follicle_root_position = NULL; } } @@ -788,29 +639,25 @@ int BKE_hair_export_cache_update(HairExportCache *cache, const HairSystem *hsys, void BKE_hair_export_cache_free(HairExportCache *cache) { - if (cache->fiber_numverts) + if (cache->fiber_curves) { - MEM_freeN(cache->fiber_numverts); + MEM_freeN(cache->fiber_curves); } - if (cache->guide_curves) + if (cache->fiber_verts) { - MEM_freeN(cache->guide_curves); + MEM_freeN(cache->fiber_verts); } - if (cache->guide_verts) + if (cache->fiber_tangents) { - MEM_freeN(cache->guide_verts); + MEM_freeN(cache->fiber_tangents); } - if (cache->guide_tangents) + if (cache->fiber_normals) { - MEM_freeN(cache->guide_tangents); + MEM_freeN(cache->fiber_normals); } - if (cache->guide_normals) + if (cache->follicle_root_position) { - MEM_freeN(cache->guide_normals); - } - if (cache->fiber_root_position) - { - MEM_freeN(cache->fiber_root_position); + MEM_freeN(cache->follicle_root_position); } MEM_freeN(cache); } @@ -833,50 +680,42 @@ void BKE_hair_export_cache_invalidate(HairExportCache *cache, int invalidate) /* Include dependencies */ int data = hair_export_cache_get_dependencies(invalidate); - if (data & HAIR_EXPORT_GUIDE_CURVES) + if (data & HAIR_EXPORT_FIBER_CURVES) { - if (cache->guide_curves) + if (cache->fiber_curves) { - MEM_freeN(cache->guide_curves); - cache->guide_curves = 0; + MEM_freeN(cache->fiber_curves); + cache->fiber_curves = 0; } } - if (data & HAIR_EXPORT_GUIDE_VERTICES) + if (data & HAIR_EXPORT_FIBER_VERTICES) { - if (cache->guide_verts) + if (cache->fiber_verts) { - MEM_freeN(cache->guide_verts); - cache->guide_verts = NULL; + MEM_freeN(cache->fiber_verts); + cache->fiber_verts = NULL; } - if (cache->guide_tangents) + if (cache->fiber_tangents) { - MEM_freeN(cache->guide_tangents); - cache->guide_tangents = NULL; + MEM_freeN(cache->fiber_tangents); + cache->fiber_tangents = NULL; } - if (cache->guide_normals) + if (cache->fiber_normals) { - MEM_freeN(cache->guide_normals); - cache->guide_tangents = NULL; + MEM_freeN(cache->fiber_normals); + cache->fiber_tangents = NULL; } } if (data & HAIR_EXPORT_FOLLICLE_BINDING) { cache->follicles = NULL; } - if (data & HAIR_EXPORT_FIBER_ROOT_POSITIONS) - { - if (cache->fiber_root_position) - { - MEM_freeN(cache->fiber_root_position); - cache->fiber_root_position = NULL; - } - } - if (data & HAIR_EXPORT_FIBER_VERTEX_COUNTS) + if (data & HAIR_EXPORT_FOLLICLE_ROOT_POSITIONS) { - if (cache->fiber_numverts) + if (cache->follicle_root_position) { - MEM_freeN(cache->fiber_numverts); - cache->fiber_numverts = NULL; + MEM_freeN(cache->follicle_root_position); + cache->follicle_root_position = NULL; } } } 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); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 188e2e5cdf5..2c0f7f7c1ec 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5007,8 +5007,8 @@ static void direct_link_hair(FileData *fd, HairSystem* hsys) hsys->pattern->follicles = newdataadr(fd, hsys->pattern->follicles); } - hsys->guides.curves = newdataadr(fd, hsys->guides.curves); - hsys->guides.verts = newdataadr(fd, hsys->guides.verts); + hsys->curve_data.curves = newdataadr(fd, hsys->curve_data.curves); + hsys->curve_data.verts = newdataadr(fd, hsys->curve_data.verts); hsys->draw_batch_cache = NULL; hsys->draw_texture_cache = NULL; @@ -5343,7 +5343,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) hmd->draw_settings = newdataadr(fd, hmd->draw_settings); - BLI_listbase_clear(&hmd->guide_curves); // runtime + BLI_listbase_clear(&hmd->fiber_curves); // runtime } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d8845798131..dc301db1a1f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1621,8 +1621,8 @@ static void write_hair(WriteData *wd, HairSystem *hsys) writestruct(wd, DATA, HairFollicle, hsys->pattern->num_follicles, hsys->pattern->follicles); } - writestruct(wd, DATA, HairGuideCurve, hsys->guides.totcurves, hsys->guides.curves); - writestruct(wd, DATA, HairGuideVertex, hsys->guides.totverts, hsys->guides.verts); + writestruct(wd, DATA, HairFiberCurve, hsys->curve_data.totcurves, hsys->curve_data.curves); + writestruct(wd, DATA, HairFiberVertex, hsys->curve_data.totverts, hsys->curve_data.verts); } static void write_modifiers(WriteData *wd, ListBase *modbase) diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e48ec095ec1..aca28d02be1 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -66,7 +66,6 @@ set(SRC intern/draw_common.c intern/draw_debug.c intern/draw_hair.c - intern/draw_hair_fibers.c intern/draw_instance_data.c intern/draw_manager.c intern/draw_manager_data.c @@ -229,7 +228,6 @@ data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC) data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC) data_to_c_simple(modes/shaders/common_hair_lib.glsl SRC) -data_to_c_simple(modes/shaders/common_hair_guides_lib.glsl SRC) data_to_c_simple(modes/shaders/common_hair_refine_vert.glsl SRC) data_to_c_simple(modes/shaders/common_view_lib.glsl SRC) data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index be6ab9c9b6e..8d569773384 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -43,7 +43,6 @@ #include "DNA_hair_types.h" #include "GPU_material.h" -#include "GPU_texture.h" #include "eevee_engine.h" #include "eevee_lut.h" @@ -57,8 +56,6 @@ static struct { struct GPUShader *default_prepass_sh; struct GPUShader *default_prepass_clip_sh; - struct GPUShader *default_prepass_hair_fiber_sh; - struct GPUShader *default_prepass_hair_fiber_clip_sh; struct GPUShader *default_hair_prepass_sh; struct GPUShader *default_hair_prepass_clip_sh; struct GPUShader *default_lit[VAR_MAT_MAX]; @@ -91,7 +88,6 @@ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_hair_guides_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; @@ -291,9 +287,6 @@ static char *eevee_get_defines(int options) if ((options & VAR_MAT_HAIR) != 0) { BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n"); } - if ((options & VAR_MAT_HAIR_FIBERS) != 0) { - BLI_dynstr_append(ds, DRW_hair_shader_defines()); - } if ((options & VAR_MAT_PROBE) != 0) { BLI_dynstr_appendf(ds, "#define PROBE_CAPTURE\n"); } @@ -571,7 +564,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_volumetric_lib_glsl); - + e_data.volume_shader_lib = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, @@ -588,7 +581,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E e_data.vert_shader_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, - datatoc_common_hair_guides_lib_glsl, datatoc_lit_surface_vert_glsl); e_data.default_background = DRW_shader_create( @@ -607,25 +599,6 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); - char *hair_fiber_vert_str = BLI_string_joinN( - datatoc_common_view_lib_glsl, - datatoc_common_hair_lib_glsl, - datatoc_common_hair_guides_lib_glsl, - datatoc_prepass_vert_glsl); - - e_data.default_prepass_hair_fiber_sh = DRW_shader_create( - hair_fiber_vert_str, NULL, datatoc_prepass_frag_glsl, DRW_hair_shader_defines()); - - { - char defines[256]; - BLI_snprintf(defines, sizeof(defines), "#define CLIP_PLANES\n%s", - DRW_hair_shader_defines()); - e_data.default_prepass_hair_fiber_clip_sh = DRW_shader_create( - hair_fiber_vert_str, NULL, datatoc_prepass_frag_glsl, defines); - } - - MEM_freeN(hair_fiber_vert_str); - char *vert_str = BLI_string_joinN( datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, @@ -829,14 +802,13 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( } struct GPUMaterial *EEVEE_material_hair_get( - struct Scene *scene, Material *ma, int shadow_method, bool use_fibers) + struct Scene *scene, Material *ma, int shadow_method) { const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_HAIR | VAR_MAT_MESH; + int options = VAR_MAT_MESH | VAR_MAT_HAIR; + options |= eevee_material_shadow_option(shadow_method); - if (use_fibers) { - options |= VAR_MAT_HAIR_FIBERS; - } + GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options); if (mat) { return mat; @@ -854,27 +826,19 @@ struct GPUMaterial *EEVEE_material_hair_get( return mat; } -typedef enum ShaderHairType -{ - DRW_SHADER_HAIR_NONE, - DRW_SHADER_HAIR_PARTICLES, - DRW_SHADER_HAIR_FIBERS, -} ShaderHairType; - /** * Create a default shading group inside the given pass. **/ static struct DRWShadingGroup *EEVEE_default_shading_group_create( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass, - ShaderHairType hair_type, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) + bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) { EEVEE_EffectsInfo *effects = vedata->stl->effects; static int ssr_id; ssr_id = (use_ssr) ? 1 : -1; int options = VAR_MAT_MESH; - if (hair_type == DRW_SHADER_HAIR_PARTICLES) options |= VAR_MAT_HAIR; - if (hair_type == DRW_SHADER_HAIR_FIBERS) options |= VAR_MAT_HAIR | VAR_MAT_HAIR_FIBERS; + if (is_hair) options |= VAR_MAT_HAIR; if (is_flat_normal) options |= VAR_MAT_FLAT; if (use_blend) options |= VAR_MAT_BLEND; if (((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) && use_blend) options |= VAR_MAT_VOLUME; @@ -896,17 +860,18 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( **/ static struct DRWShadingGroup *EEVEE_default_shading_group_get( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - Object *ob, ParticleSystem *psys, ModifierData *md, - ShaderHairType hair_type, bool is_flat_normal, bool use_ssr, int shadow_method) + Object *ob, + ParticleSystem *psys, ModifierData *md, + HairSystem *hsys, const HairDrawSettings *hdraw, struct Mesh *scalp, + bool is_hair, bool is_flat_normal, bool use_ssr, int shadow_method) { static int ssr_id; ssr_id = (use_ssr) ? 1 : -1; int options = VAR_MAT_MESH; - BLI_assert(hair_type != DRW_SHADER_HAIR_PARTICLES || (ob && psys && md)); + BLI_assert(!is_hair || (ob && psys && md) || (ob && hsys && hdraw && scalp)); - if (hair_type == DRW_SHADER_HAIR_PARTICLES) options |= VAR_MAT_HAIR; - if (hair_type == DRW_SHADER_HAIR_FIBERS) options |= VAR_MAT_HAIR | VAR_MAT_HAIR_FIBERS; + if (is_hair) options |= VAR_MAT_HAIR; if (is_flat_normal) options |= VAR_MAT_FLAT; options |= eevee_material_shadow_option(shadow_method); @@ -916,23 +881,30 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( } if (vedata->psl->default_pass[options] == NULL) { - //DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); /* XXX / WATCH: This creates non persistent binds for the ubos and textures. * But it's currently OK because the following shgroups does not add any bind. * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */ - if (hair_type != DRW_SHADER_HAIR_PARTICLES) { + if (!is_hair) { DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); } } - if (hair_type == DRW_SHADER_HAIR_PARTICLES) { - DRWShadingGroup *shgrp = DRW_shgroup_hair_create(ob, psys, md, - vedata->psl->default_pass[options], - e_data.default_lit[options]); + if (is_hair) { + DRWShadingGroup *shgrp = NULL; + if (psys && md) { + shgrp = DRW_shgroup_particle_hair_create(ob, psys, md, + vedata->psl->default_pass[options], + e_data.default_lit[options]); + } + else if (hsys && hdraw && scalp) { + shgrp = DRW_shgroup_hair_create(ob, hsys, scalp, hdraw, + vedata->psl->default_pass[options], + e_data.default_lit[options]); + } add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); return shgrp; } @@ -1286,8 +1258,8 @@ static void material_opaque( if (*shgrp == NULL) { bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); *shgrp = EEVEE_default_shading_group_get(sldata, vedata, - NULL, NULL, NULL, - DRW_SHADER_HAIR_NONE, use_flat_nor, use_ssr, linfo->shadow_method); + NULL, NULL, NULL, NULL, NULL, NULL, + false, use_flat_nor, use_ssr, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1373,7 +1345,7 @@ static void material_transparent( if (*shgrp == NULL) { *shgrp = EEVEE_default_shading_group_create( sldata, vedata, psl->transparent_pass, - DRW_SHADER_HAIR_NONE, use_flat_nor, true, false, linfo->shadow_method); + false, use_flat_nor, true, false, linfo->shadow_method); DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1); DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1); @@ -1461,12 +1433,12 @@ static void material_particle_hair( float *spec_p = &ma->spec; float *rough_p = &ma->roughness; - shgrp = DRW_shgroup_hair_create( + shgrp = DRW_shgroup_particle_hair_create( ob, psys, md, psl->depth_pass, e_data.default_hair_prepass_sh); - shgrp = DRW_shgroup_hair_create( + shgrp = DRW_shgroup_particle_hair_create( ob, psys, md, psl->depth_pass_clip, e_data.default_hair_prepass_clip_sh); @@ -1479,12 +1451,12 @@ static void material_particle_hair( static float half = 0.5f; static float error_col[3] = {1.0f, 0.0f, 1.0f}; static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method, false); + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method); switch (GPU_material_status(gpumat)) { case GPU_MAT_SUCCESS: { - shgrp = DRW_shgroup_material_hair_create( + shgrp = DRW_shgroup_material_particle_hair_create( ob, psys, md, psl->material_pass, gpumat); @@ -1509,8 +1481,8 @@ static void material_particle_hair( /* Fallback to default shader */ if (shgrp == NULL) { shgrp = EEVEE_default_shading_group_get(sldata, vedata, - ob, psys, md, - DRW_SHADER_HAIR_PARTICLES, false, use_ssr, + ob, psys, md, NULL, NULL, NULL, + true, false, use_ssr, sldata->lamps->shadow_method); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); @@ -1519,7 +1491,7 @@ static void material_particle_hair( } /* Shadows */ - DRW_shgroup_hair_create( + DRW_shgroup_particle_hair_create( ob, psys, md, psl->shadow_pass, e_data.default_hair_prepass_sh); @@ -1542,15 +1514,26 @@ static void material_hair( float mat[4][4]; copy_m4_m4(mat, ob->obmat); + if (draw_set->fiber_mode != HAIR_DRAW_FIBER_CURVES) + { + return; + } + if (ma == NULL) { ma = &defmaterial; } { - /*DRWShadingGroup *shgrp =*/ DRW_shgroup_hair_fibers_create(scene, ob, hsys, scalp, draw_set, psl->depth_pass, e_data.default_prepass_hair_fiber_sh); + /*DRWShadingGroup *shgrp =*/ DRW_shgroup_hair_create( + ob, hsys, scalp, draw_set, + psl->depth_pass, + e_data.default_hair_prepass_sh); } { - DRWShadingGroup *shgrp = DRW_shgroup_hair_fibers_create(scene, ob, hsys, scalp, draw_set, psl->depth_pass_clip, e_data.default_prepass_hair_fiber_clip_sh); + DRWShadingGroup *shgrp = DRW_shgroup_hair_create( + ob, hsys, scalp, draw_set, + psl->depth_pass_clip, + e_data.default_hair_prepass_clip_sh); DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo); } @@ -1567,15 +1550,15 @@ static void material_hair( static float half = 0.5f; static float error_col[3] = {1.0f, 0.0f, 1.0f}; static float compile_col[3] = {0.5f, 0.5f, 0.5f}; - struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method, true); + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method); switch (GPU_material_status(gpumat)) { case GPU_MAT_SUCCESS: { - shgrp = DRW_shgroup_material_hair_fibers_create( - scene, ob, hsys, scalp, - draw_set, psl->material_pass, - gpumat); + shgrp = DRW_shgroup_material_hair_create( + ob, hsys, scalp, draw_set, + psl->material_pass, + gpumat); add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); break; } @@ -1597,8 +1580,8 @@ static void material_hair( /* Fallback to default shader */ if (shgrp == NULL) { shgrp = EEVEE_default_shading_group_get(sldata, vedata, - NULL, NULL, NULL, DRW_SHADER_HAIR_FIBERS, - false, use_ssr, + ob, NULL, NULL, hsys, draw_set, scalp, + true, false, use_ssr, sldata->lamps->shadow_method); DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); @@ -1608,10 +1591,10 @@ static void material_hair( } /* Shadows */ - DRW_shgroup_hair_fibers_create( - scene, ob, hsys, scalp, - draw_set, psl->shadow_pass, - e_data.default_prepass_hair_fiber_sh); + DRW_shgroup_hair_create( + ob, hsys, scalp, draw_set, + psl->shadow_pass, + e_data.default_hair_prepass_sh); } void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, bool *cast_shadow) @@ -1886,8 +1869,6 @@ void EEVEE_materials_free(void) DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh); DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_hair_fiber_sh); - DRW_SHADER_FREE_SAFE(e_data.default_prepass_hair_fiber_clip_sh); DRW_SHADER_FREE_SAFE(e_data.default_background); DRW_SHADER_FREE_SAFE(e_data.default_studiolight_background); DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index d0b7044a018..fa9d2453934 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -114,12 +114,11 @@ enum { VAR_MAT_VSM = (1 << 5), VAR_MAT_ESM = (1 << 6), VAR_MAT_VOLUME = (1 << 7), - VAR_MAT_LOOKDEV = (1 << 8), - VAR_MAT_HAIR_FIBERS = (1 << 9), + VAR_MAT_LOOKDEV = (1 << 8), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 10), + VAR_MAT_MAX = (1 << 9), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ VAR_MAT_CLIP = (1 << 10), @@ -828,9 +827,7 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get( struct Scene *scene, Material *ma); struct GPUMaterial *EEVEE_material_mesh_depth_get( struct Scene *scene, Material *ma, bool use_hashed_alpha, bool is_shadow); -struct GPUMaterial *EEVEE_material_hair_get( - struct Scene *scene, Material *ma, int shadow_method, bool use_fibers); - +struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method); void EEVEE_materials_free(void); void EEVEE_draw_default_passes(EEVEE_PassList *psl); void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]); diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl index fbcdfd66572..58bcea7d605 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -2,20 +2,15 @@ uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelMatrix; uniform mat4 ModelViewMatrix; -uniform mat4 ModelViewMatrixInverse; uniform mat3 WorldNormalMatrix; #ifndef ATTRIB uniform mat3 NormalMatrix; +uniform mat4 ModelMatrixInverse; #endif #ifndef HAIR_SHADER in vec3 pos; in vec3 nor; -#else -#ifdef HAIR_SHADER_FIBERS -in int fiber_index; -in float curve_param; -#endif #endif out vec3 worldPosition; @@ -46,28 +41,11 @@ flat out int hairStrandID; void main() { #ifdef HAIR_SHADER - bool is_persp = (ProjectionMatrix[3][3] == 0.0); - -# ifdef HAIR_SHADER_FIBERS - vec3 pos, tang, binor; - hair_fiber_get_vertex( - fiber_index, curve_param, - is_persp, ModelViewMatrixInverse[3].xyz, ModelViewMatrixInverse[2].xyz, - pos, tang, binor, - hairTime, hairThickness, hairThickTime); - vec3 nor = cross(binor, tang); - - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz; - worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz; - hairTangent = (ModelMatrix * vec4(tang, 0.0)).xyz; - worldNormal = (ModelMatrix * vec4(nor, 0.0)).xyz; - viewNormal = normalize(mat3(ViewMatrix) * worldNormal); -# else hairStrandID = hair_get_strand_id(); vec3 pos, binor; hair_get_pos_tan_binor_time( - is_persp, ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, + (ProjectionMatrix[3][3] == 0.0), + ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, pos, hairTangent, binor, hairTime, hairThickness, hairThickTime); gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); @@ -76,15 +54,13 @@ void main() hairTangent = normalize(hairTangent); worldNormal = cross(binor, hairTangent); viewNormal = normalize(mat3(ViewMatrix) * worldNormal); -# endif - -#else /* HAIR_SHADER */ +#else gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz; worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz; worldNormal = normalize(WorldNormalMatrix * nor); viewNormal = normalize(NormalMatrix * nor); -#endif /* HAIR_SHADER */ +#endif /* Used for planar reflections */ gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), ClipPlanes[0]); diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl index b1dfa851fa1..f2e9e7001e8 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl @@ -1,53 +1,28 @@ uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelMatrix; -uniform mat4 ModelViewMatrix; -uniform mat4 ModelViewMatrixInverse; /* keep in sync with DRWManager.view_data */ layout(std140) uniform clip_block { vec4 ClipPlanes[1]; }; -#ifdef HAIR_SHADER - -#ifdef HAIR_SHADER_FIBERS -in int fiber_index; -in float curve_param; -#endif - -#else +#ifndef HAIR_SHADER in vec3 pos; #endif void main() { #ifdef HAIR_SHADER - bool is_persp = (ProjectionMatrix[3][3] == 0.0); - -#ifdef HAIR_SHADER_FIBERS - float time, thick_time, thickness; - vec3 pos, tang, binor; - hair_fiber_get_vertex( - fiber_index, curve_param, - is_persp, ModelViewMatrixInverse[3].xyz, ModelViewMatrixInverse[2].xyz, - pos, tang, binor, - time, thickness, thick_time); - - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - vec4 worldPosition = ModelMatrix * vec4(pos, 1.0); -#else float time, thick_time, thickness; vec3 pos, tan, binor; hair_get_pos_tan_binor_time( - is_persp, + (ProjectionMatrix[3][3] == 0.0), ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, pos, tan, binor, time, thickness, thick_time); gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); vec4 worldPosition = vec4(pos, 1.0); -#endif - #else gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0)); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 03d9b02a654..66b529fcf5e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -2,7 +2,6 @@ uniform mat4 ModelViewProjectionMatrix; uniform mat4 ProjectionMatrix; uniform mat4 ViewProjectionMatrix; uniform mat4 ViewMatrixInverse; -uniform mat4 ModelViewMatrixInverse; uniform mat3 NormalMatrix; #ifndef HAIR_SHADER @@ -14,10 +13,6 @@ in vec2 uv; uniform samplerBuffer u; /* active texture layer */ # endif flat out float hair_rand; -# ifdef HAIR_SHADER_FIBERS -in int fiber_index; -in float curve_param; -# endif #endif /* HAIR_SHADER */ #ifdef NORMAL_VIEWPORT_PASS_ENABLED @@ -39,42 +34,27 @@ float integer_noise(int n) void main() { #ifdef HAIR_SHADER - bool is_persp = (ProjectionMatrix[3][3] == 0.0); - -# ifdef HAIR_SHADER_FIBERS - vec2 uv = vec2(0.0); /* TODO */ - float time, thick_time, thickness; - vec3 pos, tang, binor; - hair_fiber_get_vertex( - fiber_index, curve_param, - is_persp, ModelViewMatrixInverse[3].xyz, ModelViewMatrixInverse[2].xyz, - pos, tang, binor, - time, thickness, thick_time); - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - hair_rand = integer_noise(fiber_index); -# else -# ifdef V3D_SHADING_TEXTURE_COLOR +# ifdef V3D_SHADING_TEXTURE_COLOR vec2 uv = hair_get_customdata_vec2(u); -# endif +# endif float time, thick_time, thickness; - vec3 pos, tang, binor; + vec3 pos, tan, binor; hair_get_pos_tan_binor_time( - is_persp, ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, - pos, tang, binor, time, thickness, thick_time); - gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); - hair_rand = integer_noise(hair_get_strand_id()); -# endif + (ProjectionMatrix[3][3] == 0.0), + ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, + pos, tan, binor, time, thickness, thick_time); /* To "simulate" anisotropic shading, randomize hair normal per strand. */ - tang = normalize(tang); - vec3 nor = normalize(cross(binor, tang)); - nor = normalize(mix(nor, -tang, hair_rand * 0.10)); + hair_rand = integer_noise(hair_get_strand_id()); + tan = normalize(tan); + vec3 nor = normalize(cross(binor, tan)); + nor = normalize(mix(nor, -tan, hair_rand * 0.10)); float cos_theta = (hair_rand*2.0 - 1.0) * 0.20; float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta)); nor = nor * sin_theta + binor * cos_theta; -#else /* HAIR_SHADER */ + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); +#else gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); -#endif /* HAIR_SHADER */ - +#endif #ifdef V3D_SHADING_TEXTURE_COLOR uv_interp = uv; #endif diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 412a29722ab..f3c96923dae 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -84,7 +84,6 @@ static struct { /* Shaders */ extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_hair_guides_lib_glsl[]; extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; @@ -149,7 +148,6 @@ static char *workbench_build_prepass_vert(void) DynStr *ds = BLI_dynstr_new(); BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); - BLI_dynstr_append(ds, datatoc_common_hair_guides_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); str = BLI_dynstr_get_cstring(ds); @@ -172,17 +170,17 @@ static char *workbench_build_cavity_frag(void) return str; } -static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, DRWShaderHairType hair_type) +static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, bool is_hair) { if (e_data.prepass_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, use_textures, hair_type); + char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); char *composite_frag = workbench_build_composite_frag(wpd); char *prepass_vert = workbench_build_prepass_vert(); char *prepass_frag = workbench_build_prepass_frag(); e_data.prepass_sh_cache[index] = DRW_shader_create( prepass_vert, NULL, prepass_frag, defines); - if (!use_textures && hair_type == DRW_SHADER_HAIR_NONE) { + if (!use_textures && !is_hair) { e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); } MEM_freeN(prepass_vert); @@ -194,26 +192,20 @@ static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, bool static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) { - int index_solid = workbench_material_get_shader_index(wpd, false, DRW_SHADER_HAIR_NONE); - int index_solid_hair = workbench_material_get_shader_index(wpd, false, DRW_SHADER_HAIR_PARTICLES); - int index_solid_hair_fibers = workbench_material_get_shader_index(wpd, false, DRW_SHADER_HAIR_FIBERS); - int index_texture = workbench_material_get_shader_index(wpd, true, DRW_SHADER_HAIR_NONE); - int index_texture_hair = workbench_material_get_shader_index(wpd, true, DRW_SHADER_HAIR_PARTICLES); - int index_texture_hair_fibers = workbench_material_get_shader_index(wpd, true, DRW_SHADER_HAIR_FIBERS); - - ensure_deferred_shaders(wpd, index_solid, false, DRW_SHADER_HAIR_NONE); - ensure_deferred_shaders(wpd, index_solid_hair, false, DRW_SHADER_HAIR_PARTICLES); - ensure_deferred_shaders(wpd, index_solid_hair_fibers, false, DRW_SHADER_HAIR_FIBERS); - ensure_deferred_shaders(wpd, index_texture, true, DRW_SHADER_HAIR_NONE); - ensure_deferred_shaders(wpd, index_texture_hair, true, DRW_SHADER_HAIR_PARTICLES); - ensure_deferred_shaders(wpd, index_texture_hair_fibers, true, DRW_SHADER_HAIR_FIBERS); + int index_solid = workbench_material_get_shader_index(wpd, false, false); + int index_solid_hair = workbench_material_get_shader_index(wpd, false, true); + int index_texture = workbench_material_get_shader_index(wpd, true, false); + int index_texture_hair = workbench_material_get_shader_index(wpd, true, true); + + ensure_deferred_shaders(wpd, index_solid, false, false); + ensure_deferred_shaders(wpd, index_solid_hair, false, true); + ensure_deferred_shaders(wpd, index_texture, true, false); + ensure_deferred_shaders(wpd, index_texture_hair, true, true); wpd->prepass_solid_sh = e_data.prepass_sh_cache[index_solid]; wpd->prepass_solid_hair_sh = e_data.prepass_sh_cache[index_solid_hair]; - wpd->prepass_solid_hair_fibers_sh = e_data.prepass_sh_cache[index_solid_hair_fibers]; wpd->prepass_texture_sh = e_data.prepass_sh_cache[index_texture]; wpd->prepass_texture_hair_sh = e_data.prepass_sh_cache[index_texture_hair]; - wpd->prepass_texture_hair_fibers_sh = e_data.prepass_sh_cache[index_texture_hair_fibers]; wpd->composite_sh = e_data.composite_sh_cache[index_solid]; } @@ -628,7 +620,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR) ? wpd->prepass_solid_hair_sh : wpd->prepass_texture_hair_sh; - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( + DRWShadingGroup *shgrp = DRW_shgroup_particle_hair_create( ob, psys, md, psl->prepass_hair_pass, shader); diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index fb2d7885b28..805cf0066d8 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -53,7 +53,6 @@ static struct { struct GPUShader *object_outline_sh; struct GPUShader *object_outline_texture_sh; struct GPUShader *object_outline_hair_sh; - struct GPUShader *object_outline_hair_fibers_sh; struct GPUShader *checker_depth_sh; struct GPUTexture *object_id_tx; /* ref only, not alloced */ @@ -67,7 +66,6 @@ static struct { /* Shaders */ extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_hair_guides_lib_glsl[]; extern char datatoc_workbench_forward_composite_frag_glsl[]; extern char datatoc_workbench_forward_depth_frag_glsl[]; @@ -88,7 +86,6 @@ static char *workbench_build_forward_vert(void) DynStr *ds = BLI_dynstr_new(); BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); - BLI_dynstr_append(ds, datatoc_common_hair_guides_lib_glsl); BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); str = BLI_dynstr_get_cstring(ds); @@ -195,10 +192,10 @@ static WORKBENCH_MaterialData *get_or_create_material_data( return material; } -static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, DRWShaderHairType hair_type) +static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool use_textures, bool is_hair) { - if (e_data.composite_sh_cache[index] == NULL && !use_textures && hair_type == DRW_SHADER_HAIR_NONE) { - char *defines = workbench_material_build_defines(wpd, use_textures, hair_type); + if (e_data.composite_sh_cache[index] == NULL && !use_textures && !is_hair) { + char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); char *composite_frag = workbench_build_forward_composite_frag(); e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); MEM_freeN(composite_frag); @@ -206,7 +203,7 @@ static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool u } if (e_data.transparent_accum_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, use_textures, hair_type); + char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); char *transparent_accum_vert = workbench_build_forward_vert(); char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); e_data.transparent_accum_sh_cache[index] = DRW_shader_create( @@ -220,27 +217,21 @@ static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool u static void select_forward_shaders(WORKBENCH_PrivateData *wpd) { - int index_solid = workbench_material_get_shader_index(wpd, false, DRW_SHADER_HAIR_NONE); - int index_solid_hair = workbench_material_get_shader_index(wpd, false, DRW_SHADER_HAIR_PARTICLES); - int index_solid_hair_fibers = workbench_material_get_shader_index(wpd, false, DRW_SHADER_HAIR_FIBERS); - int index_texture = workbench_material_get_shader_index(wpd, true, DRW_SHADER_HAIR_NONE); - int index_texture_hair = workbench_material_get_shader_index(wpd, true, DRW_SHADER_HAIR_PARTICLES); - int index_texture_hair_fibers = workbench_material_get_shader_index(wpd, true, DRW_SHADER_HAIR_FIBERS); - - ensure_forward_shaders(wpd, index_solid, false, DRW_SHADER_HAIR_NONE); - ensure_forward_shaders(wpd, index_solid_hair, false, DRW_SHADER_HAIR_PARTICLES); - ensure_forward_shaders(wpd, index_solid_hair_fibers, false, DRW_SHADER_HAIR_FIBERS); - ensure_forward_shaders(wpd, index_texture, true, DRW_SHADER_HAIR_NONE); - ensure_forward_shaders(wpd, index_texture_hair, true, DRW_SHADER_HAIR_PARTICLES); - ensure_forward_shaders(wpd, index_texture_hair_fibers, true, DRW_SHADER_HAIR_FIBERS); + int index_solid = workbench_material_get_shader_index(wpd, false, false); + int index_solid_hair = workbench_material_get_shader_index(wpd, false, true); + int index_texture = workbench_material_get_shader_index(wpd, true, false); + int index_texture_hair = workbench_material_get_shader_index(wpd, true, true); + + ensure_forward_shaders(wpd, index_solid, false, false); + ensure_forward_shaders(wpd, index_solid_hair, false, true); + ensure_forward_shaders(wpd, index_texture, true, false); + ensure_forward_shaders(wpd, index_texture_hair, true, true); wpd->composite_sh = e_data.composite_sh_cache[index_solid]; wpd->transparent_accum_sh = e_data.transparent_accum_sh_cache[index_solid]; wpd->transparent_accum_hair_sh = e_data.transparent_accum_sh_cache[index_solid_hair]; - wpd->transparent_accum_hair_fibers_sh = e_data.transparent_accum_sh_cache[index_solid_hair_fibers]; wpd->transparent_accum_texture_sh = e_data.transparent_accum_sh_cache[index_texture]; wpd->transparent_accum_texture_hair_sh = e_data.transparent_accum_sh_cache[index_texture_hair]; - wpd->transparent_accum_texture_hair_fibers_sh = e_data.transparent_accum_sh_cache[index_texture_hair_fibers]; } /* public functions */ @@ -270,10 +261,10 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) memset(e_data.composite_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); memset(e_data.transparent_accum_sh_cache, 0x00, sizeof(struct GPUShader *) * MAX_SHADERS); - char *defines = workbench_material_build_defines(wpd, false, DRW_SHADER_HAIR_NONE); - char *defines_texture = workbench_material_build_defines(wpd, true, DRAW_SHADER_HAIR_NONE); - char *defines_hair = workbench_material_build_defines(wpd, false, DRW_SHADER_HAIR_PARTICLES); - char *defines_hair_fibers = workbench_material_build_defines(wpd, false, DRW_SHADER_HAIR_FIBERS); + char *defines = workbench_material_build_defines(wpd, false, false); + char *defines_texture = workbench_material_build_defines(wpd, true, false); + char *defines_hair = workbench_material_build_defines(wpd, false, true); + char *defines_hair_fibers = workbench_material_build_defines(wpd, false, true); char *forward_vert = workbench_build_forward_vert(); e_data.object_outline_sh = DRW_shader_create( forward_vert, NULL, @@ -284,9 +275,6 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) e_data.object_outline_hair_sh = DRW_shader_create( forward_vert, NULL, datatoc_workbench_forward_depth_frag_glsl, defines_hair); - e_data.object_outline_hair_fibers_sh = DRW_shader_create( - forward_vert, NULL, - forward_depth_frag, defines_hair_fibers); e_data.checker_depth_sh = DRW_shader_create_fullscreen( @@ -382,7 +370,6 @@ void workbench_forward_engine_free() DRW_SHADER_FREE_SAFE(e_data.object_outline_sh); DRW_SHADER_FREE_SAFE(e_data.object_outline_texture_sh); DRW_SHADER_FREE_SAFE(e_data.object_outline_hair_sh); - DRW_SHADER_FREE_SAFE(e_data.object_outline_hair_fibers_sh); DRW_SHADER_FREE_SAFE(e_data.checker_depth_sh); workbench_fxaa_engine_free(); @@ -426,7 +413,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR) ? wpd->transparent_accum_hair_sh : wpd->transparent_accum_texture_hair_sh; - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( + DRWShadingGroup *shgrp = DRW_shgroup_particle_hair_create( ob, psys, md, psl->transparent_accum_pass, shader); @@ -445,7 +432,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O if (SPECULAR_HIGHLIGHT_ENABLED(wpd) || MATCAP_ENABLED(wpd)) { DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); } - shgrp = DRW_shgroup_hair_create(ob, psys, md, + shgrp = DRW_shgroup_particle_hair_create(ob, psys, md, vedata->psl->object_outline_pass, e_data.object_outline_hair_sh); DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1); diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 0d4b722b98f..6755bf82ecd 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -42,7 +42,7 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Mate } } -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, DRWShaderHairType hair_type) +char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) { char *str = NULL; @@ -87,16 +87,8 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_text if (NORMAL_ENCODING_ENABLED()) { BLI_dynstr_appendf(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); } - - switch (hair_type) { - case DRW_SHADER_HAIR_NONE: - break; - case DRW_SHADER_HAIR_PARTICLES: - BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n"); - break; - case DRW_SHADER_HAIR_FIBERS: - BLI_dynstr_append(ds, DRW_hair_shader_defines()); - break; + if (is_hair) { + BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n"); } #if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 0 @@ -145,7 +137,7 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template) return result; } -int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, DRWShaderHairType hair_type) +int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair) { /* NOTE: change MAX_SHADERS accordingly when modifying this function. */ int index = 0; @@ -161,8 +153,8 @@ int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_tex /* 2 bits STUDIOLIGHT_ORIENTATION */ SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 1 << 7); SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL, 1 << 8); - /* 2 bits for hair */ - SET_FLAG_FROM_TEST(index, hair_type, hair_type << 9); + /* 1 bit for hair */ + SET_FLAG_FROM_TEST(index, is_hair, 1 << 9); return index; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 23c550d6999..3bec6bb6d53 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -39,7 +39,7 @@ #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" #define M_GOLDEN_RATION_CONJUGATE 0.618033988749895 -#define MAX_SHADERS (1 << 11) +#define MAX_SHADERS (1 << 10) #define TEXTURE_DRAWING_ENABLED(wpd) (wpd->color_type & V3D_SHADING_TEXTURE_COLOR) #define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) @@ -143,17 +143,13 @@ typedef struct WORKBENCH_PrivateData { struct GHash *material_hash; struct GPUShader *prepass_solid_sh; struct GPUShader *prepass_solid_hair_sh; - struct GPUShader *prepass_solid_hair_fibers_sh; struct GPUShader *prepass_texture_sh; struct GPUShader *prepass_texture_hair_sh; - struct GPUShader *prepass_texture_hair_fibers_sh; struct GPUShader *composite_sh; struct GPUShader *transparent_accum_sh; struct GPUShader *transparent_accum_hair_sh; - struct GPUShader *transparent_accum_hair_fibers_sh; struct GPUShader *transparent_accum_texture_sh; struct GPUShader *transparent_accum_texture_hair_sh; - struct GPUShader *transparent_accum_texture_hair_fibers_sh; View3DShading shading; StudioLight *studio_light; UserDef *user_preferences; @@ -267,18 +263,11 @@ void workbench_taa_view_updated(WORKBENCH_Data *vedata); int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata); /* workbench_materials.c */ -typedef enum DRWShaderHairType -{ - DRW_SHADER_HAIR_NONE = 0, - DRW_SHADER_HAIR_PARTICLES = 1, - DRW_SHADER_HAIR_FIBERS = 2, -} DRWShaderHairType; - int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima); -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, DRWShaderHairType hair_type); +char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair); void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Material *mat, WORKBENCH_MaterialData *data); uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template); -int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, DRWShaderHairType hair_type); +int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, bool use_textures, bool is_hair); void workbench_material_set_normal_world_matrix( DRWShadingGroup *grp, WORKBENCH_PrivateData *wpd, float persistent_matrix[3][3]); void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 45814946e8a..e7854e6ade3 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -3118,10 +3118,9 @@ Gwn_Batch *DRW_cache_particles_get_prim(int type) /** \name Hair */ -Gwn_Batch *DRW_cache_hair_get_fibers(struct HairSystem *hsys, const struct HairExportCache *hair_export, - const struct DRWHairFiberTextureBuffer **r_buffer) +Gwn_Batch *DRW_cache_hair_get_fibers(struct HairSystem *hsys, const struct HairExportCache *hair_export) { - return DRW_hair_batch_cache_get_fibers(hsys, hair_export, r_buffer); + return DRW_hair_batch_cache_get_fibers(hsys, hair_export); } Gwn_Batch *DRW_cache_hair_get_follicle_points(struct HairSystem *hsys, const struct HairExportCache *hair_export) @@ -3129,11 +3128,6 @@ Gwn_Batch *DRW_cache_hair_get_follicle_points(struct HairSystem *hsys, const str return DRW_hair_batch_cache_get_follicle_points(hsys, hair_export); } -Gwn_Batch *DRW_cache_hair_get_guide_curve_edges(struct HairSystem *hsys, const struct HairExportCache *hair_export) -{ - return DRW_hair_batch_cache_get_guide_curve_edges(hsys, hair_export); -} - /* 3D cursor */ Gwn_Batch *DRW_cache_cursor_get(bool crosshair_lines) { diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index ea08b8e0fe0..aef32291215 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -33,7 +33,6 @@ struct Object; struct PTCacheEdit; struct HairSystem; struct HairExportCache; -struct DRWHairFiberTextureBuffer; void DRW_shape_cache_free(void); void DRW_shape_cache_reset(void); @@ -190,10 +189,8 @@ struct Gwn_Batch *DRW_cache_particles_get_edit_tip_points( struct Gwn_Batch *DRW_cache_particles_get_prim(int type); /* Hair */ -struct Gwn_Batch *DRW_cache_hair_get_fibers(struct HairSystem *hsys, const struct HairExportCache *hair_export, - const struct DRWHairFiberTextureBuffer **r_buffer); +struct Gwn_Batch *DRW_cache_hair_get_fibers(struct HairSystem *hsys, const struct HairExportCache *hair_export); struct Gwn_Batch *DRW_cache_hair_get_follicle_points(struct HairSystem *hsys, const struct HairExportCache *hair_export); -struct Gwn_Batch *DRW_cache_hair_get_guide_curve_edges(struct HairSystem *hsys, const struct HairExportCache *hair_export); /* Metaball */ struct Gwn_Batch *DRW_cache_mball_surface_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 5652657526f..caef4979ee3 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -38,7 +38,6 @@ struct ParticleSystem; struct PTCacheEdit; struct HairSystem; struct HairExportCache; -struct DRWHairFiberTextureBuffer; struct Curve; struct Lattice; @@ -149,9 +148,7 @@ struct Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points( struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit); /* Hair */ -struct Gwn_Batch *DRW_hair_batch_cache_get_fibers(struct HairSystem *hsys, const struct HairExportCache *hair_export, - const struct DRWHairFiberTextureBuffer **r_buffer); +struct Gwn_Batch *DRW_hair_batch_cache_get_fibers(struct HairSystem *hsys, const struct HairExportCache *hair_export); struct Gwn_Batch *DRW_hair_batch_cache_get_follicle_points(struct HairSystem *hsys, const struct HairExportCache *hair_export); -struct Gwn_Batch *DRW_hair_batch_cache_get_guide_curve_edges(struct HairSystem *hsys, const struct HairExportCache *hair_export); #endif /* __DRAW_CACHE_IMPL_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c index 9069ae7d3a8..1abcb109ac1 100644 --- a/source/blender/draw/intern/draw_cache_impl_hair.c +++ b/source/blender/draw/intern/draw_cache_impl_hair.c @@ -49,47 +49,21 @@ #include "draw_common.h" #include "draw_cache_impl.h" /* own include */ -#include "DRW_render.h" +#include "draw_hair_private.h" -// timing -//#define DEBUG_TIME -#ifdef DEBUG_TIME -# include "PIL_time_utildefines.h" -#else -# define TIMEIT_START(var) -# define TIMEIT_VALUE(var) -# define TIMEIT_VALUE_PRINT(var) -# define TIMEIT_END(var) -# define TIMEIT_BENCH(expr, id) (expr) -# define TIMEIT_BLOCK_INIT(var) -# define TIMEIT_BLOCK_START(var) -# define TIMEIT_BLOCK_END(var) -# define TIMEIT_BLOCK_STATS(var) -#endif +#include "DRW_render.h" /* ---------------------------------------------------------------------- */ /* Hair Gwn_Batch Cache */ +/* Gwn_Batch cache management. */ + typedef struct HairBatchCache { - Gwn_VertBuf *fiber_verts; - Gwn_IndexBuf *fiber_edges; - Gwn_Batch *fibers; - DRWHairFiberTextureBuffer texbuffer; - - Gwn_VertBuf *follicle_verts; - Gwn_IndexBuf *follicle_edges; - Gwn_Batch *follicles; - - Gwn_VertBuf *guide_curve_verts; - Gwn_IndexBuf *guide_curve_edges; - Gwn_Batch *guide_curves; - - /* settings to determine if cache is invalid */ + ParticleHairCache hair; + bool is_dirty; } HairBatchCache; -/* Gwn_Batch cache management. */ - static void hair_batch_cache_clear(HairSystem *hsys); static bool hair_batch_cache_valid(HairSystem *hsys) @@ -151,37 +125,8 @@ void DRW_hair_batch_cache_dirty(HairSystem *hsys, int mode) static void hair_batch_cache_clear(HairSystem *hsys) { HairBatchCache *cache = hsys->draw_batch_cache; - - if (hsys->draw_texture_cache) { - GPU_texture_free(hsys->draw_texture_cache); - hsys->draw_texture_cache = NULL; - } - if (cache) { - GWN_BATCH_DISCARD_SAFE(cache->fibers); - GWN_VERTBUF_DISCARD_SAFE(cache->fiber_verts); - GWN_INDEXBUF_DISCARD_SAFE(cache->fiber_edges); - - GWN_BATCH_DISCARD_SAFE(cache->follicles); - GWN_VERTBUF_DISCARD_SAFE(cache->follicle_verts); - GWN_INDEXBUF_DISCARD_SAFE(cache->follicle_edges); - - GWN_BATCH_DISCARD_SAFE(cache->guide_curves); - GWN_VERTBUF_DISCARD_SAFE(cache->guide_curve_verts); - GWN_INDEXBUF_DISCARD_SAFE(cache->guide_curve_edges); - - { - DRWHairFiberTextureBuffer *buffer = &cache->texbuffer; - if (buffer->data) { - MEM_freeN(buffer->data); - buffer->data = NULL; - } - buffer->fiber_start = 0; - buffer->strand_map_start = 0; - buffer->strand_vertex_start = 0; - buffer->width = 0; - buffer->height = 0; - } + particle_batch_cache_clear_hair(&cache->hair); } } @@ -191,243 +136,412 @@ void DRW_hair_batch_cache_free(HairSystem *hsys) MEM_SAFE_FREE(hsys->draw_batch_cache); } -static void hair_batch_cache_ensure_fibers(const HairExportCache *hair_export, HairBatchCache *cache) +static void ensure_seg_pt_count( + const HairExportCache *hair_export, + ParticleHairCache *cache) { - TIMEIT_START(hair_batch_cache_ensure_fibers); - - GWN_VERTBUF_DISCARD_SAFE(cache->fiber_verts); - GWN_INDEXBUF_DISCARD_SAFE(cache->fiber_edges); - - const int totfibers = hair_export->totfibercurves; - const int totpoint = hair_export->totfiberverts; - const int totseg = totpoint - totfibers; - - static Gwn_VertFormat format = { 0 }; - static unsigned curve_param_id, fiber_index_id; - - /* initialize vertex format */ - if (format.attrib_ct == 0) { - fiber_index_id = GWN_vertformat_attr_add(&format, "fiber_index", GWN_COMP_I32, 1, GWN_FETCH_INT); - curve_param_id = GWN_vertformat_attr_add(&format, "curve_param", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); - } - - cache->fiber_verts = GWN_vertbuf_create_with_format(&format); - - Gwn_IndexBufBuilder elb; + if ((cache->pos != NULL && cache->indices != NULL) || + (cache->proc_point_buf != NULL)) { - TIMEIT_START(data_alloc); - Gwn_PrimType prim_type; - unsigned prim_ct, vert_ct; - prim_type = GWN_PRIM_TRIS; - prim_ct = 2 * totseg; - vert_ct = 2 * totpoint; - - GWN_vertbuf_data_alloc(cache->fiber_verts, vert_ct); - GWN_indexbuf_init(&elb, prim_type, prim_ct, vert_ct); - TIMEIT_END(data_alloc); + return; } - - TIMEIT_START(data_fill); - TIMEIT_BLOCK_INIT(GWN_vertbuf_attr_set); - TIMEIT_BLOCK_INIT(GWN_indexbuf_add_tri_verts); - int vi = 0; - for (int i = 0; i < totfibers; ++i) { - const int fiblen = hair_export->fiber_numverts[i]; - const float da = fiblen > 1 ? 1.0f / (fiblen-1) : 0.0f; - - float a = 0.0f; - for (int k = 0; k < fiblen; ++k) { - TIMEIT_BLOCK_START(GWN_vertbuf_attr_set); - GWN_vertbuf_attr_set(cache->fiber_verts, fiber_index_id, vi, &i); - GWN_vertbuf_attr_set(cache->fiber_verts, curve_param_id, vi, &a); - GWN_vertbuf_attr_set(cache->fiber_verts, fiber_index_id, vi+1, &i); - GWN_vertbuf_attr_set(cache->fiber_verts, curve_param_id, vi+1, &a); - TIMEIT_BLOCK_END(GWN_vertbuf_attr_set); - - if (k > 0) { - TIMEIT_BLOCK_START(GWN_indexbuf_add_tri_verts); - GWN_indexbuf_add_tri_verts(&elb, vi-2, vi-1, vi+1); - GWN_indexbuf_add_tri_verts(&elb, vi+1, vi, vi-2); - TIMEIT_BLOCK_END(GWN_indexbuf_add_tri_verts); + + cache->strands_count = hair_export->totfollicles; + cache->elems_count = hair_export->totverts - hair_export->totcurves; + cache->point_count = hair_export->totverts; +} + +static void hair_batch_cache_fill_segments_proc_pos( + const HairExportCache *hair_export, + Gwn_VertBufRaw *attr_step) +{ + for (int i = 0; i < hair_export->totcurves; i++) { + const HairFiberCurve *curve = &hair_export->fiber_curves[i]; + const HairFiberVertex *verts = &hair_export->fiber_verts[curve->vertstart]; + if (curve->numverts < 2) { + continue; + } + float total_len = 0.0f; + const float *co_prev = NULL; + float *seg_data_first; + for (int j = 0; j < curve->numverts; j++) { + float *seg_data = (float *)GWN_vertbuf_raw_step(attr_step); + copy_v3_v3(seg_data, verts[j].co); + if (co_prev) { + total_len += len_v3v3(co_prev, verts[j].co); + } + else { + seg_data_first = seg_data; + } + seg_data[3] = total_len; + co_prev = verts[j].co; + } + if (total_len > 0.0f) { + /* Divide by total length to have a [0-1] number. */ + for (int j = 0; j < curve->numverts; j++, seg_data_first += 4) { + seg_data_first[3] /= total_len; } - - vi += 2; - a += da; } } - TIMEIT_BLOCK_STATS(GWN_vertbuf_attr_set); - TIMEIT_BLOCK_STATS(GWN_indexbuf_add_tri_verts); -#ifdef DEBUG_TIME - printf("Total GWN time: %f\n", _timeit_var_GWN_vertbuf_attr_set + _timeit_var_GWN_indexbuf_add_tri_verts); -#endif - fflush(stdout); - TIMEIT_END(data_fill); - - TIMEIT_BENCH(cache->fiber_edges = GWN_indexbuf_build(&elb), indexbuf_build); - - TIMEIT_END(hair_batch_cache_ensure_fibers); } -static void hair_batch_cache_ensure_fiber_texbuffer(const HairExportCache *hair_export, HairBatchCache *cache) +static void hair_batch_cache_ensure_procedural_pos( + const HairExportCache *hair_export, + ParticleHairCache *cache) { - DRWHairFiberTextureBuffer *buffer = &cache->texbuffer; - static const int elemsize = 8; - const int width = GPU_max_texture_size(); - const int align = width * elemsize; - - // Offsets in bytes - int b_size, b_strand_map_start, b_strand_vertex_start, b_fiber_start; - BKE_hair_get_texture_buffer_size(hair_export, &b_size, - &b_strand_map_start, &b_strand_vertex_start, &b_fiber_start); - // Pad for alignment - b_size += align - b_size % align; - - // Convert to element size as texture offsets - const int size = b_size / elemsize; - const int height = size / width; - - buffer->data = MEM_mallocN(b_size, "hair fiber texture buffer"); - BKE_hair_get_texture_buffer(hair_export, buffer->data); - - buffer->width = width; - buffer->height = height; - buffer->strand_map_start = b_strand_map_start / elemsize; - buffer->strand_vertex_start = b_strand_vertex_start / elemsize; - buffer->fiber_start = b_fiber_start / elemsize; + if (cache->proc_point_buf != NULL) { + return; + } + + /* initialize vertex format */ + Gwn_VertFormat format = {0}; + uint pos_id = GWN_vertformat_attr_add(&format, "posTime", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + + cache->proc_point_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(cache->proc_point_buf, cache->point_count); + + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(cache->proc_point_buf, pos_id, &pos_step); + + hair_batch_cache_fill_segments_proc_pos(hair_export, &pos_step); + + /* Create vbo immediatly to bind to texture buffer. */ + GWN_vertbuf_use(cache->proc_point_buf); + + cache->point_tex = GPU_texture_create_from_vertbuf(cache->proc_point_buf); } -Gwn_Batch *DRW_hair_batch_cache_get_fibers( - HairSystem *hsys, +static void hair_pack_mcol(MCol *mcol, unsigned short r_scol[3]) +{ + /* Convert to linear ushort and swizzle */ + r_scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); + r_scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); + r_scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); +} + +static int hair_batch_cache_fill_strands_data( const HairExportCache *hair_export, - const DRWHairFiberTextureBuffer **r_buffer) + Gwn_VertBufRaw *data_step, + Gwn_VertBufRaw *uv_step, int num_uv_layers, + Gwn_VertBufRaw *col_step, int num_col_layers) { - HairBatchCache *cache = hair_batch_cache_get(hsys); + int curr_point = 0; + for (int i = 0; i < hair_export->totcurves; i++) { + const HairFiberCurve *curve = &hair_export->fiber_curves[i]; + if (curve->numverts < 2) { + continue; + } - TIMEIT_START(DRW_hair_batch_cache_get_fibers); + uint *seg_data = (uint *)GWN_vertbuf_raw_step(data_step); + const uint numseg = curve->numverts - 1; + *seg_data = (curr_point & 0xFFFFFF) | (numseg << 24); + curr_point += curve->numverts; - if (cache->fibers == NULL) { - TIMEIT_BENCH(hair_batch_cache_ensure_fibers(hair_export, cache), - hair_batch_cache_ensure_fibers); + float (*uv)[2] = NULL; + MCol *mcol = NULL; + +#if 0 + particle_calculate_uvs( + psys, psmd, + is_simple, num_uv_layers, + is_child ? psys->child[i].parent : i, + is_child ? i : -1, + mtfaces, + *r_parent_uvs, &uv); + + particle_calculate_mcol( + psys, psmd, + is_simple, num_col_layers, + is_child ? psys->child[i].parent : i, + is_child ? i : -1, + mcols, + *r_parent_mcol, &mcol); +#else + /* XXX dummy uvs and mcols, TODO */ + uv = MEM_mallocN(sizeof(*uv) * num_uv_layers, __func__); + mcol = MEM_mallocN(sizeof(*mcol) * num_col_layers, __func__); + for (int k = 0; k < num_uv_layers; k++) { + zero_v3(uv[k]); + } + for (int k = 0; k < num_col_layers; k++) { + mcol[k].a = 255; + mcol[k].r = 255; + mcol[k].g = 0; + mcol[k].b = 255; + } +#endif + + for (int k = 0; k < num_uv_layers; k++) { + float *t_uv = (float *)GWN_vertbuf_raw_step(uv_step + k); + copy_v2_v2(t_uv, uv[k]); + } + for (int k = 0; k < num_col_layers; k++) { + unsigned short *scol = (unsigned short *)GWN_vertbuf_raw_step(col_step + k); + hair_pack_mcol(&mcol[k], scol); + } - TIMEIT_BENCH(cache->fibers = GWN_batch_create(GWN_PRIM_TRIS, cache->fiber_verts, cache->fiber_edges), - GWN_batch_create); + if (uv) { + MEM_freeN(uv); + } + if (mcol) { + MEM_freeN(mcol); + } + } + return curr_point; +} + +static void hair_batch_cache_ensure_procedural_strand_data( + const HairExportCache *hair_export, + ParticleHairCache *cache) +{ + int active_uv = 0; + int active_col = 0; + +#if 0 // TODO + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + + if (psmd != NULL && psmd->mesh_final != NULL) { + if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPUV)) { + cache->num_uv_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPUV); + active_uv = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPUV); + } + if (CustomData_has_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL)) { + cache->num_col_layers = CustomData_number_of_layers(&psmd->mesh_final->ldata, CD_MLOOPCOL); + active_col = CustomData_get_active_layer(&psmd->mesh_final->ldata, CD_MLOOPCOL); + } + } +#endif + + Gwn_VertBufRaw data_step; + Gwn_VertBufRaw uv_step[MAX_MTFACE]; + Gwn_VertBufRaw col_step[MAX_MCOL]; + + MTFace *mtfaces[MAX_MTFACE] = {NULL}; + MCol *mcols[MAX_MCOL] = {NULL}; + + Gwn_VertFormat format_data = {0}; + uint data_id = GWN_vertformat_attr_add(&format_data, "data", GWN_COMP_U32, 1, GWN_FETCH_INT); + + Gwn_VertFormat format_uv = {0}; + uint uv_id = GWN_vertformat_attr_add(&format_uv, "uv", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + Gwn_VertFormat format_col = {0}; + uint col_id = GWN_vertformat_attr_add(&format_col, "col", GWN_COMP_U16, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + memset(cache->uv_layer_names, 0, sizeof(cache->uv_layer_names)); + memset(cache->col_layer_names, 0, sizeof(cache->col_layer_names)); + + /* Strand Data */ + cache->proc_strand_buf = GWN_vertbuf_create_with_format(&format_data); + GWN_vertbuf_data_alloc(cache->proc_strand_buf, cache->strands_count); + GWN_vertbuf_attr_get_raw_data(cache->proc_strand_buf, data_id, &data_step); + +#if 0 // TODO + /* UV layers */ + for (int i = 0; i < cache->num_uv_layers; i++) { + cache->proc_uv_buf[i] = GWN_vertbuf_create_with_format(&format_uv); + GWN_vertbuf_data_alloc(cache->proc_uv_buf[i], cache->strands_count); + GWN_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]); - TIMEIT_BENCH(hair_batch_cache_ensure_fiber_texbuffer(hair_export, cache), - hair_batch_cache_ensure_fiber_texbuffer); + const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i); + uint hash = BLI_ghashutil_strhash_p(name); + int n = 0; + BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%u", hash); + BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash); + + if (i == active_uv) { + BLI_snprintf(cache->uv_layer_names[i][n], MAX_LAYER_NAME_LEN, "u"); + } } + /* Vertex colors */ + for (int i = 0; i < cache->num_col_layers; i++) { + cache->proc_col_buf[i] = GWN_vertbuf_create_with_format(&format_col); + GWN_vertbuf_data_alloc(cache->proc_col_buf[i], cache->strands_count); + GWN_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]); + + const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i); + uint hash = BLI_ghashutil_strhash_p(name); + int n = 0; + BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%u", hash); + + /* We only do vcols auto name that are not overridden by uvs */ + if (CustomData_get_named_layer_index(&psmd->mesh_final->ldata, CD_MLOOPUV, name) == -1) { + BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "a%u", hash); + } - if (r_buffer) { - *r_buffer = &cache->texbuffer; + if (i == active_col) { + BLI_snprintf(cache->col_layer_names[i][n], MAX_LAYER_NAME_LEN, "c"); + } } - TIMEIT_END(DRW_hair_batch_cache_get_fibers); + if (cache->num_uv_layers || cache->num_col_layers) { + BKE_mesh_tessface_ensure(psmd->mesh_final); + if (cache->num_uv_layers) { + for (int j = 0; j < cache->num_uv_layers; j++) { + mtfaces[j] = (MTFace *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MTFACE, j); + } + } + if (cache->num_col_layers) { + for (int j = 0; j < cache->num_col_layers; j++) { + mcols[j] = (MCol *)CustomData_get_layer_n(&psmd->mesh_final->fdata, CD_MCOL, j); + } + } + } +#endif - return cache->fibers; -} + hair_batch_cache_fill_strands_data( + hair_export, + &data_step, + uv_step, cache->num_uv_layers, + col_step, cache->num_col_layers); -static void hair_batch_cache_ensure_follicles( - const HairExportCache *hair_export, - eHairDrawFollicleMode mode, - HairBatchCache *cache) -{ - GWN_VERTBUF_DISCARD_SAFE(cache->follicle_verts); - GWN_INDEXBUF_DISCARD_SAFE(cache->follicle_edges); - - const unsigned int point_count = hair_export->totfibercurves; - - static Gwn_VertFormat format = { 0 }; - static unsigned pos_id; - - /* initialize vertex format */ - if (format.attrib_ct == 0) { - pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + /* Create vbo immediatly to bind to texture buffer. */ + GWN_vertbuf_use(cache->proc_strand_buf); + cache->strand_tex = GPU_texture_create_from_vertbuf(cache->proc_strand_buf); + + for (int i = 0; i < cache->num_uv_layers; i++) { + GWN_vertbuf_use(cache->proc_uv_buf[i]); + cache->uv_tex[i] = GPU_texture_create_from_vertbuf(cache->proc_uv_buf[i]); } - - cache->follicle_verts = GWN_vertbuf_create_with_format(&format); - - GWN_vertbuf_data_alloc(cache->follicle_verts, point_count); - - float (*root_co)[3] = hair_export->fiber_root_position; - for (int i = 0; i < hair_export->totfibercurves; ++i, ++root_co) { - GWN_vertbuf_attr_set(cache->follicle_verts, pos_id, (unsigned int)i, *root_co); + for (int i = 0; i < cache->num_col_layers; i++) { + GWN_vertbuf_use(cache->proc_col_buf[i]); + cache->col_tex[i] = GPU_texture_create_from_vertbuf(cache->proc_col_buf[i]); } - - UNUSED_VARS(mode); } -Gwn_Batch *DRW_hair_batch_cache_get_follicle_points(HairSystem *hsys, const HairExportCache *hair_export) +static void hair_batch_cache_ensure_procedural_final_points( + ParticleHairCache *cache, + int subdiv) { - HairBatchCache *cache = hair_batch_cache_get(hsys); + /* Same format as point_tex. */ + Gwn_VertFormat format = { 0 }; + GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); - if (cache->follicles == NULL) { - hair_batch_cache_ensure_follicles(hair_export, HAIR_DRAW_FOLLICLE_POINTS, cache); - - cache->follicles = GWN_batch_create(GWN_PRIM_POINTS, cache->follicle_verts, NULL); - } + cache->final[subdiv].proc_buf = GWN_vertbuf_create_with_format(&format); - return cache->follicles; + /* Create a destination buffer for the tranform feedback. Sized appropriately */ + /* Thoses are points! not line segments. */ + GWN_vertbuf_data_alloc(cache->final[subdiv].proc_buf, cache->final[subdiv].strands_res * cache->strands_count); + + /* Create vbo immediatly to bind to texture buffer. */ + GWN_vertbuf_use(cache->final[subdiv].proc_buf); + + cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_buf); } -static void hair_batch_cache_ensure_guide_curves( +static int hair_batch_cache_fill_segments_indices( const HairExportCache *hair_export, - eHairDrawGuideMode mode, - HairBatchCache *cache) + const int res, + Gwn_IndexBufBuilder *elb) { - GWN_VERTBUF_DISCARD_SAFE(cache->guide_curve_verts); - GWN_INDEXBUF_DISCARD_SAFE(cache->guide_curve_edges); - - const unsigned int point_count = hair_export->totguideverts; - /* One segment for each point, plus one for primitive restart index */ - const unsigned int elems_count = hair_export->totguideverts + hair_export->totguidecurves; - + int curr_point = 0; + for (int i = 0; i < hair_export->totcurves; i++) { + const HairFiberCurve *curve = &hair_export->fiber_curves[i]; + if (curve->numverts < 2) { + continue; + } + for (int k = 0; k < res; k++) { + GWN_indexbuf_add_generic_vert(elb, curr_point++); + } + GWN_indexbuf_add_primitive_restart(elb); + } + return curr_point; +} + +static void hair_batch_cache_ensure_procedural_indices( + const HairExportCache *hair_export, + ParticleHairCache *cache, + int thickness_res, + int subdiv) +{ + BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */ + + if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) { + return; + } + + int verts_per_hair = cache->final[subdiv].strands_res * thickness_res; + /* +1 for primitive restart */ + int element_count = (verts_per_hair + 1) * cache->strands_count; + Gwn_PrimType prim_type = (thickness_res == 1) ? GWN_PRIM_LINE_STRIP : GWN_PRIM_TRI_STRIP; + static Gwn_VertFormat format = { 0 }; - static unsigned pos_id; - + GWN_vertformat_clear(&format); + /* initialize vertex format */ - if (format.attrib_ct == 0) { - pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - } - - cache->guide_curve_verts = GWN_vertbuf_create_with_format(&format); - - GWN_vertbuf_data_alloc(cache->guide_curve_verts, point_count); - + GWN_vertformat_attr_add(&format, "dummy", GWN_COMP_U8, 1, GWN_FETCH_INT_TO_FLOAT_UNIT); + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, 1); + Gwn_IndexBufBuilder elb; - GWN_indexbuf_init_ex(&elb, - GWN_PRIM_LINE_STRIP, - elems_count, point_count, - true); - - unsigned int idx = 0; - const HairGuideCurve *curve = hair_export->guide_curves; - for (int i = 0; i < hair_export->totguidecurves; ++i, ++curve) { - const HairGuideVertex *vert = &hair_export->guide_verts[curve->vertstart]; - for (int j = 0; j < curve->numverts; ++j, ++vert) - { - GWN_vertbuf_attr_set(cache->guide_curve_verts, pos_id, idx, vert->co); - - GWN_indexbuf_add_generic_vert(&elb, idx); - - ++idx; - } - - GWN_indexbuf_add_primitive_restart(&elb); - } - - cache->guide_curve_edges = GWN_indexbuf_build(&elb); + GWN_indexbuf_init_ex(&elb, prim_type, element_count, element_count, true); + + hair_batch_cache_fill_segments_indices(hair_export, verts_per_hair, &elb); - UNUSED_VARS(mode); + cache->final[subdiv].proc_hairs[thickness_res - 1] = GWN_batch_create_ex( + prim_type, + vbo, + GWN_indexbuf_build(&elb), + GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); } -Gwn_Batch *DRW_hair_batch_cache_get_guide_curve_edges(HairSystem *hsys, const HairExportCache *hair_export) +/* Ensure all textures and buffers needed for GPU accelerated drawing. */ +bool hair_ensure_procedural_data( + Object *UNUSED(object), + HairSystem *hsys, + struct Mesh *scalp, + ParticleHairCache **r_hair_cache, + int subdiv, + int thickness_res) { + bool need_ft_update = false; + + HairExportCache *hair_export = BKE_hair_export_cache_new(); + BKE_hair_export_cache_update(hair_export, hsys, subdiv, scalp, HAIR_EXPORT_ALL); + HairBatchCache *cache = hair_batch_cache_get(hsys); + *r_hair_cache = &cache->hair; - if (cache->guide_curves == NULL) { - hair_batch_cache_ensure_guide_curves(hair_export, HAIR_DRAW_GUIDE_CURVES, cache); - - cache->guide_curves = GWN_batch_create(GWN_PRIM_LINE_STRIP, cache->guide_curve_verts, cache->guide_curve_edges); + const int hsys_subdiv = 0; // XXX TODO per-hsys or per-fiber subdiv + cache->hair.final[subdiv].strands_res = 1 << (hsys_subdiv + subdiv); + + /* Refreshed on combing and simulation. */ + if (cache->hair.proc_point_buf == NULL) { + ensure_seg_pt_count(hair_export, &cache->hair); + hair_batch_cache_ensure_procedural_pos(hair_export, &cache->hair); + need_ft_update = true; } - return cache->guide_curves; + /* Refreshed if active layer or custom data changes. */ + if (cache->hair.strand_tex == NULL) { + hair_batch_cache_ensure_procedural_strand_data(hair_export, &cache->hair); + } + + /* Refreshed only on subdiv count change. */ + if (cache->hair.final[subdiv].proc_buf == NULL) { + hair_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv); + need_ft_update = true; + } + if (cache->hair.final[subdiv].proc_hairs[thickness_res - 1] == NULL) { + hair_batch_cache_ensure_procedural_indices(hair_export, &cache->hair, thickness_res, subdiv); + } + + BKE_hair_export_cache_free(hair_export); + + return need_ft_update; +} + +Gwn_Batch *DRW_hair_batch_cache_get_fibers(HairSystem *hsys, const HairExportCache *hair_export) +{ + // TODO + UNUSED_VARS(hsys, hair_export); + return NULL; +} + +Gwn_Batch *DRW_hair_batch_cache_get_follicle_points(HairSystem *hsys, const HairExportCache *hair_export) +{ + // TODO + UNUSED_VARS(hsys, hair_export); + return NULL; } diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 28693b47c89..69b30dc7f17 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -162,37 +162,6 @@ static void particle_batch_cache_clear_point(ParticlePointCache *point_cache) GWN_VERTBUF_DISCARD_SAFE(point_cache->pos); } -static void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) -{ - /* TODO more granular update tagging. */ - GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); - - GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex); - - for (int i = 0; i < MAX_MTFACE; ++i) { - GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]); - DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]); - } - for (int i = 0; i < MAX_MCOL; ++i) { - GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]); - DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]); - } - for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) { - GWN_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); - DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); - for (int j = 0; j < MAX_THICKRES; ++j) { - GWN_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); - } - } - - /* "Normal" legacy hairs */ - GWN_BATCH_DISCARD_SAFE(hair_cache->hairs); - GWN_VERTBUF_DISCARD_SAFE(hair_cache->pos); - GWN_INDEXBUF_DISCARD_SAFE(hair_cache->indices); -} - static void particle_batch_cache_clear(ParticleSystem *psys) { ParticleBatchCache *cache = psys->batch_cache; diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index d2e9c4d1537..2e284761b11 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -166,16 +166,28 @@ void DRW_shgroup_armature_edit(struct Object *ob, struct DRWArmaturePasses passe /* This creates a shading group with display hairs. * The draw call is already added by this function, just add additional uniforms. */ -struct DRWShadingGroup *DRW_shgroup_hair_create( +struct DRWShadingGroup *DRW_shgroup_particle_hair_create( struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWPass *hair_pass, struct GPUShader *shader); -struct DRWShadingGroup *DRW_shgroup_material_hair_create( +struct DRWShadingGroup *DRW_shgroup_material_particle_hair_create( struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, struct DRWPass *hair_pass, struct GPUMaterial *material); +struct DRWShadingGroup *DRW_shgroup_hair_create( + struct Object *object, struct HairSystem *hsys, + struct Mesh *scalp, const struct HairDrawSettings *draw_set, + struct DRWPass *hair_pass, + struct GPUShader *shader); + +struct DRWShadingGroup *DRW_shgroup_material_hair_create( + struct Object *object, struct HairSystem *hsys, + struct Mesh *scalp, const struct HairDrawSettings *draw_set, + struct DRWPass *hair_pass, + struct GPUMaterial *material); + void DRW_hair_init(void); void DRW_hair_update(void); void DRW_hair_free(void); @@ -184,42 +196,4 @@ void DRW_hair_free(void); bool DRW_pose_mode_armature( struct Object *ob, struct Object *active_ob); -/* hair drawing */ -typedef struct DRWHairFiberTextureBuffer { - void *data; - int strand_map_start; - int strand_vertex_start; - int fiber_start; - int width; - int height; -} DRWHairFiberTextureBuffer; - -const char* DRW_hair_shader_defines(void); - -struct DRWShadingGroup *DRW_shgroup_hair_fibers_create( - struct Scene *scene, - struct Object *object, - struct HairSystem *hsys, - struct Mesh *scalp, - const struct HairDrawSettings *draw_set, - struct DRWPass *hair_pass, - struct GPUShader *shader); - -struct DRWShadingGroup *DRW_shgroup_material_hair_fibers_create( - struct Scene *scene, - struct Object *object, - struct HairSystem *hsys, - struct Mesh *scalp, - const struct HairDrawSettings *draw_set, - struct DRWPass *hair_pass, - struct GPUMaterial *material); - -void DRW_shgroup_hair( - struct Object *ob, - struct HairSystem *hsys, - struct HairDrawSettings *draw_settings, - struct Mesh *scalp, - struct DRWShadingGroup *shgrp_verts, - struct DRWShadingGroup *shgrp_edges); - #endif /* __DRAW_COMMON_H__ */ diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index fd0850eb2f2..aabca35c440 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -34,12 +34,14 @@ #include "BLI_utildefines.h" #include "BLI_string_utils.h" +#include "DNA_hair_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_particle_types.h" #include "DNA_customdata_types.h" +#include "BKE_hair.h" #include "BKE_mesh.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -60,7 +62,6 @@ static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL}; static DRWPass *g_tf_pass; /* XXX can be a problem with mulitple DRWManager in the future */ extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_hair_guides_lib_glsl[]; extern char datatoc_common_hair_refine_vert_glsl[]; static GPUShader *hair_refine_shader_get(ParticleRefineShader sh) @@ -86,7 +87,38 @@ void DRW_hair_init(void) g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_TRANS_FEEDBACK); } -static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex( +void particle_batch_cache_clear_hair(ParticleHairCache *hair_cache) +{ + /* TODO more granular update tagging. */ + GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_point_buf); + DRW_TEXTURE_FREE_SAFE(hair_cache->point_tex); + + GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_strand_buf); + DRW_TEXTURE_FREE_SAFE(hair_cache->strand_tex); + + for (int i = 0; i < MAX_MTFACE; ++i) { + GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_uv_buf[i]); + DRW_TEXTURE_FREE_SAFE(hair_cache->uv_tex[i]); + } + for (int i = 0; i < MAX_MCOL; ++i) { + GWN_VERTBUF_DISCARD_SAFE(hair_cache->proc_col_buf[i]); + DRW_TEXTURE_FREE_SAFE(hair_cache->col_tex[i]); + } + for (int i = 0; i < MAX_HAIR_SUBDIV; ++i) { + GWN_VERTBUF_DISCARD_SAFE(hair_cache->final[i].proc_buf); + DRW_TEXTURE_FREE_SAFE(hair_cache->final[i].proc_tex); + for (int j = 0; j < MAX_THICKRES; ++j) { + GWN_BATCH_DISCARD_SAFE(hair_cache->final[i].proc_hairs[j]); + } + } + + /* "Normal" legacy hairs */ + GWN_BATCH_DISCARD_SAFE(hair_cache->hairs); + GWN_VERTBUF_DISCARD_SAFE(hair_cache->pos); + GWN_INDEXBUF_DISCARD_SAFE(hair_cache->indices); +} + +static DRWShadingGroup *drw_shgroup_create_particle_hair_procedural_ex( Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, struct GPUMaterial *gpu_mat, GPUShader *gpu_shader) @@ -151,20 +183,102 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex( return shgrp; } -DRWShadingGroup *DRW_shgroup_hair_create( +DRWShadingGroup *DRW_shgroup_particle_hair_create( Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader) { - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader); + return drw_shgroup_create_particle_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader); } -DRWShadingGroup *DRW_shgroup_material_hair_create( +DRWShadingGroup *DRW_shgroup_material_particle_hair_create( Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, struct GPUMaterial *material) { - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL); + return drw_shgroup_create_particle_hair_procedural_ex(object, psys, md, hair_pass, material, NULL); +} + +static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex( + Object *object, HairSystem *hsys, Mesh *scalp, const HairDrawSettings *draw_set, + DRWPass *hair_pass, + struct GPUMaterial *gpu_mat, GPUShader *gpu_shader) +{ + /* TODO(fclem): Pass the scene as parameter */ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + int subdiv = scene->r.hair_subdiv; + int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2; + + ParticleHairCache *hair_cache; + bool need_ft_update = hair_ensure_procedural_data(object, hsys, scalp, &hair_cache, subdiv, thickness_res); + + DRWShadingGroup *shgrp; + if (gpu_mat) { + shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass); + } + else if (gpu_shader) { + shgrp = DRW_shgroup_create(gpu_shader, hair_pass); + } + else { + shgrp = NULL; + BLI_assert(0); + } + + /* TODO optimize this. Only bind the ones GPUMaterial needs. */ + for (int i = 0; i < hair_cache->num_uv_layers; ++i) { + for (int n = 0; hair_cache->uv_layer_names[i][n][0] != '\0'; ++n) { + DRW_shgroup_uniform_texture(shgrp, hair_cache->uv_layer_names[i][n], hair_cache->uv_tex[i]); + } + } + for (int i = 0; i < hair_cache->num_col_layers; ++i) { + for (int n = 0; hair_cache->col_layer_names[i][n][0] != '\0'; ++n) { + DRW_shgroup_uniform_texture(shgrp, hair_cache->col_layer_names[i][n], hair_cache->col_tex[i]); + } + } + + DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_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(shgrp, "hairRadShape", &draw_set->shape, 1); + DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", draw_set->root_radius * draw_set->radius_scale * 0.5f); + DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", draw_set->tip_radius * draw_set->radius_scale * 0.5f); + DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", (draw_set->shape_flag & PART_SHAPE_CLOSE_TIP) != 0); + /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass culling test. */ + DRW_shgroup_call_object_add_no_cull(shgrp, hair_cache->final[subdiv].proc_hairs[thickness_res - 1], object); + + /* Transform Feedback subdiv. */ + if (need_ft_update) { + int final_points_ct = hair_cache->final[subdiv].strands_res * hair_cache->strands_count; + GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM); + DRWShadingGroup *tf_shgrp = DRW_shgroup_transform_feedback_create(tf_shader, g_tf_pass, + hair_cache->final[subdiv].proc_buf); + DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", hair_cache->point_tex); + DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", hair_cache->strand_tex); + DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1); + DRW_shgroup_call_procedural_points_add(tf_shgrp, final_points_ct, NULL); + } + + return shgrp; +} + +DRWShadingGroup *DRW_shgroup_hair_create( + Object *object, HairSystem *hsys, + Mesh *scalp, const HairDrawSettings *draw_set, + DRWPass *hair_pass, + GPUShader *shader) +{ + return drw_shgroup_create_hair_procedural_ex(object, hsys, scalp, draw_set, hair_pass, NULL, shader); +} + +DRWShadingGroup *DRW_shgroup_material_hair_create( + Object *object, HairSystem *hsys, + Mesh *scalp, const HairDrawSettings *draw_set, + DRWPass *hair_pass, + struct GPUMaterial *material) +{ + return drw_shgroup_create_hair_procedural_ex(object, hsys, scalp, draw_set, hair_pass, material, NULL); } void DRW_hair_update(void) diff --git a/source/blender/draw/intern/draw_hair_fibers.c b/source/blender/draw/intern/draw_hair_fibers.c deleted file mode 100644 index 622a791ead9..00000000000 --- a/source/blender/draw/intern/draw_hair_fibers.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2016, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Blender Institute - * - */ - -/** \file draw_hair.c - * \ingroup draw - */ - -#include "BLI_utildefines.h" - -#include "DNA_hair_types.h" -#include "DNA_scene_types.h" - -#include "BKE_hair.h" - -#include "DRW_render.h" - -#include "GPU_extensions.h" -#include "GPU_texture.h" - -#include "draw_common.h" - -const char* DRW_hair_shader_defines(void) -{ - static char str[256]; - - BLI_snprintf(str, sizeof(str), "#define HAIR_SHADER\n#define HAIR_SHADER_FIBERS\n#define HAIR_SHADER_TEX_WIDTH %d\n", - GPU_max_texture_size()); - - return str; -} - -static DRWShadingGroup *drw_shgroup_create_hair_fibers_ex( - Scene *UNUSED(scene), Object *object, HairSystem *hsys, struct Mesh *scalp, - const HairDrawSettings *draw_set, DRWPass *hair_pass, - struct GPUMaterial *gpu_mat, GPUShader *gpu_shader) -{ - /* TODO */ - const int subdiv = 0; - - HairExportCache *hair_export = BKE_hair_export_cache_new(); - BKE_hair_export_cache_update(hair_export, hsys, subdiv, scalp, HAIR_EXPORT_ALL); - - const DRWHairFiberTextureBuffer *fiber_buffer = NULL; - struct Gwn_Batch *hair_geom = DRW_cache_hair_get_fibers(hsys, hair_export, &fiber_buffer); - - BKE_hair_export_cache_free(hair_export); - - DRWShadingGroup *shgrp; - if (gpu_mat) { - shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass); - } - else if (gpu_shader) { - shgrp = DRW_shgroup_create(gpu_shader, hair_pass); - } - else { - BLI_assert(0); - } - - if (!hsys->draw_texture_cache) { - hsys->draw_texture_cache = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, - GPU_RG32F, 0, fiber_buffer->data); - } - GPUTexture **fibertex = (GPUTexture **)(&hsys->draw_texture_cache); - - DRW_shgroup_uniform_texture_ref(shgrp, "fiber_data", fibertex); - DRW_shgroup_uniform_int(shgrp, "strand_map_start", &fiber_buffer->strand_map_start, 1); - DRW_shgroup_uniform_int(shgrp, "strand_vertex_start", &fiber_buffer->strand_vertex_start, 1); - DRW_shgroup_uniform_int(shgrp, "fiber_start", &fiber_buffer->fiber_start, 1); - - DRW_shgroup_uniform_float(shgrp, "hairRadShape", &draw_set->shape, 1); - DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", draw_set->root_radius * draw_set->radius_scale* 0.5f); - DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", draw_set->tip_radius * draw_set->radius_scale * 0.5f); - DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", (draw_set->shape_flag & HAIR_DRAW_CLOSE_TIP) != 0); - - /* TODO(fclem): Until we have a better way to cull the hair and render with orco, bypass culling test. */ - DRW_shgroup_call_object_add_no_cull(shgrp, hair_geom, object); - - return shgrp; -} - -DRWShadingGroup *DRW_shgroup_hair_fibers_create( - Scene *scene, Object *object, HairSystem *hsys, struct Mesh *scalp, - const HairDrawSettings *draw_set, DRWPass *hair_pass, - GPUShader *shader) -{ - return drw_shgroup_create_hair_fibers_ex(scene, object, hsys, scalp, draw_set, hair_pass, NULL, shader); -} - -DRWShadingGroup *DRW_shgroup_material_hair_fibers_create( - Scene *scene, Object *object, HairSystem *hsys, struct Mesh *scalp, - const HairDrawSettings *draw_set, DRWPass *hair_pass, - struct GPUMaterial *material) -{ - return drw_shgroup_create_hair_fibers_ex(scene, object, hsys, scalp, draw_set, hair_pass, material, NULL); -} - -void DRW_shgroup_hair( - Object *ob, - HairSystem *hsys, - HairDrawSettings *draw_settings, - struct Mesh *scalp, - DRWShadingGroup *shgrp_verts, - DRWShadingGroup *shgrp_edges) -{ - HairExportCache *hair_export = BKE_hair_export_cache_new(); - BKE_hair_export_cache_update(hair_export, hsys, 0, scalp, HAIR_EXPORT_GUIDE_CURVES | HAIR_EXPORT_GUIDE_VERTICES); - - switch (draw_settings->follicle_mode) - { - case HAIR_DRAW_FOLLICLE_NONE: - break; - case HAIR_DRAW_FOLLICLE_POINTS: - { - struct Gwn_Batch *geom = DRW_cache_hair_get_follicle_points(hsys, hair_export); - DRW_shgroup_call_add(shgrp_verts, geom, ob->obmat); - break; - } - } - - switch (draw_settings->guide_mode) - { - case HAIR_DRAW_GUIDE_NONE: - break; - case HAIR_DRAW_GUIDE_CURVES: - { - struct Gwn_Batch *geom = DRW_cache_hair_get_guide_curve_edges(hsys, hair_export); - DRW_shgroup_call_add(shgrp_edges, geom, ob->obmat); - break; - } - } - - BKE_hair_export_cache_free(hair_export); -} diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index 2e6c9a0d3c1..7f2c3d3eb1e 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -39,6 +39,7 @@ struct Object; struct ParticleSystem; struct ModifierData; struct ParticleHairCache; +struct HairSystem; typedef struct ParticleHairFinalCache { /* Output of the subdivision stage: vertex buff sized to subdiv level. */ @@ -81,6 +82,8 @@ typedef struct ParticleHairCache { int point_count; } ParticleHairCache; +void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache); + bool particles_ensure_procedural_data( struct Object *object, struct ParticleSystem *psys, @@ -89,4 +92,12 @@ bool particles_ensure_procedural_data( int subdiv, int thickness_res); +bool hair_ensure_procedural_data( + struct Object *object, + struct HairSystem *hsys, + struct Mesh *scalp, + struct ParticleHairCache **r_hair_cache, + int subdiv, + int thickness_res); + #endif /* __DRAW_HAIR_PRIVATE_H__ */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index c92d05f336d..8894c3e64ec 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -242,7 +242,6 @@ typedef struct OBJECT_PrivateData { /* Hair Systems */ DRWShadingGroup *hair_verts; - DRWShadingGroup *hair_edges; /* Outlines id offset */ int id_ofs_active; @@ -1323,10 +1322,6 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_uniform_vec4(stl->g_data->hair_verts, "color", ts.colorVertex, 1); DRW_shgroup_uniform_float(stl->g_data->hair_verts, "size", &ts.sizeVertex, 1); DRW_shgroup_state_enable(stl->g_data->hair_verts, DRW_STATE_POINT); - - GPUShader *sh_edges = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); - stl->g_data->hair_edges = DRW_shgroup_create(sh_edges, psl->hair); - DRW_shgroup_uniform_vec4(stl->g_data->hair_edges, "color", ts.colorWire, 1); } { @@ -2278,27 +2273,6 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) break; } - { - struct Mesh *scalp = ob->data; - if (scalp) - { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) - { - if (md->type == eModifierType_Hair) - { - HairModifierData *hmd = (HairModifierData*)md; - - if (!modifier_isEnabled(draw_ctx->scene, md, eModifierMode_Realtime)) - { - continue; - } - - DRW_shgroup_hair(ob, hmd->hair_system, hmd->draw_settings, scalp, stl->g_data->hair_verts, stl->g_data->hair_edges); - } - } - } - } - if (ob->pd && ob->pd->forcefield) { DRW_shgroup_forcefield(stl, ob, view_layer); } diff --git a/source/blender/draw/modes/shaders/common_hair_guides_lib.glsl b/source/blender/draw/modes/shaders/common_hair_guides_lib.glsl deleted file mode 100644 index b044420e037..00000000000 --- a/source/blender/draw/modes/shaders/common_hair_guides_lib.glsl +++ /dev/null @@ -1,296 +0,0 @@ -/* NOTE: Keep this code in sync with the C version in BKE_hair! */ - -#ifdef HAIR_SHADER_FIBERS - -/* Hair Displacement */ - -/* Note: The deformer functions below calculate a new location vector - * as well as a new direction (aka "normal"), using the partial derivatives of the transformation. - * - * Each transformation function can depend on the location L as well as the curve parameter t: - * - * Lnew = f(L, t) - * => dLnew/dt = del f/del L * dL/dt + del f/del t - * - * The first term is the Jacobian of the function f, dL/dt is the original direction vector. - * Some more information can be found here: - * https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch42.html - */ - -/* Float with single derivative */ -struct DualFloat -{ - float v; - float dv; -}; - -/* Vector with single derivative */ -struct DualVec3 -{ - vec3 v; - vec3 dv; -}; - -struct DeformParams -{ - /* Length where strand reaches final thickness */ - float taper_length; - /* Relative strand thickness at the tip. - * (0.0, 1.0] - * 0.0 : Strand clumps into a single line - * 1.0 : Strand does not clump at all - * (> 1.0 is possible but not recommended) - */ - float taper_thickness; - - /* Radius of the curls. - * >= 0.0 - */ - float curl_radius; - /* Steepness of curls - * < 0.0 : Clockwise curls - * > 0.0 : Anti-clockwise curls - */ - float curl_angle; -}; - -void calc_taper_factor(DeformParams params, float t, out DualFloat taper) -{ - /* Uses the right half of the smoothstep function */ - float x = (t + params.taper_length) / params.taper_length; - float dx = 1.0 / params.taper_length; - if (x > 2.0) - { - x = 2.0; - dx = 0.0; - } - - taper.v = 0.5 * x * x * (3 - x) - 1.0; - taper.dv = 1.5 * x * (2.0 - x) * dx; -} - -/* Hairs tend to stick together and run in parallel. - * The effect increases with distance from the root, - * as the stresses pulling fibers apart decrease. - */ -void deform_clump(DualFloat taper, DualVec3 target, float thickness, inout vec3 co, inout vec3 tang) -{ - DualFloat factor; - factor.v = taper.v * thickness; - factor.dv = taper.dv * thickness; - - vec3 nco; - vec3 ntang; - nco = co + (target.v - co) * factor.v; - ntang = normalize(tang - + (target.dv - tang) * factor.v - + (target.v - co) * factor.dv); - - co = nco; - tang = ntang; -} - -/*===================================*/ -/* Hair Interpolation */ - -uniform sampler2D fiber_data; - -uniform int fiber_start; -uniform int strand_map_start; -uniform int strand_vertex_start; - -#define INDEX_INVALID -1 - -vec2 read_texdata(int offset) -{ - ivec2 offset2 = ivec2(offset % HAIR_SHADER_TEX_WIDTH, offset / HAIR_SHADER_TEX_WIDTH); - return texelFetch(fiber_data, offset2, 0).rg; -} - -void get_strand_data(int index, out int start, out int count, out DeformParams deform_params) -{ - int offset = strand_map_start + index * 2; - vec2 a = read_texdata(offset); - vec2 b = read_texdata(offset + 1); - - start = floatBitsToInt(a.r); - count = floatBitsToInt(a.g); - - deform_params.taper_length = b.r; - deform_params.taper_thickness = b.g; - deform_params.curl_radius = 0.1; - deform_params.curl_angle = 0.2; -} - -void get_strand_vertex(int index, out vec3 co, out vec3 nor, out vec3 tang, out float len) -{ - int offset = strand_vertex_start + index * 5; - vec2 a = read_texdata(offset); - vec2 b = read_texdata(offset + 1); - vec2 c = read_texdata(offset + 2); - vec2 d = read_texdata(offset + 3); - vec2 e = read_texdata(offset + 4); - - co = vec3(a.rg, b.r); - nor = vec3(b.g, c.rg); - tang = vec3(d.rg, e.r); - len = e.g; -} - -void get_strand_root(int index, out vec3 co) -{ - int offset = strand_vertex_start + index * 5; - vec2 a = read_texdata(offset); - vec2 b = read_texdata(offset + 1); - - co = vec3(a.rg, b.r); -} - -void get_fiber_data(int fiber_index, out ivec4 parent_index, out vec4 parent_weight, out vec3 pos) -{ - int offset = fiber_start + fiber_index * 6; - vec2 a = read_texdata(offset); - vec2 b = read_texdata(offset + 1); - vec2 c = read_texdata(offset + 2); - vec2 d = read_texdata(offset + 3); - vec2 e = read_texdata(offset + 4); - vec2 f = read_texdata(offset + 5); - - parent_index = ivec4(floatBitsToInt(a.rg), floatBitsToInt(b.rg)); - parent_weight = vec4(c.rg, d.rg); - pos = vec3(e.rg, f.r); -} - -struct ParentCurveResult -{ - vec3 co; - vec3 nor; - vec3 tang; - float len; - - // Only needed for the primary parent curve - vec3 rootco; - DeformParams deform_params; -}; - -bool interpolate_parent_curve(int index, float curve_param, out ParentCurveResult result) -{ - if (index == INDEX_INVALID) - { - return false; - } - - int start, count; - get_strand_data(index, start, count, result.deform_params); - - get_strand_root(start, result.rootco); - -#if 0 // Don't have to worry about out-of-bounds segment here, as long as lerpfac becomes 0.0 when curve_param==1.0 - float maxlen = float(count - 1); - float arclength = curve_param * maxlen; - int segment = min(int(arclength), count - 2); - float lerpfac = arclength - min(floor(arclength), maxlen - 1.0); -#else - float maxlen = float(count - 1); - float arclength = curve_param * maxlen; - int segment = int(arclength); - float lerpfac = arclength - floor(arclength); -#endif - - vec3 co0, co1; - vec3 nor0, nor1; - vec3 tang0, tang1; - float len0, len1; - get_strand_vertex(start + segment, co0, nor0, tang0, len0); - get_strand_vertex(start + segment + 1, co1, nor1, tang1, len1); - - result.co = mix(co0, co1, lerpfac) - result.rootco; - result.nor = normalize(mix(nor0, nor1, lerpfac)); - result.tang = normalize(mix(tang0, tang1, lerpfac)); - result.len = mix(len0, len1, lerpfac); - - return true; -} - -void interpolate_vertex(int fiber_index, float curve_param, - out vec3 co, out vec3 tang) -{ - ivec4 parent_index; - vec4 parent_weight; - vec3 rootco; - get_fiber_data(fiber_index, parent_index, parent_weight, rootco); - - co = vec3(0.0); - tang = vec3(0.0); - - ParentCurveResult p1, p2, p3, p4; - if (interpolate_parent_curve(parent_index.x, curve_param, p1)) - { - vec3 defco = p1.co + rootco; - vec3 deftang = p1.tang; - - DualFloat taper; - calc_taper_factor(p1.deform_params, p1.len, taper); - if (taper.v > 0.0) - { - DualVec3 target; - target.v = p1.co + p1.rootco; - target.dv = p1.tang; - - deform_clump(taper, target, p1.deform_params.taper_thickness, defco, deftang); - - /* Modulate weights by taper factor, - * so influence of the parent increases with taper - */ - parent_weight.x = parent_weight.x * (1.0 - taper.v) + taper.v; - parent_weight.yzw = parent_weight.yzw * (1.0 - taper.v); - } - - co += parent_weight.x * (defco - rootco); - tang += parent_weight.x * normalize(deftang); - } - if (interpolate_parent_curve(parent_index.y, curve_param, p2)) - { - co += parent_weight.y * p2.co; - tang += parent_weight.y * p2.tang; - } - if (interpolate_parent_curve(parent_index.z, curve_param, p3)) - { - co += parent_weight.z * p3.co; - tang += parent_weight.z * p3.tang; - } - if (interpolate_parent_curve(parent_index.w, curve_param, p4)) - { - co += parent_weight.w * p4.co; - tang += parent_weight.w * p4.tang; - } - - co += rootco; - tang = normalize(tang); -} - -void hair_fiber_get_vertex( - int fiber_index, float curve_param, - bool is_persp, vec3 camera_pos, vec3 camera_z, - out vec3 pos, out vec3 tang, out vec3 binor, - out float time, out float thickness, out float thick_time) -{ - interpolate_vertex(fiber_index, curve_param, pos, tang); - - vec3 camera_vec = (is_persp) ? pos - camera_pos : -camera_z; - binor = normalize(cross(camera_vec, tang)); - - time = curve_param; - thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time); - - // TODO use the uniform for hairThicknessRes - int hairThicknessRes = 2; - if (hairThicknessRes > 1) { - thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1); - thick_time = thickness * (thick_time * 2.0 - 1.0); - - pos += binor * thick_time; - } -} - -#endif /*HAIR_SHADER_FIBERS*/ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 3aa64a68094..d9fefd2b5a9 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -37,6 +37,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" +#include "DNA_hair_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -2450,13 +2451,37 @@ static int hair_generate_follicles_exec(bContext *C, wmOperator *op) BLI_assert(ob && ob->type == OB_MESH); Mesh *scalp = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data); + HairSystem *hsys = hmd->hair_system; BKE_hair_generate_follicles( - hmd->hair_system, + hsys, scalp, (unsigned int)hmd->follicle_seed, hmd->follicle_count); + { + const int numverts = 5; + const float hairlen = 0.05f; + const float taper_length = 0.02f; + const float taper_thickness = 0.8f; + BKE_hair_fiber_curves_begin(hsys, hsys->pattern->num_follicles); + for (int i = 0; i < hsys->pattern->num_follicles; ++i) + { + BKE_hair_set_fiber_curve(hsys, i, numverts, taper_length, taper_thickness); + } + BKE_hair_fiber_curves_end(hsys); + for (int i = 0; i < hsys->pattern->num_follicles; ++i) + { + float loc[3], nor[3], tan[3]; + BKE_mesh_sample_eval(scalp, &hsys->pattern->follicles[i].mesh_sample, loc, nor, tan); + for (int j = 0; j < numverts; ++j) + { + madd_v3_v3fl(loc, nor, hairlen / (numverts-1)); + BKE_hair_set_fiber_vertex(hsys, i * numverts + j, 0, loc); + } + } + } + BKE_hair_bind_follicles(hmd->hair_system, scalp); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); diff --git a/source/blender/makesdna/DNA_hair_types.h b/source/blender/makesdna/DNA_hair_types.h index df407b85660..790d7952f4a 100644 --- a/source/blender/makesdna/DNA_hair_types.h +++ b/source/blender/makesdna/DNA_hair_types.h @@ -39,12 +39,9 @@ extern "C" { /* Root point (follicle) of a hair on a surface */ typedef struct HairFollicle { - /* Sample on the scalp mesh for the root vertex */ - MeshSample mesh_sample; - /* Parent curve indices for shape interpolation */ - unsigned int parent_index[4]; - /* Parent curve weights for shape interpolation */ - float parent_weight[4]; + MeshSample mesh_sample; /* Sample on the scalp mesh for the root vertex */ + unsigned int curve; /* Index of the curve used by the fiber */ + int pad; } HairFollicle; /* Collection of hair roots on a surface */ @@ -54,33 +51,32 @@ typedef struct HairPattern { int pad; } HairPattern; -typedef struct HairGuideCurve { - MeshSample mesh_sample; /* Sample on the scalp mesh for the root vertex */ +typedef struct HairFiberCurve { int vertstart; /* Offset in the vertex array where the curve starts */ int numverts; /* Number of vertices in the curve */ /* Shape */ float taper_length; /* Distance at which final thickness is reached */ float taper_thickness; /* Relative thickness of the strand */ -} HairGuideCurve; +} HairFiberCurve; -typedef struct HairGuideVertex { +typedef struct HairFiberVertex { int flag; float co[3]; -} HairGuideVertex; +} HairFiberVertex; -/* Guide curve data */ -typedef struct HairGuideData +/* Hair curve data */ +typedef struct HairCurveData { - /* Curves for guiding hair fibers */ - struct HairGuideCurve *curves; - /* Control vertices on guide curves */ - struct HairGuideVertex *verts; - /* Number of guide curves */ + /* Curves for shaping hair fibers */ + struct HairFiberCurve *curves; + /* Control vertices on curves */ + struct HairFiberVertex *verts; + /* Number of curves */ int totcurves; - /* Number of guide curve vertices */ + /* Number of curve vertices */ int totverts; -} HairGuideData; +} HairCurveData; typedef struct HairSystem { int flag; @@ -89,8 +85,8 @@ typedef struct HairSystem { /* Set of hair follicles on the scalp mesh */ struct HairPattern *pattern; - /* Guide curve data */ - HairGuideData guides; + /* Curve data */ + HairCurveData curve_data; /* Data buffers for drawing */ void *draw_batch_cache; @@ -100,14 +96,14 @@ typedef struct HairSystem { typedef enum eHairSystemFlag { - /* Guide curve positions have changed, rebind hair follicles */ + /* Curve positions have changed, rebind hair follicles */ HAIR_SYSTEM_UPDATE_FOLLICLE_BINDING = (1 << 8), } eHairSystemFlag; typedef struct HairDrawSettings { short follicle_mode; - short guide_mode; + short fiber_mode; short shape_flag; short pad; @@ -123,11 +119,11 @@ typedef enum eHairDrawFollicleMode HAIR_DRAW_FOLLICLE_POINTS = 1, } eHairDrawFollicleMode; -typedef enum eHairDrawGuideMode +typedef enum eHairDrawFiberMode { - HAIR_DRAW_GUIDE_NONE = 0, - HAIR_DRAW_GUIDE_CURVES = 1, -} eHairDrawGuideMode; + HAIR_DRAW_FIBER_NONE = 0, + HAIR_DRAW_FIBER_CURVES = 1, +} eHairDrawFiberMode; typedef enum eHairDrawShapeFlag { HAIR_DRAW_CLOSE_TIP = (1<<0), diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index e9f4492b954..62cc5631907 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1642,16 +1642,16 @@ enum { (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR) /* Hair modifier */ -typedef struct HairModifierGuideCurve { - struct HairModifierGuideCurve *next, *prev; +typedef struct HairModifierFiberCurve { + struct HairModifierFiberCurve *next, *prev; /* Index for the mesh sample buffer */ int mesh_sample_index; /* Number of vertices in the curve */ int numverts; /* Vertex array */ - struct HairGuideVertex *verts; -} HairModifierGuideCurve; + struct HairFiberVertex *verts; +} HairModifierFiberCurve; typedef struct HairModifierData { ModifierData modifier; @@ -1666,7 +1666,7 @@ typedef struct HairModifierData { int follicle_seed; int follicle_count; - ListBase guide_curves; + ListBase fiber_curves; } HairModifierData; #endif /* __DNA_MODIFIER_TYPES_H__ */ diff --git a/source/blender/makesrna/intern/rna_hair.c b/source/blender/makesrna/intern/rna_hair.c index f04420cf1ff..39bf28dff42 100644 --- a/source/blender/makesrna/intern/rna_hair.c +++ b/source/blender/makesrna/intern/rna_hair.c @@ -161,9 +161,9 @@ static void rna_def_hair_draw_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem guide_mode_items[] = { - {HAIR_DRAW_GUIDE_NONE, "NONE", 0, "None", ""}, - {HAIR_DRAW_GUIDE_CURVES, "CURVES", 0, "Curves", "Draw guide curves"}, + static const EnumPropertyItem fiber_mode_items[] = { + {HAIR_DRAW_FIBER_NONE, "NONE", 0, "None", ""}, + {HAIR_DRAW_FIBER_CURVES, "CURVES", 0, "Curves", "Draw fiber curves"}, {0, NULL, 0, NULL, NULL} }; @@ -176,9 +176,9 @@ static void rna_def_hair_draw_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Follicle Mode", "Draw follicles on the scalp surface"); RNA_def_property_update(prop, 0, "rna_HairDrawSettings_update"); - prop = RNA_def_property(srna, "guide_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, guide_mode_items); - RNA_def_property_ui_text(prop, "Guide Mode", "Draw guide curves"); + prop = RNA_def_property(srna, "fiber_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, fiber_mode_items); + RNA_def_property_ui_text(prop, "Fiber Mode", "Draw fiber curves"); RNA_def_property_update(prop, 0, "rna_HairDrawSettings_update"); /* hair shape */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index fc3177f9580..b3602af4d06 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1198,49 +1198,46 @@ static void rna_ParticleInstanceModifier_particle_system_set(PointerRNA *ptr, co CLAMP_MIN(psmd->psys, 1); } -static void rna_Hair_guide_curves_clear(HairModifierData *hmd) +static void rna_Hair_fiber_curves_clear(HairModifierData *hmd) { - for (HairModifierGuideCurve* curve = hmd->guide_curves.first; curve; curve = curve->next) + for (HairModifierFiberCurve* curve = hmd->fiber_curves.first; curve; curve = curve->next) { if (curve->verts) { MEM_freeN(curve->verts); } } - BLI_freelistN(&hmd->guide_curves); + BLI_freelistN(&hmd->fiber_curves); } -static void rna_Hair_guide_curves_new(HairModifierData *hmd, ReportList *UNUSED(reports), int numverts) +static void rna_Hair_fiber_curves_new(HairModifierData *hmd, ReportList *UNUSED(reports), int numverts) { - HairModifierGuideCurve *curve = MEM_callocN(sizeof(HairModifierGuideCurve), "hair guide curve"); + HairModifierFiberCurve *curve = MEM_callocN(sizeof(HairModifierFiberCurve), "hair fiber curve"); curve->numverts = numverts; - curve->verts = MEM_callocN(sizeof(HairGuideVertex) * numverts, "hair guide curve vertices"); + curve->verts = MEM_callocN(sizeof(HairFiberVertex) * numverts, "hair fiber curve vertices"); - BLI_addtail(&hmd->guide_curves, curve); + BLI_addtail(&hmd->fiber_curves, curve); } -static void rna_Hair_guide_curves_apply(ID *id, HairModifierData *hmd, bContext *C, ReportList *UNUSED(reports)) +static void rna_Hair_fiber_curves_apply(ID *id, HairModifierData *hmd, bContext *C, ReportList *UNUSED(reports)) { - const int totcurves = BLI_listbase_count(&hmd->guide_curves); + const int totcurves = BLI_listbase_count(&hmd->fiber_curves); int i = 0; - MeshSample msample; - memset(&msample, 0, sizeof(msample)); - - BKE_hair_guide_curves_begin(hmd->hair_system, totcurves); + BKE_hair_fiber_curves_begin(hmd->hair_system, totcurves); i = 0; - for (HairModifierGuideCurve *curve = hmd->guide_curves.first; curve; curve = curve->next, ++i) + for (HairModifierFiberCurve *curve = hmd->fiber_curves.first; curve; curve = curve->next, ++i) { - BKE_hair_set_guide_curve(hmd->hair_system, i, &msample, curve->numverts, 0.1, 1.0); + BKE_hair_set_fiber_curve(hmd->hair_system, i, curve->numverts, 0.1, 1.0); } - BKE_hair_guide_curves_end(hmd->hair_system); + BKE_hair_fiber_curves_end(hmd->hair_system); i = 0; - for (HairModifierGuideCurve *curve = hmd->guide_curves.first; curve; curve = curve->next) + for (HairModifierFiberCurve *curve = hmd->fiber_curves.first; curve; curve = curve->next) { for (int j = 0; j < curve->numverts; ++j, ++i) { - BKE_hair_set_guide_vertex(hmd->hair_system, i, curve->verts[j].flag, curve->verts[j].co); + BKE_hair_set_fiber_vertex(hmd->hair_system, i, curve->verts[j].flag, curve->verts[j].co); } } @@ -4960,49 +4957,49 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); } -static void rna_def_modifier_hair_guide_curve(BlenderRNA *brna) +static void rna_def_modifier_hair_fiber_curve(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "HairModifierGuideCurve", NULL); - RNA_def_struct_ui_text(srna, "Hair Modifier Guide Curve", ""); - RNA_def_struct_sdna(srna, "HairModifierGuideCurve"); + srna = RNA_def_struct(brna, "HairModifierFiberCurve", NULL); + RNA_def_struct_ui_text(srna, "Hair Modifier Fiber Curve", ""); + RNA_def_struct_sdna(srna, "HairModifierFiberCurve"); prop = RNA_def_property(srna, "vertices", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "verts", "numverts"); - RNA_def_property_struct_type(prop, "HairModifierGuideVertex"); - RNA_def_property_ui_text(prop, "Vertices", "Guide vertices"); + RNA_def_property_struct_type(prop, "HairModifierFiberVertex"); + RNA_def_property_ui_text(prop, "Vertices", "Fiber vertices"); - srna = RNA_def_struct(brna, "HairModifierGuideVertex", NULL); - RNA_def_struct_ui_text(srna, "Hair Modifier Guide Vertex", ""); - RNA_def_struct_sdna(srna, "HairGuideVertex"); + srna = RNA_def_struct(brna, "HairModifierFiberVertex", NULL); + RNA_def_struct_ui_text(srna, "Hair Modifier Fiber Vertex", ""); + RNA_def_struct_sdna(srna, "HairFiberVertex"); prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "co"); RNA_def_property_ui_text(prop, "Location", "Location of the vertex relative to the root"); } -static void rna_def_modifier_hair_guide_curves_api(BlenderRNA *brna, PropertyRNA *cprop) +static void rna_def_modifier_hair_fiber_curves_api(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; FunctionRNA *func; PropertyRNA *parm; - RNA_def_property_srna(cprop, "HairModifierGuideCurves"); - srna = RNA_def_struct(brna, "HairModifierGuideCurves", NULL); - RNA_def_struct_ui_text(srna, "Hair Modifier Guide Curves", ""); + RNA_def_property_srna(cprop, "HairModifierFiberCurves"); + srna = RNA_def_struct(brna, "HairModifierFiberCurves", NULL); + RNA_def_struct_ui_text(srna, "Hair Modifier Fiber Curves", ""); RNA_def_struct_sdna(srna, "HairModifierData"); - /*func =*/ RNA_def_function(srna, "clear", "rna_Hair_guide_curves_clear"); + /*func =*/ RNA_def_function(srna, "clear", "rna_Hair_fiber_curves_clear"); - func = RNA_def_function(srna, "new", "rna_Hair_guide_curves_new"); + func = RNA_def_function(srna, "new", "rna_Hair_fiber_curves_new"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int(func, "vertex_count", 2, 0, INT_MAX, "Vertex Count", "Number of vertices", 2, 1000); RNA_def_property_flag(parm, PARM_REQUIRED); - func = RNA_def_function(srna, "apply", "rna_Hair_guide_curves_apply"); + func = RNA_def_function(srna, "apply", "rna_Hair_fiber_curves_apply"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); } @@ -5034,13 +5031,13 @@ static void rna_def_modifier_hair(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Draw Settings", "Hair draw settings"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_property(srna, "guide_curves", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "guide_curves", NULL); - RNA_def_property_struct_type(prop, "HairModifierGuideCurve"); - RNA_def_property_ui_text(prop, "Guide Curves", "Guide curve data"); - rna_def_modifier_hair_guide_curves_api(brna, prop); + prop = RNA_def_property(srna, "fiber_curves", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "fiber_curves", NULL); + RNA_def_property_struct_type(prop, "HairModifierFiberCurve"); + RNA_def_property_ui_text(prop, "Fiber Curves", "Fiber curve data"); + rna_def_modifier_hair_fiber_curves_api(brna, prop); - rna_def_modifier_hair_guide_curve(brna); + rna_def_modifier_hair_fiber_curve(brna); } void RNA_def_modifier(BlenderRNA *brna) diff --git a/source/blender/modifiers/intern/MOD_hair.c b/source/blender/modifiers/intern/MOD_hair.c index dc4e2bf6c90..58b7e2f6920 100644 --- a/source/blender/modifiers/intern/MOD_hair.c +++ b/source/blender/modifiers/intern/MOD_hair.c @@ -28,7 +28,7 @@ * */ -/** \file blender/modifiers/intern/MOD_fur.c +/** \file blender/modifiers/intern/MOD_hair.c * \ingroup modifiers */ @@ -90,14 +90,14 @@ static void freeData(ModifierData *md) { BKE_hair_draw_settings_free(hmd->draw_settings); } - for (HairModifierGuideCurve *curve = hmd->guide_curves.first; curve; curve = curve->next) + for (HairModifierFiberCurve *curve = hmd->fiber_curves.first; curve; curve = curve->next) { if (curve->verts) { MEM_freeN(curve->verts); } } - BLI_freelistN(&hmd->guide_curves); + BLI_freelistN(&hmd->fiber_curves); } static struct Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, |