diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_materials.c')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 334 |
1 files changed, 248 insertions, 86 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index fc4439a253c..d146fda5373 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -31,6 +31,8 @@ #include "BLI_rand.h" #include "BLI_string_utils.h" +#include "BKE_DerivedMesh.h" +#include "BKE_groom.h" #include "BKE_particle.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -38,8 +40,11 @@ #include "DNA_world_types.h" #include "DNA_modifier_types.h" #include "DNA_view3d_types.h" +#include "DNA_groom_types.h" +#include "DNA_hair_types.h" #include "GPU_material.h" +#include "GPU_texture.h" #include "eevee_engine.h" #include "eevee_lut.h" @@ -53,6 +58,8 @@ 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_lit[VAR_MAT_MAX]; struct GPUShader *default_background; struct GPUShader *update_noise_sh; @@ -99,6 +106,7 @@ extern char datatoc_volumetric_vert_glsl[]; extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_hair_lib_glsl[]; extern Material defmaterial; extern GlobalsUboStorage ts; @@ -280,6 +288,9 @@ 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"); } @@ -411,15 +422,20 @@ static void add_standard_uniforms( static void create_default_shader(int options) { + char *vert_str = BLI_string_joinN( + datatoc_hair_lib_glsl, + datatoc_lit_surface_vert_glsl); + char *frag_str = BLI_string_joinN( e_data.frag_shader_lib, datatoc_default_frag_glsl); char *defines = eevee_get_defines(options); - e_data.default_lit[options] = DRW_shader_create(datatoc_lit_surface_vert_glsl, NULL, frag_str, defines); + e_data.default_lit[options] = DRW_shader_create(vert_str, NULL, frag_str, defines); MEM_freeN(defines); + MEM_freeN(vert_str); MEM_freeN(frag_str); } @@ -529,8 +545,6 @@ static void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { if (!e_data.frag_shader_lib) { - char *frag_str = NULL; - /* Shaders */ e_data.shadow_shader_lib = BLI_string_joinN( datatoc_common_uniforms_lib_glsl, @@ -555,7 +569,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.frag_shader_lib = BLI_string_joinN( datatoc_common_view_lib_glsl, e_data.shadow_shader_lib); @@ -574,7 +588,11 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_volumetric_lib_glsl, datatoc_volumetric_frag_glsl); - frag_str = BLI_string_joinN( + char *hair_fiber_vert_str = BLI_string_joinN( + datatoc_hair_lib_glsl, + datatoc_prepass_vert_glsl); + + char *frag_str = BLI_string_joinN( e_data.frag_shader_lib, datatoc_default_frag_glsl); @@ -590,7 +608,19 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); + 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(frag_str); + MEM_freeN(hair_fiber_vert_str); e_data.update_noise_sh = DRW_shader_create_fullscreen( datatoc_update_noise_frag_glsl, NULL); @@ -779,25 +809,36 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( } struct GPUMaterial *EEVEE_material_hair_get( - struct Scene *scene, Material *ma, int shadow_method) + struct Scene *scene, Material *ma, int shadow_method, bool use_fibers) { const void *engine = &DRW_engine_viewport_eevee_type; - int options = VAR_MAT_MESH | VAR_MAT_HAIR; - + int options = VAR_MAT_HAIR | VAR_MAT_MESH; options |= eevee_material_shadow_option(shadow_method); - + if (use_fibers) { + options |= VAR_MAT_HAIR_FIBERS; + } GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options); if (mat) { return mat; } + char *vert_str = NULL; + { + DynStr *ds_vert = BLI_dynstr_new(); + BLI_dynstr_append(ds_vert, datatoc_hair_lib_glsl); + BLI_dynstr_append(ds_vert, datatoc_lit_surface_vert_glsl); + vert_str = BLI_dynstr_get_cstring(ds_vert); + BLI_dynstr_free(ds_vert); + } + char *defines = eevee_get_defines(options); mat = DRW_shader_create_from_material( scene, ma, engine, options, - datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib, + vert_str, NULL, e_data.frag_shader_lib, defines); + MEM_freeN(vert_str); MEM_freeN(defines); return mat; @@ -808,7 +849,7 @@ struct GPUMaterial *EEVEE_material_hair_get( **/ static struct DRWShadingGroup *EEVEE_default_shading_group_create( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWPass *pass, - bool is_hair, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) + bool is_hair, bool is_hair_fibers, bool is_flat_normal, bool use_blend, bool use_ssr, int shadow_method) { EEVEE_EffectsInfo *effects = vedata->stl->effects; static int ssr_id; @@ -816,6 +857,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( int options = VAR_MAT_MESH; if (is_hair) options |= VAR_MAT_HAIR; + if (is_hair_fibers) options |= VAR_MAT_HAIR_FIBERS; 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; @@ -837,13 +879,14 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_create( **/ static struct DRWShadingGroup *EEVEE_default_shading_group_get( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, - bool is_hair, bool is_flat_normal, bool use_ssr, int shadow_method) + bool is_hair, bool is_hair_fibers, 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; if (is_hair) options |= VAR_MAT_HAIR; + if (is_hair_fibers) options |= VAR_MAT_HAIR_FIBERS; if (is_flat_normal) options |= VAR_MAT_FLAT; options |= eevee_material_shadow_option(shadow_method); @@ -853,7 +896,8 @@ 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 | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); @@ -928,20 +972,26 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE; psl->depth_pass = DRW_pass_create("Depth Pass", state); stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass); + stl->g_data->hair_fibers_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_hair_fiber_sh, psl->depth_pass); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK; psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", state); stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass_cull); + stl->g_data->hair_fibers_depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_hair_fiber_sh, psl->depth_pass_cull); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; psl->depth_pass_clip = DRW_pass_create("Depth Pass Clip", state); stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip); + stl->g_data->hair_fibers_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_hair_fiber_clip_sh, psl->depth_pass_clip); DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip, "clip_block", sldata->clip_ubo); + DRW_shgroup_uniform_block(stl->g_data->hair_fibers_depth_shgrp_clip, "clip_block", sldata->clip_ubo); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK; psl->depth_pass_clip_cull = DRW_pass_create("Depth Pass Cull Clip", state); stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip_cull); + stl->g_data->hair_fibers_depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_hair_fiber_clip_sh, psl->depth_pass_clip_cull); DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); + DRW_shgroup_uniform_block(stl->g_data->hair_fibers_depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); } { @@ -1159,7 +1209,7 @@ static void material_opaque( /* Fallback to default shader */ if (*shgrp == NULL) { bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0); - *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, use_flat_nor, use_ssr, linfo->shadow_method); + *shgrp = EEVEE_default_shading_group_get(sldata, vedata, false, 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); @@ -1241,7 +1291,7 @@ static void material_transparent( if (*shgrp == NULL) { *shgrp = EEVEE_default_shading_group_create( sldata, vedata, psl->transparent_pass, - false, use_flat_nor, true, false, linfo->shadow_method); + false, 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); @@ -1289,6 +1339,178 @@ static void material_transparent( } } +static void material_particle_hair( + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + 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; + float mat[4][4]; + unit_m4(mat); + + bool use_hair = false; + struct Gwn_Batch *hair_geom = NULL; + { + 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; + 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; + } + + 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); + + 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, false, sldata->lamps->shadow_method); + + shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); + if (shgrp) { + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); + + 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 = ½ + } + } + + /* Fallback to default shader */ + if (shgrp == NULL) { + bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, false, 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); + 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); + } + } +} + +static void material_hair( + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata, + Object *ob, + HairSystem *hsys, + DerivedMesh *scalp) +{ + 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; + /* TODO */ + const int subdiv = 0; + float mat[4][4]; + copy_m4_m4(mat, ob->obmat); + + const DRWHairFiberTextureBuffer *fiber_buffer = NULL; + struct Gwn_Batch *hair_geom = DRW_cache_hair_get_fibers(hsys, scalp, subdiv, &fiber_buffer); + + if (!hsys->draw_texture_cache) { + hsys->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 **)(&hsys->draw_texture_cache); + + Material *ma = give_current_material(ob, hsys->material_index); + if (ma == NULL) { + ma = &defmaterial; + } + + DRW_shgroup_call_add(stl->g_data->hair_fibers_depth_shgrp, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->hair_fibers_depth_shgrp, scene, + fiber_texture, fiber_buffer); + + DRW_shgroup_call_add(stl->g_data->hair_fibers_depth_shgrp_clip, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->hair_fibers_depth_shgrp_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, sldata->lamps->shadow_method, true); + + shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); + if (shgrp) { + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); + 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 = ½ + } + } + + /* Fallback to default shader */ + if (shgrp == NULL) { + bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, 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); + 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_ViewLayerData *sldata, Object *ob) { EEVEE_PassList *psl = vedata->psl; @@ -1437,84 +1659,22 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld if (ob->type == OB_MESH) { if (ob != draw_ctx->object_edit) { - 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; - 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)) { - struct Gwn_Batch *hair_geom = DRW_cache_particles_get_hair(psys, md); - DRWShadingGroup *shgrp = NULL; - Material *ma = give_current_material(ob, part->omat); - static float mat[4][4]; - - unit_m4(mat); - - if (ma == NULL) { - ma = &defmaterial; - } - - float *color_p = &ma->r; - float *metal_p = &ma->ray_mirror; - float *spec_p = &ma->spec; - float *rough_p = &ma->gloss_mir; - - 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); - - shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); - - if (shgrp) { - DRW_shgroup_call_add(shgrp, hair_geom, mat); - } - else { - if (ma->use_nodes && ma->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, sldata->lamps->shadow_method); - - shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); - if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); - - BLI_ghash_insert(material_hash, ma, shgrp); - - DRW_shgroup_call_add(shgrp, hair_geom, mat); - } - 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 = ½ - } - } - - /* Fallback to default shader */ - if (shgrp == NULL) { - bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0); - shgrp = EEVEE_default_shading_group_get(sldata, vedata, 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); - 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); - - DRW_shgroup_call_add(shgrp, hair_geom, mat); - } - } - } - } + material_particle_hair(vedata, sldata, ob, psys, md); + } + else if (md->type == eModifierType_Fur) { + FurModifierData *fmd = (FurModifierData *)md; + material_hair(vedata, sldata, ob, fmd->hair_system, ob->derivedFinal); } } } } + else if (ob->type == OB_GROOM) { + Groom *groom = ob->data; + material_hair(vedata, sldata, ob, groom->hair_system, BKE_groom_get_scalp(groom)); + } } void EEVEE_materials_cache_finish(EEVEE_Data *vedata) @@ -1535,6 +1695,8 @@ void EEVEE_materials_free(void) MEM_SAFE_FREE(e_data.volume_shader_lib); 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.update_noise_sh); DRW_TEXTURE_FREE_SAFE(e_data.util_tex); |