diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-05-29 13:25:43 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-05-30 13:25:20 +0300 |
commit | 10f6450ef24ca1e99b3454c76117d877f35541fe (patch) | |
tree | e51aed473eb7bf398cab55abf47a889c087c17e4 /source | |
parent | 501c0b1df8c2db9806481d4e4c4c59008389b426 (diff) |
Eevee: Add support for new Hair geometry system.
This now can shade actual poly strips that mimics cylinders.
This makes hair coverage exact compared to the line method and result in
smoother fading hair.
This does make the sampling a bit more exact but needs more samples to
converge properly.
Diffstat (limited to 'source')
6 files changed, 187 insertions, 80 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 1e43a244f04..dfeb91637ea 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -190,6 +190,10 @@ static void eevee_draw_background(void *vedata) /* Default framebuffer and texture */ DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + /* Refresh Hair */ + DRW_draw_pass(psl->hair_tf_pass); + /* Sort transparents before the loop. */ DRW_pass_sort_shgroup_z(psl->transparent_pass); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 32bd6f23d84..85c312d311c 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -49,10 +49,13 @@ /* *********** STATIC *********** */ static struct { char *frag_shader_lib; + char *vert_shader_str; char *volume_shader_lib; struct GPUShader *default_prepass_sh; struct GPUShader *default_prepass_clip_sh; + struct GPUShader *default_hair_prepass_sh; + struct GPUShader *default_hair_prepass_clip_sh; struct GPUShader *default_lit[VAR_MAT_MAX]; struct GPUShader *default_background; struct GPUShader *default_studiolight_background; @@ -83,6 +86,7 @@ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_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_view_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; @@ -100,6 +104,8 @@ extern char datatoc_volumetric_geom_glsl[]; extern char datatoc_volumetric_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; + extern Material defmaterial; extern GlobalsUboStorage ts; @@ -421,7 +427,7 @@ static void create_default_shader(int options) 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(e_data.vert_shader_str, NULL, frag_str, defines); MEM_freeN(defines); MEM_freeN(frag_str); @@ -533,8 +539,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.frag_shader_lib = BLI_string_joinN( datatoc_common_view_lib_glsl, @@ -575,9 +579,10 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_volumetric_lib_glsl, datatoc_volumetric_frag_glsl); - frag_str = BLI_string_joinN( - e_data.frag_shader_lib, - datatoc_default_frag_glsl); + e_data.vert_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_common_hair_lib_glsl, + datatoc_lit_surface_vert_glsl); e_data.default_background = DRW_shader_create( datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, @@ -595,7 +600,21 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_prepass_vert_glsl, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n"); - MEM_freeN(frag_str); + char *vert_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_common_hair_lib_glsl, + datatoc_prepass_vert_glsl); + + e_data.default_hair_prepass_sh = DRW_shader_create( + vert_str, NULL, datatoc_prepass_frag_glsl, + "#define HAIR_SHADER\n"); + + e_data.default_hair_prepass_clip_sh = DRW_shader_create( + vert_str, NULL, datatoc_prepass_frag_glsl, + "#define HAIR_SHADER\n" + "#define CLIP_PLANES\n"); + + MEM_freeN(vert_str); e_data.update_noise_sh = DRW_shader_create_fullscreen( datatoc_update_noise_frag_glsl, NULL); @@ -712,7 +731,7 @@ struct GPUMaterial *EEVEE_material_mesh_get( mat = DRW_shader_create_from_material( scene, ma, engine, options, - datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib, + e_data.vert_shader_str, NULL, e_data.frag_shader_lib, defines); MEM_freeN(defines); @@ -772,7 +791,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( mat = DRW_shader_create_from_material( scene, ma, engine, options, - (is_shadow) ? datatoc_shadow_vert_glsl : datatoc_lit_surface_vert_glsl, + (is_shadow) ? datatoc_shadow_vert_glsl : e_data.vert_shader_str, NULL, frag_str, defines); @@ -800,7 +819,7 @@ struct GPUMaterial *EEVEE_material_hair_get( mat = DRW_shader_create_from_material( scene, ma, engine, options, - datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib, + e_data.vert_shader_str, NULL, e_data.frag_shader_lib, defines); MEM_freeN(defines); @@ -842,12 +861,15 @@ 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, 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(!is_hair || (ob && psys && md)); + if (is_hair) options |= VAR_MAT_HAIR; if (is_flat_normal) options |= VAR_MAT_FLAT; @@ -861,13 +883,25 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( 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); - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); /* 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. */ - add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); + * But it's currently OK because the following shgroups does not add any bind. + * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */ + 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); + } } - return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); + if (is_hair) { + DRWShadingGroup *shgrp = DRW_shgroup_hair_create(ob, psys, md, + vedata->psl->default_pass[options], vedata->psl->hair_tf_pass, + e_data.default_lit[options]); + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); + return shgrp; + } + else { + return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); + } } /** @@ -984,7 +1018,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } { - 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_LESS_EQUAL | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; psl->material_pass = DRW_pass_create("Material Shader Pass", state); } @@ -1039,6 +1073,9 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } + { + psl->hair_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_TRANS_FEEDBACK); + } } #define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) do { \ @@ -1216,7 +1253,9 @@ 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, + 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); @@ -1557,7 +1596,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld if (draw_as != PART_DRAW_PATH) { continue; } - struct Gwn_Batch *hair_geom = DRW_cache_particles_get_hair(ob, psys, md); + DRWShadingGroup *shgrp = NULL; Material *ma = give_current_material(ob, part->omat); @@ -1570,56 +1609,60 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld float *spec_p = &ma->spec; float *rough_p = &ma->gloss_mir; - DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, NULL); - DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, NULL); - - shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); - - if (shgrp) { - DRW_shgroup_call_add(shgrp, hair_geom, NULL); - } - else { - if (ma->use_nodes && ma->nodetree) { - 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); - - switch (GPU_material_status(gpumat)) { - case GPU_MAT_SUCCESS: - { - shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); - add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); - break; - } - case GPU_MAT_QUEUED: - { - sldata->probes->all_materials_updated = false; - color_p = compile_col; - metal_p = spec_p = rough_p = ½ - break; - } - case GPU_MAT_FAILED: - default: - color_p = error_col; - metal_p = spec_p = rough_p = ½ - break; + shgrp = DRW_shgroup_hair_create( + ob, psys, md, + psl->depth_pass, psl->hair_tf_pass, + e_data.default_hair_prepass_sh); + + shgrp = DRW_shgroup_hair_create( + ob, psys, md, + psl->depth_pass_clip, psl->hair_tf_pass, + e_data.default_hair_prepass_clip_sh); + DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo); + + shgrp = NULL; + if (ma->use_nodes && ma->nodetree) { + 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); + + switch (GPU_material_status(gpumat)) { + case GPU_MAT_SUCCESS: + { + shgrp = DRW_shgroup_material_hair_create( + ob, psys, md, + psl->material_pass, psl->hair_tf_pass, + gpumat); + add_standard_uniforms(shgrp, sldata, vedata, NULL, NULL, false, false); + break; } + case GPU_MAT_QUEUED: + { + sldata->probes->all_materials_updated = false; + color_p = compile_col; + metal_p = spec_p = rough_p = ½ + break; + } + case GPU_MAT_FAILED: + default: + color_p = error_col; + metal_p = spec_p = rough_p = ½ + break; } + } - /* 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); - } - - DRW_shgroup_call_add(shgrp, hair_geom, NULL); - BLI_ghash_insert(material_hash, ma, shgrp); + /* 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, + ob, psys, md, + 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); } } } @@ -1679,8 +1722,10 @@ void EEVEE_materials_free(void) DRW_SHADER_FREE_SAFE(e_data.default_lit[i]); } MEM_SAFE_FREE(e_data.frag_shader_lib); - MEM_SAFE_FREE(e_data.frag_shader_lib); + MEM_SAFE_FREE(e_data.vert_shader_str); MEM_SAFE_FREE(e_data.volume_shader_lib); + DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh); + 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_background); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 6b2e2ebfdcb..8aca79255b0 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -212,6 +212,7 @@ typedef struct EEVEE_PassList { struct DRWPass *background_pass; struct DRWPass *update_noise_pass; struct DRWPass *lookdev_pass; + struct DRWPass *hair_tf_pass; } EEVEE_PassList; typedef struct EEVEE_FramebufferList { diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 737a2977146..accecaacbde 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -21,6 +21,15 @@ in vec3 worldNormal; in vec3 viewNormal; #endif +#ifdef HAIR_SHADER +in vec3 hairTangent; /* world space */ +in float hairThickTime; +in float hairThickness; +in float hairTime; + +uniform int hairThicknessRes = 1; +#endif + #endif /* LIT_SURFACE_UNIFORM */ /** AUTO CONFIG @@ -169,21 +178,30 @@ void CLOSURE_NAME( vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0); #ifdef HAIR_SHADER - /* Random normal distribution on the hair surface. */ - vec3 T = normalize(worldNormal); /* meh, TODO fix worldNormal misnaming. */ - vec3 B = normalize(cross(V, T)); - N = cross(T, B); /* Normal facing view */ - /* We want a cosine distribution. */ - float cos_theta = rand.x * 2.0 - 1.0; - float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta));; - N = N * sin_theta + B * cos_theta; + if (hairThicknessRes == 1) { + /* Random normal distribution on the hair surface. */ + vec3 T = normalize(worldNormal); /* meh, TODO fix worldNormal misnaming. */ + vec3 B = normalize(cross(V, T)); + N = cross(T, B); /* Normal facing view */ + /* We want a cosine distribution. */ + float cos_theta = rand.x * 2.0 - 1.0; + float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta));; + N = N * sin_theta + B * cos_theta; # ifdef CLOSURE_GLOSSY - /* Hair random normal does not work with SSR :(. - * It just create self reflection feedback (which is beautifful btw) - * but not correct. */ - ssr_id = NO_SSR; /* Force bypass */ + /* Hair random normal does not work with SSR :(. + * It just create self reflection feedback (which is beautifful btw) + * but not correct. */ + ssr_id = NO_SSR; /* Force bypass */ # endif + } + else { + vec3 T = normalize(cross(hairTangent, worldNormal)); + /* We want a cosine distribution. */ + float cos_theta = hairThickTime / hairThickness; + float sin_theta = sqrt(max(0.0, 1.0f - cos_theta*cos_theta));; + N = normalize(hairTangent * cos_theta + T * sin_theta); + } #endif /* ---------------------------------------------------------------- */ 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 06b073afd8a..9dffe1ec33b 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -8,8 +8,10 @@ uniform mat3 NormalMatrix; uniform mat4 ModelMatrixInverse; #endif +#ifndef HAIR_SHADER in vec3 pos; in vec3 nor; +#endif out vec3 worldPosition; out vec3 viewPosition; @@ -28,12 +30,34 @@ out vec3 worldNormal; out vec3 viewNormal; #endif -void main() { +#ifdef HAIR_SHADER +out vec3 hairTangent; +out float hairThickTime; +out float hairThickness; +out float hairTime; +#endif + +void main() +{ +#ifdef HAIR_SHADER + vec3 pos, nor; + hair_get_pos_tan_nor_time( + (ProjectionMatrix[3][3] == 0.0), + ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, + pos, nor, hairTangent, hairTime, hairThickness, hairThickTime); + + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + viewPosition = (ModelMatrixInverse * vec4(pos, 1.0)).xyz; + worldPosition = pos; + worldNormal = nor; + viewNormal = normalize(mat3(ViewMatrixInverse) * nor); +#else gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz; worldPosition = (ModelMatrix * vec4(pos, 1.0)).xyz; - viewNormal = normalize(NormalMatrix * nor); worldNormal = normalize(WorldNormalMatrix * nor); + viewNormal = normalize(NormalMatrix * nor); +#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 c756e061d70..1ed4f5f6500 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl @@ -7,13 +7,28 @@ layout(std140) uniform clip_block { vec4 ClipPlanes[1]; }; +#ifndef HAIR_SHADER in vec3 pos; +#endif void main() { +#ifdef HAIR_SHADER + float time, thick_time, thickness; + vec3 pos, nor, binor; + hair_get_pos_tan_nor_time( + (ProjectionMatrix[3][3] == 0.0), + ViewMatrixInverse[3].xyz, ViewMatrixInverse[2].xyz, + pos, nor, binor, time, thickness, thick_time); + + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); + vec4 worldPosition = vec4(pos, 1.0); +#else gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); -#ifdef CLIP_PLANES vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0)); +#endif + +#ifdef CLIP_PLANES gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), ClipPlanes[0]); #endif /* TODO motion vectors */ |