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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2018-08-12 13:17:33 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2018-08-12 13:17:33 +0300
commit209686f1c8189bc01f91d14a922651844df8b201 (patch)
tree75d90e46d148ef63653dbb7492292a75506eca80
parentb1e839d9e37eff389fb10fc2b93e22fd6efaea90 (diff)
parent27b28e437d974ebbafa234205941c07aa0ab546c (diff)
Merge branch 'hair_guides' into hair_guides_grooming
-rw-r--r--release/scripts/startup/bl_ui/__init__.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py11
-rw-r--r--release/scripts/startup/bl_ui/properties_hair_common.py (renamed from release/scripts/startup/bl_ui/properties_hair.py)43
-rw-r--r--source/blender/blenkernel/BKE_hair.h99
-rw-r--r--source/blender/blenkernel/intern/hair.c437
-rw-r--r--source/blender/blenkernel/intern/hair_draw.c222
-rw-r--r--source/blender/blenloader/intern/readfile.c6
-rw-r--r--source/blender/blenloader/intern/writefile.c4
-rw-r--r--source/blender/draw/CMakeLists.txt2
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c139
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h9
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl35
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl29
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl49
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c34
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c50
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c20
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h17
-rw-r--r--source/blender/draw/intern/draw_cache.c10
-rw-r--r--source/blender/draw/intern/draw_cache.h5
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.c633
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c138
-rw-r--r--source/blender/draw/intern/draw_common.h54
-rw-r--r--source/blender/draw/intern/draw_hair.c131
-rw-r--r--source/blender/draw/intern/draw_hair_fibers.c153
-rw-r--r--source/blender/draw/intern/draw_hair_private.h22
-rw-r--r--source/blender/draw/modes/object_mode.c26
-rw-r--r--source/blender/draw/modes/shaders/common_hair_guides_lib.glsl296
-rw-r--r--source/blender/draw/modes/shaders/common_hair_lib.glsl70
-rw-r--r--source/blender/editors/object/object_modifier.c27
-rw-r--r--source/blender/makesdna/DNA_hair_types.h52
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h10
-rw-r--r--source/blender/makesrna/intern/rna_hair.c12
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c77
-rw-r--r--source/blender/modifiers/intern/MOD_hair.c6
36 files changed, 1187 insertions, 1748 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 658b97d2992..1ef6566ed8e 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -43,7 +43,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 adea3696893..3f35e151ada 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,10 +53,10 @@ 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
* \param totverts Number of guide curve vertices to allocate
*/
void BKE_hair_guide_curves_alloc(struct HairSystem *hsys, int totcurves, int totverts);
@@ -64,33 +64,33 @@ void BKE_hair_guide_curves_alloc(struct HairSystem *hsys, int totcurves, int tot
/* Allocate buffers for defining guide curves
* \param totcurves Number of guide 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 === */
@@ -137,22 +137,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 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 curve data */
+ int totcurves;
+ struct HairFiberCurve *fiber_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;
@@ -160,28 +157,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;
@@ -233,6 +226,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);
@@ -241,6 +235,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 c68c758e955..3906dc2d105 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -5040,8 +5040,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;
@@ -5375,7 +5375,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 4ac422eed05..78fdf51b616 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1617,8 +1617,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 be5e50befe4..8f38b7e6408 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -67,7 +67,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
@@ -233,7 +232,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 e0eb5814ad8..ad2bf366310 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -45,7 +45,6 @@
#include "DNA_hair_types.h"
#include "GPU_material.h"
-#include "GPU_texture.h"
#include "eevee_engine.h"
#include "eevee_lut.h"
@@ -59,8 +58,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];
@@ -93,7 +90,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[];
@@ -293,9 +289,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");
}
@@ -575,7 +568,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,
@@ -592,7 +585,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(
@@ -611,25 +603,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,
@@ -834,14 +807,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, true);
if (mat) {
@@ -860,27 +832,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;
@@ -902,17 +866,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);
@@ -922,23 +887,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;
}
@@ -1290,8 +1262,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);
@@ -1376,7 +1348,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);
@@ -1464,12 +1436,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);
@@ -1482,12 +1454,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);
@@ -1511,8 +1483,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);
@@ -1521,7 +1493,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);
@@ -1544,21 +1516,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,
+ /*DRWShadingGroup *shgrp =*/ DRW_shgroup_hair_create(
+ ob, hsys, scalp, draw_set,
psl->depth_pass,
- e_data.default_prepass_hair_fiber_sh);
+ e_data.default_hair_prepass_sh);
}
{
- DRWShadingGroup *shgrp = DRW_shgroup_hair_fibers_create(
- scene, ob, hsys, scalp, draw_set,
+ DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
+ ob, hsys, scalp, draw_set,
psl->depth_pass_clip,
- e_data.default_prepass_hair_fiber_clip_sh);
+ e_data.default_hair_prepass_clip_sh);
DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo);
}
@@ -1575,13 +1552,13 @@ 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,
+ 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);
@@ -1604,8 +1581,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);
@@ -1615,10 +1592,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)
@@ -1901,8 +1878,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 7cc5f137b39..e2a875dca1f 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -122,12 +122,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),
@@ -806,9 +805,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 03efa4507d2..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,29 +41,11 @@ flat out int hairStrandID;
void main()
{
#ifdef HAIR_SHADER
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
-
-# ifdef HAIR_SHADER_FIBERS
- hairStrandID = fiber_index;
- 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 = normalize((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);
@@ -77,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..dfc45c8d04c 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
@@ -28,6 +23,8 @@ out vec3 normal_viewport;
out vec2 uv_interp;
#endif
+out int DEBUG;
+
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -39,42 +36,28 @@ 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
+ DEBUG = hair_get_strand_id();
+# 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 a3c57f5903e..ab7b79d1f55 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -86,7 +86,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[];
@@ -151,7 +150,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);
@@ -174,17 +172,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);
@@ -196,26 +194,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];
}
@@ -630,7 +622,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 ea48ccd78fb..b4cc731bff7 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -55,7 +55,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 */
@@ -69,7 +68,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[];
@@ -90,7 +88,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);
@@ -198,10 +195,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);
@@ -209,7 +206,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(
@@ -223,27 +220,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 */
@@ -273,10 +264,9 @@ 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, DRW_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 *forward_vert = workbench_build_forward_vert();
e_data.object_outline_sh = DRW_shader_create(
forward_vert, NULL,
@@ -287,9 +277,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_vert, defines_hair_fibers);
e_data.checker_depth_sh = DRW_shader_create_fullscreen(
@@ -385,7 +372,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();
@@ -429,7 +415,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);
@@ -448,7 +434,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 e2131db30c0..54e8aa1c3b3 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
@@ -144,7 +136,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;
@@ -160,8 +152,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 fb5bcfd432f..4210e03f470 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->shading.color_type & V3D_SHADING_TEXTURE_COLOR)
#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT)
@@ -142,17 +142,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;
@@ -261,18 +257,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 9922e241d75..7633605ff45 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3172,10 +3172,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)
@@ -3183,11 +3182,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 8678f9b1f5c..2702303e06a 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -34,7 +34,6 @@ struct PTCacheEdit;
struct Groom;
struct HairSystem;
struct HairExportCache;
-struct DRWHairFiberTextureBuffer;
void DRW_shape_cache_free(void);
void DRW_shape_cache_reset(void);
@@ -199,10 +198,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 d6c117321a7..9cd114c1454 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -39,7 +39,6 @@ struct PTCacheEdit;
struct Groom;
struct HairSystem;
struct HairExportCache;
-struct DRWHairFiberTextureBuffer;
struct Curve;
struct Lattice;
@@ -160,9 +159,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 ebbbdb45b9e..e945e2bb52e 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,421 @@ 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 hair_batch_cache_ensure_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.attr_len == 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);
+ cache->strands_len = hair_export->totfollicles;
+ cache->elems_len = hair_export->totverts - hair_export->totcurves;
+ cache->point_len = hair_export->totverts;
+}
- Gwn_IndexBufBuilder elb;
- {
- 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);
- }
-
- 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);
+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_len);
+
+ 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;
- TIMEIT_BENCH(cache->fibers = GWN_batch_create(GWN_PRIM_TRIS, cache->fiber_verts, cache->fiber_edges),
- GWN_batch_create);
+#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);
+ }
+
+ 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;
- TIMEIT_BENCH(hair_batch_cache_ensure_fiber_texbuffer(hair_export, cache),
- hair_batch_cache_ensure_fiber_texbuffer);
+ 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};
- if (r_buffer) {
- *r_buffer = &cache->texbuffer;
+ 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_len);
+ 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_len);
+ GWN_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
+
+ 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_len);
+ 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);
+ }
- TIMEIT_END(DRW_hair_batch_cache_get_fibers);
+ if (i == active_col) {
+ BLI_snprintf(cache->col_layer_names[i][n], MAX_LAYER_NAME_LEN, "c");
+ }
+ }
- return cache->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
+
+ hair_batch_cache_fill_strands_data(
+ hair_export,
+ &data_step,
+ uv_step, cache->num_uv_layers,
+ col_step, cache->num_col_layers);
+
+ /* 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]);
+ }
+ 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]);
+ }
}
-static void hair_batch_cache_ensure_follicles(
+static void hair_batch_cache_ensure_final_count(
const HairExportCache *hair_export,
- eHairDrawFollicleMode mode,
- HairBatchCache *cache)
+ ParticleHairFinalCache *cache,
+ int subdiv,
+ int thickness_res)
{
- 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.attr_len == 0) {
- pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
- }
-
- 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);
- }
-
- UNUSED_VARS(mode);
+ const int totverts = hair_export->totverts;
+ const int totcurves = hair_export->totcurves;
+ cache->strands_len = hair_export->totfollicles;
+ /* +1 for primitive restart */
+ cache->elems_len = (((totverts - totcurves) << subdiv) + totcurves) * thickness_res;
+ cache->point_len = ((totverts - totcurves) << subdiv) + totcurves;
}
-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_point_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_point_buf, cache->final[subdiv].point_len);
+
+ /* Create vbo immediatly to bind to texture buffer. */
+ GWN_vertbuf_use(cache->final[subdiv].proc_point_buf);
+
+ cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_point_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 subdiv,
+ const int thickness_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;
+ }
+
+ const int res = (((curve->numverts - 1) << subdiv) + 1) * thickness_res;
+ 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 element_count = cache->final[subdiv].elems_len;
+ 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.attr_len == 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);
- UNUSED_VARS(mode);
+ hair_batch_cache_fill_segments_indices(hair_export, subdiv, thickness_res, &elb);
+
+ 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);
+ /* Refreshed on combing and simulation. */
+ if (cache->hair.proc_point_buf == NULL) {
+ hair_batch_cache_ensure_count(hair_export, &cache->hair);
- cache->guide_curves = GWN_batch_create(GWN_PRIM_LINE_STRIP, cache->guide_curve_verts, cache->guide_curve_edges);
+ hair_batch_cache_ensure_procedural_pos(hair_export, &cache->hair);
+ need_ft_update = true;
+ }
+
+ /* 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);
}
- return cache->guide_curves;
+ /* Refreshed only on subdiv count change. */
+ if (cache->hair.final[subdiv].proc_point_buf == NULL) {
+ hair_batch_cache_ensure_final_count(hair_export, &cache->hair.final[subdiv], subdiv, thickness_res);
+
+ 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 df67d34d566..da360f89051 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;
@@ -654,19 +623,26 @@ static void particle_batch_cache_fill_segments_proc_pos(
}
static int particle_batch_cache_fill_segments_indices(
+ const ParticleSystem *psys,
ParticleCacheKey **path_cache,
const int start_index,
const int num_path_keys,
- const int res,
+ const int subdiv,
+ const int thickness_res,
Gwn_IndexBufBuilder *elb)
{
+ const ParticleSettings *part = psys->part;
+ const int points_per_curve = (1 << (part->draw_step + subdiv)) + 1;
+ const int points_per_hair = points_per_curve * thickness_res;
+
int curr_point = start_index;
for (int i = 0; i < num_path_keys; i++) {
ParticleCacheKey *path = path_cache[i];
if (path->segments <= 0) {
continue;
}
- for (int k = 0; k < res; k++) {
+
+ for (int k = 0; k < points_per_hair; k++) {
GWN_indexbuf_add_generic_vert(elb, curr_point++);
}
GWN_indexbuf_add_primitive_restart(elb);
@@ -749,24 +725,93 @@ static int particle_batch_cache_fill_strands_data(
return curr_point;
}
+static void ensure_seg_pt_final_count(
+ const ParticleSystem *psys,
+ ParticleHairCache *hair_cache,
+ int subdiv,
+ int thickness_res)
+{
+ ParticleHairFinalCache *final_cache = &hair_cache->final[subdiv];
+
+ const ParticleSettings *part = psys->part;
+ const int points_per_curve = (1 << (part->draw_step + subdiv)) + 1;
+
+ final_cache->strands_len = hair_cache->strands_len;
+ final_cache->point_len = points_per_curve * final_cache->strands_len;
+
+ /* +1 for primitive restart */
+ final_cache->elems_len = (points_per_curve * thickness_res + 1) * final_cache->strands_len;
+}
+
+#define USE_POSITION_HAIR_INDEX
+
static void particle_batch_cache_ensure_procedural_final_points(
+ const ParticleSystem *psys,
ParticleHairCache *cache,
int subdiv)
{
+
/* Same format as point_tex. */
+#ifdef USE_POSITION_HAIR_INDEX
+ static Gwn_VertFormat format = { 0 };
+ GWN_vertformat_clear(&format);
+ uint pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+#else
Gwn_VertFormat format = { 0 };
GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+#endif
- cache->final[subdiv].proc_buf = GWN_vertbuf_create_with_format(&format);
+ cache->final[subdiv].proc_point_buf = GWN_vertbuf_create_with_format(&format);
/* 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_len);
+ GWN_vertbuf_data_alloc(cache->final[subdiv].proc_point_buf, cache->final[subdiv].point_len);
+
+#ifdef USE_POSITION_HAIR_INDEX
+ Gwn_VertBufRaw data_step;
+ GWN_vertbuf_attr_get_raw_data(cache->final[subdiv].proc_point_buf, pos_id, &data_step);
+ const int points_per_curve = (1 << (psys->part->draw_step + subdiv)) + 1;
+ for (int i = 0; i < cache->final[subdiv].strands_len; i++) {
+ for (int j = 0; j < points_per_curve; ++j) {
+ uint *data = (uint *)GWN_vertbuf_raw_step(&data_step);
+ *data = (uint)i;
+ }
+ }
+#endif
+
+ /* Create vbo immediatly to bind to texture buffer. */
+ GWN_vertbuf_use(cache->final[subdiv].proc_point_buf);
+
+ cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_point_buf);
+}
+
+static void particle_batch_cache_ensure_procedural_final_hair_index(
+ const ParticleSystem *psys,
+ ParticleHairCache *cache,
+ int subdiv)
+{
+ /* Same format as point_tex. */
+ Gwn_VertFormat format = { 0 };
+ uint hair_index_id = GWN_vertformat_attr_add(&format, "hair_index", GWN_COMP_U32, 1, GWN_FETCH_INT);
+
+ cache->final[subdiv].proc_hair_index_buf = GWN_vertbuf_create_with_format(&format);
+
+ GWN_vertbuf_data_alloc(cache->final[subdiv].proc_hair_index_buf, cache->final[subdiv].point_len);
+
+ Gwn_VertBufRaw data_step;
+ GWN_vertbuf_attr_get_raw_data(cache->final[subdiv].proc_hair_index_buf, hair_index_id, &data_step);
+ const int points_per_curve = (1 << (psys->part->draw_step + subdiv)) + 1;
+ for (int i = 0; i < cache->final[subdiv].strands_len; i++) {
+ for (int j = 0; j < points_per_curve; ++j) {
+ uint *data = (uint *)GWN_vertbuf_raw_step(&data_step);
+ *data = (uint)i;
+ }
+ }
/* Create vbo immediatly to bind to texture buffer. */
- GWN_vertbuf_use(cache->final[subdiv].proc_buf);
+ GWN_vertbuf_use(cache->final[subdiv].proc_hair_index_buf);
- cache->final[subdiv].proc_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_buf);
+ cache->final[subdiv].hair_index_tex = GPU_texture_create_from_vertbuf(cache->final[subdiv].proc_hair_index_buf);
}
static void particle_batch_cache_ensure_procedural_strand_data(
@@ -940,9 +985,7 @@ static void particle_batch_cache_ensure_procedural_indices(
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_len;
+ int element_count = cache->final[subdiv].elems_len;
Gwn_PrimType prim_type = (thickness_res == 1) ? GWN_PRIM_LINE_STRIP : GWN_PRIM_TRI_STRIP;
static Gwn_VertFormat format = { 0 };
@@ -959,7 +1002,7 @@ static void particle_batch_cache_ensure_procedural_indices(
if (edit != NULL && edit->pathcache != NULL) {
particle_batch_cache_fill_segments_indices(
- edit->pathcache, 0, edit->totcached, verts_per_hair, &elb);
+ psys, edit->pathcache, 0, edit->totcached, subdiv, thickness_res, &elb);
}
else {
int curr_point = 0;
@@ -967,12 +1010,12 @@ static void particle_batch_cache_ensure_procedural_indices(
(!psys->childcache || (psys->part->draw & PART_DRAW_PARENT)))
{
curr_point = particle_batch_cache_fill_segments_indices(
- psys->pathcache, 0, psys->totpart, verts_per_hair, &elb);
+ psys, psys->pathcache, 0, psys->totpart, subdiv, thickness_res, &elb);
}
if (psys->childcache) {
const int child_count = psys->totchild * psys->part->disp / 100;
curr_point = particle_batch_cache_fill_segments_indices(
- psys->childcache, curr_point, child_count, verts_per_hair, &elb);
+ psys, psys->childcache, curr_point, child_count, subdiv, thickness_res, &elb);
}
}
@@ -1555,12 +1598,9 @@ bool particles_ensure_procedural_data(
ParticleDrawSource source;
drw_particle_get_hair_source(object, psys, md, NULL, &source);
- ParticleSettings *part = source.psys->part;
ParticleBatchCache *cache = particle_batch_cache_get(source.psys);
*r_hair_cache = &cache->hair;
- (*r_hair_cache)->final[subdiv].strands_res = 1 << (part->draw_step + subdiv);
-
/* Refreshed on combing and simulation. */
if ((*r_hair_cache)->proc_point_buf == NULL) {
ensure_seg_pt_count(source.edit, source.psys, &cache->hair);
@@ -1574,8 +1614,10 @@ bool particles_ensure_procedural_data(
}
/* Refreshed only on subdiv count change. */
- if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
- particle_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv);
+ if ((*r_hair_cache)->final[subdiv].proc_point_buf == NULL) {
+ ensure_seg_pt_final_count(psys, &cache->hair, subdiv, thickness_res);
+ particle_batch_cache_ensure_procedural_final_points(psys, &cache->hair, subdiv);
+ particle_batch_cache_ensure_procedural_final_hair_index(psys, &cache->hair, subdiv);
need_ft_update = true;
}
if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
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 f43a9b95df8..7406e7a0645 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_point_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)
@@ -127,7 +159,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(
}
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_texture(shgrp, "hairIndexBuffer", hair_cache->final[subdiv].hair_index_tex);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float(shgrp, "hairRadShape", &part->shape, 1);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", part->rad_root * part->rad_scale * 0.5f);
@@ -138,33 +170,110 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(
/* Transform Feedback subdiv. */
if (need_ft_update) {
- int final_points_len = hair_cache->final[subdiv].strands_res * hair_cache->strands_len;
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);
+ hair_cache->final[subdiv].proc_point_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_len, NULL);
+ DRW_shgroup_call_procedural_points_add(tf_shgrp, hair_cache->final[subdiv].point_len, NULL);
}
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_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) {
+ 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_point_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_call_procedural_points_add(tf_shgrp, hair_cache->final[subdiv].point_len, 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 eccd65cd507..00000000000
--- a/source/blender/draw/intern/draw_hair_fibers.c
+++ /dev/null
@@ -1,153 +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 *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;
- int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
-
- 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_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 & 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 17acd7e6259..e035131b4d7 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -39,16 +39,22 @@ struct Object;
struct ParticleSystem;
struct ModifierData;
struct ParticleHairCache;
+struct HairSystem;
typedef struct ParticleHairFinalCache {
/* Output of the subdivision stage: vertex buff sized to subdiv level. */
- Gwn_VertBuf *proc_buf;
+ Gwn_VertBuf *proc_point_buf;
GPUTexture *proc_tex;
- /* Just contains a huge index buffer used to draw the final hair. */
+ Gwn_VertBuf *proc_hair_index_buf; /* Hair strand index for each vertex */
+ GPUTexture *hair_index_tex;
+
+ /* Just contains a huge index buffer used to draw the final hair. */
Gwn_Batch *proc_hairs[MAX_THICKRES];
- int strands_res; /* points per hair, at least 2 */
+ int strands_len;
+ int elems_len;
+ int point_len;
} ParticleHairFinalCache;
typedef struct ParticleHairCache {
@@ -81,6 +87,8 @@ typedef struct ParticleHairCache {
int point_len;
} ParticleHairCache;
+void particle_batch_cache_clear_hair(struct ParticleHairCache *hair_cache);
+
bool particles_ensure_procedural_data(
struct Object *object,
struct ParticleSystem *psys,
@@ -89,4 +97,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 ea36b03284b..b8964e2682b 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -244,7 +244,6 @@ typedef struct OBJECT_PrivateData {
/* Hair Systems */
DRWShadingGroup *hair_verts;
- DRWShadingGroup *hair_edges;
/* Outlines id offset */
int id_ofs_active;
@@ -1346,10 +1345,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);
}
{
@@ -2353,27 +2348,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 83ac4bcceb2..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 * (1.0 - thickness);
- factor.dv = taper.dv * (1.0 - 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/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/modes/shaders/common_hair_lib.glsl
index 552690ba972..75e58adf374 100644
--- a/source/blender/draw/modes/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/modes/shaders/common_hair_lib.glsl
@@ -6,13 +6,6 @@
**/
/**
- * hairStrandsRes: Number of points per hair strand.
- * 2 - no subdivision
- * 3+ - 1 or more interpolated points per hair.
- **/
-uniform int hairStrandsRes = 8;
-
-/**
* hairThicknessRes : Subdiv around the hair.
* 1 - Wire Hair: Only one pixel thick, independant of view distance.
* 2 - Polystrip Hair: Correct width, flat if camera is parallel.
@@ -33,6 +26,7 @@ uniform samplerBuffer hairPointBuffer; /* RGBA32F */
/* -- Per strands data -- */
uniform usamplerBuffer hairStrandBuffer; /* R32UI */
+uniform usamplerBuffer hairIndexBuffer; /* R32UI */
/* Not used, use one buffer per uv layer */
//uniform samplerBuffer hairUVBuffer; /* RG32F */
@@ -49,6 +43,13 @@ void unpack_strand_data(uint data, out int strand_offset, out int strand_segment
#endif
}
+int hair_get_strand_id(void)
+{
+ //return gl_VertexID / (hairStrandsRes * hairThicknessRes);
+ uint strand_index = texelFetch(hairIndexBuffer, gl_VertexID).x;
+ return int(strand_index);
+}
+
/* -- Subdivision stage -- */
/**
* We use a transform feedback to preprocess the strands and add more subdivision to it.
@@ -59,40 +60,40 @@ void unpack_strand_data(uint data, out int strand_offset, out int strand_segment
**/
#ifdef HAIR_PHASE_SUBDIV
-int hair_get_base_id(float local_time, int strand_segments, out float interp_time)
+/**
+ * Calculate segment and local time for interpolation
+ */
+void hair_get_interp_time(float local_time, int strand_segments, out int interp_segment, out float interp_time)
{
float time_per_strand_seg = 1.0 / float(strand_segments);
float ratio = local_time / time_per_strand_seg;
+ interp_segment = int(ratio);
interp_time = fract(ratio);
-
- return int(ratio);
}
void hair_get_interp_attribs(out vec4 data0, out vec4 data1, out vec4 data2, out vec4 data3, out float interp_time)
{
- float local_time = float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1);
-
- int hair_id = gl_VertexID / hairStrandsRes;
- uint strand_data = texelFetch(hairStrandBuffer, hair_id).x;
-
+ int strand_index = hair_get_strand_id();
+ uint strand_data = texelFetch(hairStrandBuffer, strand_index).x;
int strand_offset, strand_segments;
unpack_strand_data(strand_data, strand_offset, strand_segments);
- int id = hair_get_base_id(local_time, strand_segments, interp_time);
+ float local_time = float(gl_VertexID - strand_offset) / float(strand_segments);
+ int interp_segment;
+ hair_get_interp_time(local_time, strand_segments, interp_segment, interp_time);
+ int interp_point = interp_segment + strand_offset;
- int ofs_id = id + strand_offset;
+ data0 = texelFetch(hairPointBuffer, interp_point - 1);
+ data1 = texelFetch(hairPointBuffer, interp_point);
+ data2 = texelFetch(hairPointBuffer, interp_point + 1);
+ data3 = texelFetch(hairPointBuffer, interp_point + 2);
- data0 = texelFetch(hairPointBuffer, ofs_id - 1);
- data1 = texelFetch(hairPointBuffer, ofs_id);
- data2 = texelFetch(hairPointBuffer, ofs_id + 1);
- data3 = texelFetch(hairPointBuffer, ofs_id + 2);
-
- if (id <= 0) {
+ if (interp_segment <= 0) {
/* root points. Need to reconstruct previous data. */
data0 = data1 * 2.0 - data2;
}
- if (id + 1 >= strand_segments) {
+ if (interp_segment + 1 >= strand_segments) {
/* tip points. Need to reconstruct next data. */
data3 = data2 * 2.0 - data1;
}
@@ -105,11 +106,6 @@ void hair_get_interp_attribs(out vec4 data0, out vec4 data1, out vec4 data2, out
**/
#ifndef HAIR_PHASE_SUBDIV
-int hair_get_strand_id(void)
-{
- return gl_VertexID / (hairStrandsRes * hairThicknessRes);
-}
-
int hair_get_base_id(void)
{
return gl_VertexID / hairThicknessRes;
@@ -165,25 +161,25 @@ void hair_get_pos_tan_binor_time(
vec2 hair_get_customdata_vec2(const samplerBuffer cd_buf)
{
- int id = hair_get_strand_id();
- return texelFetch(cd_buf, id).rg;
+ int strand_index = hair_get_strand_id();
+ return texelFetch(cd_buf, strand_index).rg;
}
vec3 hair_get_customdata_vec3(const samplerBuffer cd_buf)
{
- int id = hair_get_strand_id();
- return texelFetch(cd_buf, id).rgb;
+ int strand_index = hair_get_strand_id();
+ return texelFetch(cd_buf, strand_index).rgb;
}
vec4 hair_get_customdata_vec4(const samplerBuffer cd_buf)
{
- int id = hair_get_strand_id();
- return texelFetch(cd_buf, id).rgba;
+ int strand_index = hair_get_strand_id();
+ return texelFetch(cd_buf, strand_index).rgba;
}
-vec3 hair_get_strand_pos(void)
+vec3 hair_get_strand_pos()
{
- int id = hair_get_strand_id() * hairStrandsRes;
+ int id = hair_get_base_id();
return texelFetch(hairPointBuffer, id).point_position;
}
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index aa8489d2cf9..f2122f7961a 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"
@@ -2440,13 +2441,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 a04ad732ee7..e3d02cdc0c8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1640,16 +1640,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;
@@ -1664,7 +1664,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 965c0893ec6..a25684b0f80 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1179,49 +1179,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);
}
}
@@ -4941,49 +4938,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);
}
@@ -5015,13 +5012,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 538687b6525..11edff95da6 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,