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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2017-08-14 09:58:02 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2017-08-14 09:58:02 +0300
commitb0717ad91eedb64fa23a7ac16403d3fc166e447a (patch)
treeeed9d3061d44ef55fb131140710f10017621424d /source/blender/draw
parent91fd0a487d95e604c1c245905895123eeaf2ca0e (diff)
Hair drawing data based on the new DNA hair groups.
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c332
-rw-r--r--source/blender/draw/engines/eevee/shaders/hair_lib.glsl8
-rw-r--r--source/blender/draw/intern/draw_cache.c10
-rw-r--r--source/blender/draw/intern/draw_cache.h6
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h9
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.c310
-rw-r--r--source/blender/draw/intern/draw_cache_impl_strands.c8
-rw-r--r--source/blender/draw/intern/draw_hair.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c6
10 files changed, 577 insertions, 115 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index c6b07c76d83..bcedcfc0f0a 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
intern/draw_cache.c
intern/draw_cache_impl_curve.c
intern/draw_cache_impl_displist.c
+ intern/draw_cache_impl_hair.c
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.c
intern/draw_cache_impl_particles.c
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index e91ffeaa6b8..3cc6ca81171 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -25,19 +25,23 @@
#include "DRW_render.h"
-#include "DNA_world_types.h"
+#include "DNA_hair_types.h"
#include "DNA_modifier_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_alloca.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_editstrands.h"
#include "BKE_particle.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "DEG_depsgraph.h"
+
#include "GPU_material.h"
#include "GPU_texture.h"
@@ -1003,6 +1007,219 @@ static void material_transparent(
}
}
+static void material_particle_hair(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata,
+ Object *ob, ParticleSystem *psys, ModifierData *md)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ GHash *material_hash = stl->g_data->hair_material_hash;
+
+ if (!psys_check_enabled(ob, psys, false)) {
+ return;
+ }
+
+ ParticleSettings *part = psys->part;
+ bool use_hair = false;
+ bool use_fibers = false;
+ float mat[4][4];
+ struct Gwn_Batch *hair_geom = NULL;
+ const DRWHairFiberTextureBuffer *fiber_buffer = NULL;
+ GPUTexture **fiber_texture = NULL;
+
+ if (ob->mode & OB_MODE_HAIR_EDIT) {
+ BMEditStrands *edit = psys->hairedit;
+ const HairEditSettings *tsettings = &scene->toolsettings->hair_edit;
+ if (edit &&tsettings->hair_draw_mode == HAIR_DRAW_FIBERS && edit->hair_group) {
+ use_hair = true;
+ use_fibers = true;
+ copy_m4_m4(mat, ob->obmat);
+
+ hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer);
+
+ if (!edit->texture) {
+ edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height,
+ DRW_TEX_RG_32, 0, fiber_buffer->data);
+ }
+ fiber_texture = (GPUTexture **)(&edit->texture);
+ }
+ }
+ else {
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+ if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) {
+ use_hair = true;
+ unit_m4(mat);
+ hair_geom = DRW_cache_particles_get_hair(psys, md);
+ }
+ }
+
+ if (use_hair) {
+ Material *ma = give_current_material(ob, part->omat);
+ if (ma == NULL) {
+ ma = &defmaterial;
+ }
+
+ if (!use_fibers) {
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat);
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat);
+ }
+ else {
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat);
+ DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene,
+ fiber_texture, fiber_buffer);
+
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat);
+ DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene,
+ fiber_texture, fiber_buffer);
+ }
+
+ DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
+ if (!shgrp) {
+ float *color_p = &ma->r;
+ float *metal_p = &ma->ray_mirror;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->gloss_mir;
+
+ if (ma->use_nodes && ma->nodetree) {
+ struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma,
+ use_fibers, stl->effects->use_ao, stl->effects->use_bent_normals);
+
+ shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
+ if (shgrp) {
+ add_standard_uniforms(shgrp, sldata, vedata, NULL);
+
+ BLI_ghash_insert(material_hash, ma, shgrp);
+ }
+ else {
+ /* Shader failed : pink color */
+ static float col[3] = {1.0f, 0.0f, 1.0f};
+ static float half = 0.5f;
+
+ color_p = col;
+ metal_p = spec_p = rough_p = &half;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (shgrp == NULL) {
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, use_fibers,
+ false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr);
+ 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);
+ DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
+
+ BLI_ghash_insert(material_hash, ma, shgrp);
+ }
+ }
+
+ if (shgrp) {
+ DRW_shgroup_call_add(shgrp, hair_geom, mat);
+
+ if (use_fibers) {
+ DRW_hair_shader_uniforms(shgrp, scene,
+ fiber_texture, fiber_buffer);
+ }
+ }
+ }
+}
+
+static void material_hair(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, Object *ob, HairGroup *group)
+{
+ EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ GHash *material_hash = stl->g_data->hair_material_hash;
+ const HairEditSettings *tsettings = &scene->toolsettings->hair_edit;
+
+ float mat[4][4];
+ copy_m4_m4(mat, ob->obmat);
+
+ const DRWHairFiberTextureBuffer *fiber_buffer = NULL;
+ struct Gwn_Batch *hair_geom;
+ {
+ DerivedMesh *scalp = NULL;
+ if (ob->derivedFinal) {
+ scalp = ob->derivedFinal;
+ }
+ else {
+ EvaluationContext eval_ctx = {0};
+ DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_VIEWPORT);
+ scalp = mesh_get_derived_final(&eval_ctx, scene, ob, CD_MASK_BAREMESH);
+ }
+ hair_geom = DRW_cache_hair_get_fibers(group, tsettings->hair_draw_subdiv, scalp, &fiber_buffer);
+ }
+
+ if (!group->draw_texture_cache) {
+ group->draw_texture_cache = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height,
+ DRW_TEX_RG_32, 0, fiber_buffer->data);
+ }
+ GPUTexture **fiber_texture = (GPUTexture **)(&group->draw_texture_cache);
+
+ // TODO
+ Material *ma = NULL;/*give_current_material(ob, omat);*/
+ if (ma == NULL) {
+ ma = &defmaterial;
+ }
+
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat);
+ DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene,
+ fiber_texture, fiber_buffer);
+
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat);
+ DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene,
+ fiber_texture, fiber_buffer);
+
+ DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
+ if (!shgrp) {
+ float *color_p = &ma->r;
+ float *metal_p = &ma->ray_mirror;
+ float *spec_p = &ma->spec;
+ float *rough_p = &ma->gloss_mir;
+
+ if (ma->use_nodes && ma->nodetree) {
+ struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma,
+ true, stl->effects->use_ao, stl->effects->use_bent_normals);
+
+ shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
+ if (shgrp) {
+ add_standard_uniforms(shgrp, sldata, vedata, NULL);
+
+ BLI_ghash_insert(material_hash, ma, shgrp);
+ }
+ else {
+ /* Shader failed : pink color */
+ static float col[3] = {1.0f, 0.0f, 1.0f};
+ static float half = 0.5f;
+
+ color_p = col;
+ metal_p = spec_p = rough_p = &half;
+ }
+ }
+
+ /* Fallback to default shader */
+ if (shgrp == NULL) {
+ shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, true,
+ false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr);
+ 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);
+ DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
+
+ BLI_ghash_insert(material_hash, ma, shgrp);
+ }
+ }
+
+ if (shgrp) {
+ DRW_shgroup_call_add(shgrp, hair_geom, mat);
+
+ DRW_hair_shader_uniforms(shgrp, scene,
+ fiber_texture, fiber_buffer);
+ }
+}
+
void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
@@ -1132,116 +1349,15 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl
if (ob->type == OB_MESH) {
if (ob != draw_ctx->scene->obedit) {
- material_hash = stl->g_data->hair_material_hash;
-
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
-
- if (psys_check_enabled(ob, psys, false)) {
- ParticleSettings *part = psys->part;
- bool use_hair = false;
- bool use_fibers = false;
- float mat[4][4];
- struct Gwn_Batch *hair_geom = NULL;
- const DRWHairFiberTextureBuffer *fiber_buffer = NULL;
- GPUTexture **fiber_texture = NULL;
-
- if (ob->mode & OB_MODE_HAIR_EDIT) {
- BMEditStrands *edit = psys->hairedit;
- const HairEditSettings *tsettings = &scene->toolsettings->hair_edit;
- if (edit &&tsettings->hair_draw_mode == HAIR_DRAW_FIBERS && BKE_editstrands_hair_ensure(edit)) {
- use_hair = true;
- use_fibers = true;
- copy_m4_m4(mat, ob->obmat);
-
- hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer);
-
- if (!edit->texture) {
- edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height,
- DRW_TEX_RG_32, 0, fiber_buffer->data);
- }
- fiber_texture = (GPUTexture **)(&edit->texture);
- }
- }
- else {
- int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
- if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) {
- use_hair = true;
- unit_m4(mat);
- hair_geom = DRW_cache_particles_get_hair(psys, md);
- }
- }
-
- if (use_hair) {
- Material *ma = give_current_material(ob, part->omat);
- if (ma == NULL) {
- ma = &defmaterial;
- }
-
- if (!use_fibers) {
- DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat);
- DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat);
- }
- else {
- DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat);
- DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene,
- fiber_texture, fiber_buffer);
-
- DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat);
- DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene,
- fiber_texture, fiber_buffer);
- }
-
- DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma);
- if (!shgrp) {
- float *color_p = &ma->r;
- float *metal_p = &ma->ray_mirror;
- float *spec_p = &ma->spec;
- float *rough_p = &ma->gloss_mir;
-
- if (ma->use_nodes && ma->nodetree) {
- struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma,
- use_fibers, stl->effects->use_ao, stl->effects->use_bent_normals);
-
- shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass);
- if (shgrp) {
- add_standard_uniforms(shgrp, sldata, vedata, NULL);
-
- BLI_ghash_insert(material_hash, ma, shgrp);
- }
- else {
- /* Shader failed : pink color */
- static float col[3] = {1.0f, 0.0f, 1.0f};
- static float half = 0.5f;
-
- color_p = col;
- metal_p = spec_p = rough_p = &half;
- }
- }
-
- /* Fallback to default shader */
- if (shgrp == NULL) {
- shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, use_fibers,
- false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr);
- 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);
- DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
-
- BLI_ghash_insert(material_hash, ma, shgrp);
- }
- }
-
- if (shgrp) {
- DRW_shgroup_call_add(shgrp, hair_geom, mat);
-
- if (use_fibers) {
- DRW_hair_shader_uniforms(shgrp, scene,
- fiber_texture, fiber_buffer);
- }
- }
- }
+ material_particle_hair(sldata, vedata, ob, psys, md);
+ }
+ else if (md->type == eModifierType_Hair) {
+ HairModifierData *hmd = (HairModifierData *)md;
+ for (HairGroup *group = hmd->hair->groups.first; group; group = group->next) {
+ material_hair(sldata, vedata, ob, group);
}
}
}
diff --git a/source/blender/draw/engines/eevee/shaders/hair_lib.glsl b/source/blender/draw/engines/eevee/shaders/hair_lib.glsl
index 0611ea5d2d9..c6a4950839b 100644
--- a/source/blender/draw/engines/eevee/shaders/hair_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/hair_lib.glsl
@@ -147,10 +147,12 @@ void deform_fiber(DeformParams params,
#define FIBER_RIBBON
-uniform sampler2D strand_data;
+uniform sampler2D fiber_data;
+
+uniform int fiber_start;
uniform int strand_map_start;
uniform int strand_vertex_start;
-uniform int fiber_start;
+
uniform float ribbon_width;
uniform vec2 viewport_size;
@@ -159,7 +161,7 @@ uniform vec2 viewport_size;
vec2 read_texdata(int offset)
{
ivec2 offset2 = ivec2(offset % HAIR_SHADER_TEX_WIDTH, offset / HAIR_SHADER_TEX_WIDTH);
- return texelFetch(strand_data, offset2, 0).rg;
+ return texelFetch(fiber_data, offset2, 0).rg;
}
mat4 mat4_from_vectors(vec3 nor, vec3 tang, vec3 co)
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 7981b565089..9a4000cc0f2 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -2615,3 +2615,13 @@ Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool
{
return DRW_editstrands_batch_cache_get_hair_fibers(es, use_ribbons, subdiv, r_buffer);
}
+
+/* -------------------------------------------------------------------- */
+
+/** \name Hair */
+
+Gwn_Batch *DRW_cache_hair_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp,
+ const struct DRWHairFiberTextureBuffer **r_buffer)
+{
+ return DRW_hair_batch_cache_get_fibers(group, subdiv, scalp, r_buffer);
+}
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index c536bd81084..b6853c1fd3c 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -31,7 +31,9 @@ struct GPUMaterial;
struct Object;
struct ModifierData;
struct BMEditStrands;
+struct HairGroup;
struct DRWHairFiberTextureBuffer;
+struct DerivedMesh;
void DRW_shape_cache_free(void);
@@ -167,4 +169,8 @@ struct Gwn_Batch *DRW_cache_editstrands_get_wires(struct BMEditStrands *es);
struct Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv,
const struct DRWHairFiberTextureBuffer **r_buffer);
+/* Hair */
+struct Gwn_Batch *DRW_cache_hair_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp,
+ const struct DRWHairFiberTextureBuffer **r_buffer);
+
#endif /* __DRAW_CACHE_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index a6f4c486e2f..f026b7452df 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -33,7 +33,9 @@ struct CurveCache;
struct ParticleSystem;
struct ModifierData;
struct BMEditStrands;
+struct HairGroup;
struct DRWHairFiberTextureBuffer;
+struct DerivedMesh;
struct Curve;
struct Lattice;
@@ -52,6 +54,9 @@ void DRW_lattice_batch_cache_free(struct Lattice *lt);
void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode);
void DRW_particle_batch_cache_free(struct ParticleSystem *psys);
+void DRW_hair_batch_cache_dirty(struct HairGroup *group, int mode);
+void DRW_hair_batch_cache_free(struct HairGroup *group);
+
void DRW_editstrands_batch_cache_dirty(struct BMEditStrands *es, int mode);
void DRW_editstrands_batch_cache_free(struct BMEditStrands *es);
@@ -115,4 +120,8 @@ struct Gwn_Batch *DRW_editstrands_batch_cache_get_points(struct BMEditStrands *e
struct Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv,
const struct DRWHairFiberTextureBuffer **r_buffer);
+/* Hair */
+struct Gwn_Batch *DRW_hair_batch_cache_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp,
+ const struct DRWHairFiberTextureBuffer **r_buffer);
+
#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
new file mode 100644
index 00000000000..94a22a610e1
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_hair.c
@@ -0,0 +1,310 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_strands.c
+ * \ingroup draw
+ *
+ * \brief Strands API for render engines
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_ghash.h"
+
+#include "DNA_hair_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_hair.h"
+
+#include "GPU_batch.h"
+#include "GPU_extensions.h"
+#include "GPU_texture.h"
+
+#include "draw_common.h"
+#include "draw_cache_impl.h" /* own include */
+#include "DRW_render.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
+
+/* ---------------------------------------------------------------------- */
+/* Hair Gwn_Batch Cache */
+
+typedef struct HairBatchCache {
+ Gwn_VertBuf *verts;
+ Gwn_IndexBuf *segments;
+
+ Gwn_Batch *fibers;
+
+ DRWHairFiberTextureBuffer texbuffer;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+} HairBatchCache;
+
+/* Gwn_Batch cache management. */
+
+static void hair_batch_cache_clear(HairGroup *group);
+
+static bool hair_batch_cache_valid(HairGroup *group)
+{
+ HairBatchCache *cache = group->draw_batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (cache->is_dirty) {
+ return false;
+ }
+
+ return true;
+}
+
+static void hair_batch_cache_init(HairGroup *group)
+{
+ HairBatchCache *cache = group->draw_batch_cache;
+
+ if (!cache) {
+ cache = group->draw_batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->is_dirty = false;
+}
+
+static HairBatchCache *hair_batch_cache_get(HairGroup *group)
+{
+ if (!hair_batch_cache_valid(group)) {
+ hair_batch_cache_clear(group);
+ hair_batch_cache_init(group);
+ }
+ return group->draw_batch_cache;
+}
+
+void DRW_hair_batch_cache_dirty(HairGroup *group, int mode)
+{
+ HairBatchCache *cache = group->draw_batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_HAIR_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void hair_batch_cache_clear(HairGroup *group)
+{
+ HairBatchCache *cache = group->draw_batch_cache;
+
+ if (group->draw_texture_cache) {
+ GPU_texture_free(group->draw_texture_cache);
+ group->draw_texture_cache = NULL;
+ }
+
+ if (cache) {
+ GWN_BATCH_DISCARD_SAFE(cache->fibers);
+ GWN_VERTBUF_DISCARD_SAFE(cache->verts);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->segments);
+
+ {
+ 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;
+ }
+ }
+}
+
+void DRW_hair_batch_cache_free(HairGroup *group)
+{
+ hair_batch_cache_clear(group);
+ MEM_SAFE_FREE(group->draw_batch_cache);
+}
+
+static void hair_batch_cache_ensure_fibers(HairGroup *group, HairBatchCache *cache, int subdiv)
+{
+ TIMEIT_START(hair_batch_cache_ensure_fibers);
+
+ GWN_VERTBUF_DISCARD_SAFE(cache->verts);
+ GWN_INDEXBUF_DISCARD_SAFE(cache->segments);
+
+ const int totfibers = group->num_follicles;
+ int *fiber_lengths = BKE_hair_group_get_fiber_lengths(group, subdiv);
+ int totpoint = 0;
+ for (int i = 0; i < totfibers; ++i) {
+ totpoint += fiber_lengths[i];
+ }
+ const int totseg = totpoint - totfibers;
+
+ static Gwn_VertFormat format = { 0 };
+ static unsigned curve_param_id, fiber_index_id;
+
+ /* initialize vertex format */
+ if (format.attrib_ct == 0) {
+ fiber_index_id = GWN_vertformat_attr_add(&format, "fiber_index", GWN_COMP_I32, 1, GWN_FETCH_INT);
+ curve_param_id = GWN_vertformat_attr_add(&format, "curve_param", GWN_COMP_F32, 1, GWN_FETCH_FLOAT);
+ }
+
+ cache->verts = GWN_vertbuf_create_with_format(&format);
+
+ 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->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 = fiber_lengths[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->verts, fiber_index_id, vi, &i);
+ GWN_vertbuf_attr_set(cache->verts, curve_param_id, vi, &a);
+ GWN_vertbuf_attr_set(cache->verts, fiber_index_id, vi+1, &i);
+ GWN_vertbuf_attr_set(cache->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);
+ }
+
+ 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);
+
+ MEM_freeN(fiber_lengths);
+
+ TIMEIT_BENCH(cache->segments = GWN_indexbuf_build(&elb), indexbuf_build);
+
+ TIMEIT_END(hair_batch_cache_ensure_fibers);
+}
+
+static void hair_batch_cache_ensure_texbuffer(HairGroup *group, HairBatchCache *cache, int subdiv, struct DerivedMesh *scalp)
+{
+ 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_group_get_texture_buffer_size(group, subdiv, &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_group_get_texture_buffer(group, subdiv, scalp, 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;
+}
+
+Gwn_Batch *DRW_hair_batch_cache_get_fibers(HairGroup *group, int subdiv, struct DerivedMesh *scalp,
+ const DRWHairFiberTextureBuffer **r_buffer)
+{
+ HairBatchCache *cache = hair_batch_cache_get(group);
+
+ TIMEIT_START(DRW_hair_batch_cache_get_fibers);
+
+ if (cache->fibers == NULL) {
+ TIMEIT_BENCH(hair_batch_cache_ensure_fibers(group, cache, subdiv),
+ hair_batch_cache_ensure_fibers);
+
+ TIMEIT_BENCH(cache->fibers = GWN_batch_create(GWN_PRIM_TRIS, cache->verts, cache->segments),
+ GWN_batch_create);
+
+ TIMEIT_BENCH(hair_batch_cache_ensure_texbuffer(group, cache, subdiv, scalp),
+ hair_batch_cache_ensure_texbuffer);
+ }
+
+ if (r_buffer) {
+ *r_buffer = &cache->texbuffer;
+ }
+
+ TIMEIT_END(DRW_hair_batch_cache_get_fibers);
+
+ return cache->fibers;
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_strands.c b/source/blender/draw/intern/draw_cache_impl_strands.c
index fc87e765001..fdf401c3641 100644
--- a/source/blender/draw/intern/draw_cache_impl_strands.c
+++ b/source/blender/draw/intern/draw_cache_impl_strands.c
@@ -35,6 +35,7 @@
#include "BLI_math_vector.h"
#include "BLI_ghash.h"
+#include "DNA_hair_types.h"
#include "DNA_scene_types.h"
#include "BKE_editstrands.h"
@@ -390,12 +391,13 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand
GWN_VERTBUF_DISCARD_SAFE(cache->hair.verts);
GWN_INDEXBUF_DISCARD_SAFE(cache->hair.segments);
+ const int totfibers = es->hair_group->num_follicles;
int *fiber_lengths = BKE_editstrands_hair_get_fiber_lengths(es, subdiv);
int totpoint = 0;
- for (int i = 0; i < es->hair_totfibers; ++i) {
+ for (int i = 0; i < totfibers; ++i) {
totpoint += fiber_lengths[i];
}
- const int totseg = totpoint - es->hair_totfibers;
+ const int totseg = totpoint - totfibers;
static Gwn_VertFormat format = { 0 };
static unsigned curve_param_id, fiber_index_id;
@@ -433,7 +435,7 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand
TIMEIT_BLOCK_INIT(GWN_vertbuf_attr_set);
TIMEIT_BLOCK_INIT(GWN_indexbuf_add_tri_verts);
int vi = 0;
- for (int i = 0; i < es->hair_totfibers; ++i) {
+ for (int i = 0; i < totfibers; ++i) {
const int fiblen = fiber_lengths[i];
const float da = fiblen > 1 ? 1.0f / (fiblen-1) : 0.0f;
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 0a357518381..f4e5f211efe 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -52,7 +52,7 @@ void DRW_hair_shader_uniforms(DRWShadingGroup *shgrp, Scene *scene,
DRW_shgroup_uniform_vec2(shgrp, "viewport_size", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_float(shgrp, "ribbon_width", &tsettings->hair_draw_size, 1);
- DRW_shgroup_uniform_buffer(shgrp, "strand_data", fibertex);
+ DRW_shgroup_uniform_buffer(shgrp, "fiber_data", fibertex);
DRW_shgroup_uniform_int(shgrp, "strand_map_start", &texbuffer->strand_map_start, 1);
DRW_shgroup_uniform_int(shgrp, "strand_vertex_start", &texbuffer->strand_vertex_start, 1);
DRW_shgroup_uniform_int(shgrp, "fiber_start", &texbuffer->fiber_start, 1);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index df08053c0b5..40f136a07f0 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -3614,6 +3614,9 @@ void DRW_engines_register(void)
/* BKE: editstrands.c */
extern void *BKE_editstrands_batch_cache_dirty_cb;
extern void *BKE_editstrands_batch_cache_free_cb;
+ /* BKE: hair.c */
+ extern void *BKE_hair_batch_cache_dirty_cb;
+ extern void *BKE_hair_batch_cache_free_cb;
BKE_curve_batch_cache_dirty_cb = DRW_curve_batch_cache_dirty;
BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free;
@@ -3629,6 +3632,9 @@ void DRW_engines_register(void)
BKE_editstrands_batch_cache_dirty_cb = DRW_editstrands_batch_cache_dirty;
BKE_editstrands_batch_cache_free_cb = DRW_editstrands_batch_cache_free;
+
+ BKE_hair_batch_cache_dirty_cb = DRW_hair_batch_cache_dirty;
+ BKE_hair_batch_cache_free_cb = DRW_hair_batch_cache_free;
}
}