diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-06-03 13:13:19 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-06-03 13:36:03 +0300 |
commit | 32c5972653041a3423122b5a5ae791ef536b87ed (patch) | |
tree | 281dd3678d964369d9f87ebee300630a3c585d32 /source/blender/draw | |
parent | 38bf3b8d23041c547186fee5633782384c8ab384 (diff) |
Workbench: Rework hair support.
Now hairs are shaded properly in workbench and support texturing.
I also added a 10% random normal direction per hair to have a bit more
variation in the shading. This is hardcoded for now.
Diffstat (limited to 'source/blender/draw')
8 files changed, 266 insertions, 84 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl index 269911189fa..5f37490603d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl @@ -47,7 +47,7 @@ void main() #ifdef NORMAL_VIEWPORT_PASS_ENABLED #ifdef WORKBENCH_ENCODE_NORMALS vec3 normal_viewport = normal_decode(texelFetch(normalBuffer, texel, 0).rg); - if (diffuse_color.a == 1.0) { + if (diffuse_color.a == 0.0) { normal_viewport = -normal_viewport; } #else /* WORKBENCH_ENCODE_NORMALS */ @@ -81,9 +81,13 @@ void main() #endif /* V3D_LIGHTING_STUDIO */ #ifdef V3D_SHADING_SHADOW - float shadow_mix = step(-shadowShift, dot(normal_viewport, world_data.light_direction_vs.xyz)); - float light_multiplier; - light_multiplier = mix(lightMultiplier, shadowMultiplier, shadow_mix); + float light_factor = -dot(normal_viewport, world_data.light_direction_vs.xyz); + /* The step function might be ok for meshes but it's + * clearly not the case for hairs. Do smoothstep in this case. */ + float shadow_mix = (diffuse_color.a == 1.0 || diffuse_color.a == 0.0) + ? step(-shadowShift, -light_factor) + : smoothstep(1.0, shadowShift, light_factor); + float light_multiplier = mix(lightMultiplier, shadowMultiplier, shadow_mix); #else /* V3D_SHADING_SHADOW */ float light_multiplier = 1.0; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl index 3f271ec439b..a9c84e11aa6 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -39,20 +39,17 @@ void main() #endif #ifdef V3D_LIGHTING_STUDIO -#ifdef STUDIOLIGHT_ORIENTATION_CAMERA +# ifdef STUDIOLIGHT_ORIENTATION_CAMERA vec3 diffuse_light = get_camera_diffuse_light(world_data, normal_viewport); -#endif -#ifdef STUDIOLIGHT_ORIENTATION_WORLD +# endif +# ifdef STUDIOLIGHT_ORIENTATION_WORLD vec3 normal_world = normalWorldMatrix * normal_viewport; vec3 diffuse_light = get_world_diffuse_light(world_data, normal_world); -#endif - +# endif vec3 shaded_color = diffuse_light * diffuse_color.rgb + specular_color; - -#else /* V3D_LIGHTING_STUDIO */ +#else vec3 shaded_color = diffuse_color.rgb + specular_color; - -#endif /* V3D_LIGHTING_STUDIO */ +#endif vec4 premultiplied = vec4(shaded_color.rgb * alpha, alpha); transparentAccum = calculate_transparent_accum(premultiplied); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index c0f58271a8c..bc7741f853c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -9,12 +9,17 @@ uniform sampler2D image; #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED +in vec3 position_viewport; in vec3 normal_viewport; #endif /* NORMAL_VIEWPORT_PASS_ENABLED */ #ifdef OB_TEXTURE in vec2 uv_interp; #endif /* OB_TEXTURE */ +#ifdef HAIR_SHADER +flat in float hair_rand; +#endif + layout(location=0) out uint objectId; layout(location=1) out vec4 diffuseColor; layout(location=2) out vec4 specularColor; @@ -35,23 +40,29 @@ void main() #ifdef OB_TEXTURE diffuseColor = texture(image, uv_interp); #endif /* OB_TEXTURE */ +#ifdef HAIR_SHADER + float hair_color_variation = hair_rand * 0.1; + diffuseColor.rgb = clamp(diffuseColor.rgb - hair_color_variation, 0.0, 1.0); +#endif #ifdef V3D_SHADING_SPECULAR_HIGHLIGHT specularColor = vec4(material_data.specular_color.rgb, material_data.roughness); +#ifdef HAIR_SHADER + specularColor.rgb = clamp(specularColor.rgb - hair_color_variation, 0.0, 1.0); +#endif #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED - #ifdef WORKBENCH_ENCODE_NORMALS - if (!gl_FrontFacing) { - normalViewport = normal_encode(normalize(-normal_viewport)); - diffuseColor.a = 1.0; - } - else { - normalViewport = normal_encode(normalize(normal_viewport)); - diffuseColor.a = 0.0; - } - #else /* WORKBENCH_ENCODE_NORMALS */ - normalViewport = normal_viewport; - #endif /* WORKBENCH_ENCODE_NORMALS */ + vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; + n = normalize(n); +# ifdef WORKBENCH_ENCODE_NORMALS + diffuseColor.a = float(gl_FrontFacing); + normalViewport = normal_encode(n); +# else /* WORKBENCH_ENCODE_NORMALS */ + normalViewport = n; +# endif /* WORKBENCH_ENCODE_NORMALS */ +# ifdef HAIR_SHADER + diffuseColor.a = 0.5; +# endif #endif /* NORMAL_VIEWPORT_PASS_ENABLED */ } 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 f2df117d897..7da9c2644fe 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -1,30 +1,66 @@ uniform mat4 ModelViewProjectionMatrix; -#ifdef NORMAL_VIEWPORT_PASS_ENABLED +uniform mat4 ProjectionMatrix; +uniform mat4 ViewProjectionMatrix; +uniform mat4 ViewMatrixInverse; uniform mat3 NormalMatrix; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ +#ifndef HAIR_SHADER in vec3 pos; -#ifdef NORMAL_VIEWPORT_PASS_ENABLED in vec3 nor; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ -#ifdef OB_TEXTURE in vec2 uv; -#endif +#else /* HAIR_SHADER */ +# ifdef OB_TEXTURE +uniform samplerBuffer u; /* active texture layer */ +# endif +flat out float hair_rand; +#endif /* HAIR_SHADER */ #ifdef NORMAL_VIEWPORT_PASS_ENABLED out vec3 normal_viewport; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ +#endif #ifdef OB_TEXTURE out vec2 uv_interp; #endif +/* From http://libnoise.sourceforge.net/noisegen/index.html */ +float integer_noise(int n) +{ + n = (n >> 13) ^ n; + int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return (float(nn) / 1073741824.0); +} + void main() { +#ifdef HAIR_SHADER +# ifdef OB_TEXTURE + vec2 uv = hair_get_customdata_vec2(u); +# endif + float time, thick_time, thickness; + vec3 pos, tan, binor; + hair_get_pos_tan_binor_time( + (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. */ + 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; + gl_Position = ViewProjectionMatrix * vec4(pos, 1.0); +#else + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +#endif #ifdef OB_TEXTURE uv_interp = uv; #endif #ifdef NORMAL_VIEWPORT_PASS_ENABLED - normal_viewport = normalize(NormalMatrix * nor); -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + normal_viewport = NormalMatrix * nor; +# ifndef HAIR_SHADER + normal_viewport = normalize(normal_viewport); +# endif +#endif } diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 47700c4bfd3..82f24b5c8cf 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -76,6 +76,8 @@ static struct { } e_data = {{NULL}}; /* Shaders */ +extern char datatoc_common_hair_lib_glsl[]; + extern char datatoc_workbench_prepass_vert_glsl[]; extern char datatoc_workbench_prepass_frag_glsl[]; extern char datatoc_workbench_deferred_composite_frag_glsl[]; @@ -130,15 +132,31 @@ static char *workbench_build_prepass_frag(void) return str; } -static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype) +static char *workbench_build_prepass_vert(void) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype, bool is_hair) { if (e_data.prepass_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, drawtype); + char *defines = workbench_material_build_defines(wpd, drawtype, 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( - datatoc_workbench_prepass_vert_glsl, NULL, prepass_frag, defines); - if (drawtype == OB_SOLID) { + prepass_vert, NULL, + prepass_frag, defines); + if (drawtype == OB_SOLID && !is_hair) { e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); } MEM_freeN(prepass_frag); @@ -149,14 +167,20 @@ static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, int d static void select_deferred_shaders(WORKBENCH_PrivateData *wpd) { - int index_solid = workbench_material_get_shader_index(wpd, OB_SOLID); - int index_texture = workbench_material_get_shader_index(wpd, OB_TEXTURE); + int index_solid = workbench_material_get_shader_index(wpd, OB_SOLID, false); + int index_solid_hair = workbench_material_get_shader_index(wpd, OB_SOLID, true); + int index_texture = workbench_material_get_shader_index(wpd, OB_TEXTURE, false); + int index_texture_hair = workbench_material_get_shader_index(wpd, OB_TEXTURE, true); - ensure_deferred_shaders(wpd, index_solid, OB_SOLID); - ensure_deferred_shaders(wpd, index_texture, OB_TEXTURE); + ensure_deferred_shaders(wpd, index_solid, OB_SOLID, false); + ensure_deferred_shaders(wpd, index_solid_hair, OB_SOLID, true); + ensure_deferred_shaders(wpd, index_texture, OB_TEXTURE, false); + ensure_deferred_shaders(wpd, index_texture_hair, OB_TEXTURE, 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_texture_sh = e_data.prepass_sh_cache[index_texture]; + wpd->prepass_texture_hair_sh = e_data.prepass_sh_cache[index_texture_hair]; wpd->composite_sh = e_data.composite_sh_cache[index_solid]; } @@ -263,6 +287,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata) { int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; psl->prepass_pass = DRW_pass_create("Prepass", state); + psl->prepass_hair_pass = DRW_pass_create("Prepass", state); } } @@ -449,11 +474,18 @@ static WORKBENCH_MaterialData *get_or_create_material_data( static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) { + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PassList *psl = vedata->psl; + WORKBENCH_PrivateData *wpd = stl->g_data; const DRWContextState *draw_ctx = DRW_context_state_get(); if (ob == draw_ctx->object_edit) { return; } - for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { + for (ModifierData *md = ob->modifiers.first; md; md = md->next) { + if (md->type != eModifierType_ParticleSystem) { + continue; + } + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; if (!psys_check_enabled(ob, psys, false)) { continue; } @@ -463,13 +495,35 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o ParticleSettings *part = psys->part; const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - static float mat[4][4]; - unit_m4(mat); - if (draw_as == PART_DRAW_PATH) { - struct Gwn_Batch *geom = DRW_cache_particles_get_hair(ob, psys, NULL); - WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); - DRW_shgroup_call_add(material->shgrp, geom, mat); + Image *image = NULL; + Material *mat = give_current_material(ob, part->omat); + int mat_drawtype = OB_SOLID; + + if (wpd->drawtype == OB_TEXTURE) { + ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL); + /* use OB_SOLID when no texture could be determined */ + if (image) { + mat_drawtype = OB_TEXTURE; + } + } + + WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, mat_drawtype); + + struct GPUShader *shader = (mat_drawtype == OB_SOLID) + ? wpd->prepass_solid_hair_sh + : wpd->prepass_texture_hair_sh; + DRWShadingGroup *shgrp = DRW_shgroup_hair_create( + ob, psys, md, + psl->prepass_hair_pass, + shader); + DRW_shgroup_stencil_mask(shgrp, 0xFF); + DRW_shgroup_uniform_int(shgrp, "object_id", &material->object_id, 1); + DRW_shgroup_uniform_block(shgrp, "material_block", material->material_ubo); + if (image) { + GPUTexture *tex = GPU_texture_from_blender(image, NULL, GL_TEXTURE_2D, false, false, false); + DRW_shgroup_uniform_texture(shgrp, "image", tex); + } } } } @@ -658,6 +712,7 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata) /* clear in background */ GPU_framebuffer_bind(fbl->prepass_fb); DRW_draw_pass(psl->prepass_pass); + DRW_draw_pass(psl->prepass_hair_pass); if (SHADOW_ENABLED(wpd)) { #ifdef DEBUG_SHADOW_VOLUME GPU_framebuffer_bind(fbl->composite_fb); diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index dc7d80d51ce..cf7a7858f7a 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -51,8 +51,9 @@ static struct { struct GPUShader *composite_sh_cache[MAX_SHADERS]; struct GPUShader *transparent_accum_sh_cache[MAX_SHADERS]; struct GPUShader *transparent_revealage_sh; + struct GPUShader *transparent_revealage_hair_sh; struct GPUShader *object_outline_sh; - struct GPUShader *depth_sh; + struct GPUShader *object_outline_hair_sh; struct GPUShader *checker_depth_sh; struct GPUTexture *object_id_tx; /* ref only, not alloced */ @@ -66,6 +67,7 @@ static struct { } e_data = {{NULL}}; /* Shaders */ +extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_workbench_forward_composite_frag_glsl[]; extern char datatoc_workbench_forward_depth_frag_glsl[]; extern char datatoc_workbench_forward_transparent_accum_frag_glsl[]; @@ -95,6 +97,20 @@ static char *workbench_build_forward_depth_frag(void) return str; } +static char *workbench_build_forward_vert(void) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); + BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + static char *workbench_build_forward_transparent_accum_frag(void) { char *str = NULL; @@ -208,10 +224,10 @@ static WORKBENCH_MaterialData *get_or_create_material_data( return material; } -static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype) +static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, int drawtype, bool is_hair) { - if (e_data.composite_sh_cache[index] == NULL && drawtype == OB_SOLID) { - char *defines = workbench_material_build_defines(wpd, drawtype); + if (e_data.composite_sh_cache[index] == NULL && drawtype == OB_SOLID && !is_hair) { + char *defines = workbench_material_build_defines(wpd, drawtype, 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); @@ -219,27 +235,35 @@ static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, int dr } if (e_data.transparent_accum_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines(wpd, drawtype); + char *defines = workbench_material_build_defines(wpd, drawtype, 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( - datatoc_workbench_prepass_vert_glsl, NULL, transparent_accum_frag, defines); + transparent_accum_vert, NULL, + transparent_accum_frag, defines); + MEM_freeN(transparent_accum_vert); MEM_freeN(transparent_accum_frag); - MEM_freeN(defines); } } static void select_forward_shaders(WORKBENCH_PrivateData *wpd) { - int index_solid = workbench_material_get_shader_index(wpd, OB_SOLID); - int index_texture = workbench_material_get_shader_index(wpd, OB_TEXTURE); + int index_solid = workbench_material_get_shader_index(wpd, OB_SOLID, false); + int index_solid_hair = workbench_material_get_shader_index(wpd, OB_SOLID, true); + int index_texture = workbench_material_get_shader_index(wpd, OB_TEXTURE, false); + int index_texture_hair = workbench_material_get_shader_index(wpd, OB_TEXTURE, true); - ensure_forward_shaders(wpd, index_solid, OB_SOLID); - ensure_forward_shaders(wpd, index_texture, OB_TEXTURE); + ensure_forward_shaders(wpd, index_solid, OB_SOLID, false); + ensure_forward_shaders(wpd, index_solid_hair, OB_SOLID, true); + ensure_forward_shaders(wpd, index_texture, OB_TEXTURE, false); + ensure_forward_shaders(wpd, index_texture_hair, OB_TEXTURE, 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_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]; } /* public functions */ @@ -265,21 +289,31 @@ 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, OB_SOLID); + char *defines = workbench_material_build_defines(wpd, OB_SOLID, false); + char *defines_hair = workbench_material_build_defines(wpd, OB_SOLID, true); + char *forward_vert = workbench_build_forward_vert(); char *forward_depth_frag = workbench_build_forward_depth_frag(); e_data.object_outline_sh = DRW_shader_create( - datatoc_workbench_prepass_vert_glsl, NULL, forward_depth_frag, defines); + forward_vert, NULL, + forward_depth_frag, defines); + e_data.object_outline_hair_sh = DRW_shader_create( + forward_vert, NULL, + forward_depth_frag, defines_hair); #ifdef WORKBENCH_REVEALAGE_ENABLED char *forward_transparent_revealage_frag = workbench_build_forward_transparent_revealage_frag(); e_data.transparent_revealage_sh = DRW_shader_create( - datatoc_workbench_prepass_vert_glsl, NULL, forward_transparent_revealage_frag, defines); + forward_vert, NULL, + forward_transparent_revealage_frag, defines); + e_data.transparent_revealage_hair_sh = DRW_shader_create( + forward_vert, NULL, + forward_transparent_revealage_frag, defines_hair); MEM_freeN(forward_transparent_revealage_frag); #endif - e_data.depth_sh = DRW_shader_create_3D_depth_only(); e_data.checker_depth_sh = DRW_shader_create_fullscreen( datatoc_workbench_checkerboard_depth_frag_glsl, NULL); + MEM_freeN(forward_vert); MEM_freeN(forward_depth_frag); MEM_freeN(defines); } @@ -332,14 +366,14 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) GPU_framebuffer_clear_color_depth(fbl->object_outline_fb, clear_color, 1.0f); DRW_stats_group_end(); - /* Treansparecy Accum */ + /* Transparency Accum */ { int state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE_FULL; psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state); } #ifdef WORKBENCH_REVEALAGE_ENABLED - /* Treansparecy Revealage */ + /* Transparency Revealage */ { int state = DRW_STATE_WRITE_COLOR | DRW_STATE_TRANSPARENT_REVEALAGE; psl->transparent_revealage_pass = DRW_pass_create("Transparent Revealage", state); @@ -386,8 +420,10 @@ void workbench_forward_engine_free() } #ifdef WORKBENCH_REVEALAGE_ENABLED DRW_SHADER_FREE_SAFE(e_data.transparent_revealage_sh); + DRW_SHADER_FREE_SAFE(e_data.transparent_revealage_hair_sh); #endif DRW_SHADER_FREE_SAFE(e_data.object_outline_sh); + DRW_SHADER_FREE_SAFE(e_data.object_outline_hair_sh); DRW_SHADER_FREE_SAFE(e_data.checker_depth_sh); } @@ -397,15 +433,19 @@ void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata)) static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) { -#ifdef WORKBENCH_REVEALAGE_ENABLED WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_PrivateData *wpd = stl->g_data; -#endif const DRWContextState *draw_ctx = DRW_context_state_get(); + if (ob == draw_ctx->object_edit) { return; } - for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) { + for (ModifierData *md = ob->modifiers.first; md; md = md->next) { + if (md->type != eModifierType_ParticleSystem) { + continue; + } + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; if (!psys_check_enabled(ob, psys, false)) { continue; } @@ -415,17 +455,46 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O ParticleSettings *part = psys->part; const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - static float mat[4][4]; - unit_m4(mat); - if (draw_as == PART_DRAW_PATH) { - struct Gwn_Batch *geom = DRW_cache_particles_get_hair(ob, psys, NULL); - WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, NULL, NULL, OB_SOLID); + Image *image = NULL; + Material *mat = give_current_material(ob, part->omat); + int mat_drawtype = OB_SOLID; + + if (wpd->drawtype == OB_TEXTURE) { + ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL); + /* use OB_SOLID when no texture could be determined */ + if (image) { + mat_drawtype = OB_TEXTURE; + } + } + + WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, mat_drawtype); + + struct GPUShader *shader = (mat_drawtype == OB_SOLID) + ? wpd->transparent_accum_hair_sh + : wpd->transparent_accum_texture_hair_sh; + DRWShadingGroup *shgrp = DRW_shgroup_hair_create( + ob, psys, md, + psl->transparent_accum_pass, + shader); + workbench_material_set_normal_world_matrix(shgrp, wpd, e_data.normal_world_matrix); + DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_block(shgrp, "material_block", material->material_ubo); + DRW_shgroup_uniform_float(shgrp, "alpha", &wpd->shading.xray_alpha, 1); + if (image) { + GPUTexture *tex = GPU_texture_from_blender(image, NULL, GL_TEXTURE_2D, false, false, false); + DRW_shgroup_uniform_texture(shgrp, "image", tex); + } #ifdef WORKBENCH_REVEALAGE_ENABLED - DRW_shgroup_call_add(wpd->transparent_revealage_shgrp, geom, mat); + shgrp = DRW_shgroup_hair_create(ob, psys, md, + psl->transparent_revealage_pass, + e_data.transparent_revealage_hair_sh); + DRW_shgroup_uniform_float(shgrp, "alpha", &wpd->shading.xray_alpha, 1); #endif - DRW_shgroup_call_add(material->shgrp_object_outline, geom, mat); - DRW_shgroup_call_add(material->shgrp, geom, mat); + shgrp = DRW_shgroup_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 55a97b99066..7c9c7b96b7b 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -40,7 +40,7 @@ void workbench_material_update_data(WORKBENCH_PrivateData *wpd, Object *ob, Mate } } -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype) +char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype, bool is_hair) { char *str = NULL; @@ -79,6 +79,9 @@ char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype) if (NORMAL_ENCODING_ENABLED()) { BLI_dynstr_appendf(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); } + if (is_hair) { + BLI_dynstr_appendf(ds, "#define HAIR_SHADER\n"); + } #ifdef WORKBENCH_REVEALAGE_ENABLED BLI_dynstr_appendf(ds, "#define WORKBENCH_REVEALAGE_ENABLED\n"); @@ -115,12 +118,13 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template) return result; } -int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype) +int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype, bool is_hair) { + /* NOTE: change MAX_SHADERS accordingly when modifying this function. */ const int DRAWOPTIONS_MASK = V3D_SHADING_OBJECT_OUTLINE | V3D_SHADING_SHADOW | V3D_SHADING_SPECULAR_HIGHLIGHT; int index = (wpd->shading.flag & DRAWOPTIONS_MASK); index = (index << 2) + wpd->shading.light; - index = (index << 2); + index = (index << 3); /* set the drawtype flag 0 = OB_SOLID, 1 = OB_TEXTURE @@ -128,6 +132,7 @@ int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype */ SET_FLAG_FROM_TEST(index, wpd->studio_light->flag & STUDIOLIGHT_ORIENTATION_WORLD, 2); SET_FLAG_FROM_TEST(index, drawtype == OB_TEXTURE, 1); + SET_FLAG_FROM_TEST(index, is_hair, 4); return index; } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 6fc3251a085..ddcec29cd21 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -38,7 +38,7 @@ #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" #define M_GOLDEN_RATION_CONJUGATE 0.618033988749895 -#define MAX_SHADERS 512 +#define MAX_SHADERS (1 << 10) #define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) @@ -72,6 +72,7 @@ typedef struct WORKBENCH_StorageList { typedef struct WORKBENCH_PassList { /* deferred rendering */ struct DRWPass *prepass_pass; + struct DRWPass *prepass_hair_pass; struct DRWPass *shadow_depth_pass_pass; struct DRWPass *shadow_depth_pass_mani_pass; struct DRWPass *shadow_depth_fail_pass; @@ -133,10 +134,14 @@ BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Material, 16) typedef struct WORKBENCH_PrivateData { struct GHash *material_hash; struct GPUShader *prepass_solid_sh; + struct GPUShader *prepass_solid_hair_sh; struct GPUShader *prepass_texture_sh; + struct GPUShader *prepass_texture_hair_sh; struct GPUShader *composite_sh; struct GPUShader *transparent_accum_sh; + struct GPUShader *transparent_accum_hair_sh; struct GPUShader *transparent_accum_texture_sh; + struct GPUShader *transparent_accum_texture_hair_sh; View3DShading shading; StudioLight *studio_light; int drawtype; @@ -216,10 +221,10 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob); void workbench_forward_cache_finish(WORKBENCH_Data *vedata); /* workbench_materials.c */ -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype); +char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, int drawtype, 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, int drawtype); +int workbench_material_get_shader_index(WORKBENCH_PrivateData *wpd, int drawtype, bool is_hair); void workbench_material_set_normal_world_matrix( DRWShadingGroup *grp, WORKBENCH_PrivateData *wpd, float persistent_matrix[3][3]); |