diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 06ae1847d06..0e8acf6e6c5 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -1054,6 +1054,88 @@ class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel): _property_type = bpy.types.Material +class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): + bl_label = "" + bl_context = "material" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return (context.material or context.object) and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + mat = context.material + ob = context.object + slot = context.material_slot + space = context.space_data + + if ob: + is_sortable = len(ob.material_slots) > 1 + rows = 1 + if (is_sortable): + rows = 4 + + row = layout.row() + + row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows) + + col = row.column(align=True) + col.operator("object.material_slot_add", icon='ZOOMIN', text="") + col.operator("object.material_slot_remove", icon='ZOOMOUT', text="") + + col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="") + + if is_sortable: + col.separator() + + col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP' + col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN' + + if ob.mode == 'EDIT': + row = layout.row(align=True) + row.operator("object.material_slot_assign", text="Assign") + row.operator("object.material_slot_select", text="Select") + row.operator("object.material_slot_deselect", text="Deselect") + + split = layout.split(percentage=0.65) + + if ob: + split.template_ID(ob, "active_material", new="material.new") + row = split.row() + + if slot: + row.prop(slot, "link", text="") + else: + row.label() + elif mat: + split.template_ID(space, "pin_id") + split.separator() + + +class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel): + bl_label = "Surface" + bl_context = "material" + COMPAT_ENGINES = {'BLENDER_EEVEE'} + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return context.material and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + mat = context.material + if not mat.use_nodes: + layout.prop(mat, "diffuse_color", text="Diffuse") + layout.prop(mat, "specular_color", text="Specular") + layout.prop(mat, "specular_hardness", text="Glossiness") + + classes = ( MATERIAL_MT_sss_presets, MATERIAL_MT_specials, @@ -1082,6 +1164,8 @@ classes = ( MATERIAL_PT_volume_integration, MATERIAL_PT_volume_options, MATERIAL_PT_custom_props, + EEVEE_MATERIAL_PT_context_material, + EEVEE_MATERIAL_PT_surface, ) if __name__ == "__main__": # only for live edit. diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 61f95f8a176..14dbd50c487 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -109,6 +109,7 @@ data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC) data_to_c_simple(engines/clay/shaders/ssao_alchemy.glsl SRC) data_to_c_simple(engines/clay/shaders/ssao_groundtruth.glsl SRC) +data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lit_surface_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/probe_filter_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee.c b/source/blender/draw/engines/eevee/eevee.c index 26e82467cd7..69d6c19b8a7 100644 --- a/source/blender/draw/engines/eevee/eevee.c +++ b/source/blender/draw/engines/eevee/eevee.c @@ -54,6 +54,7 @@ static struct { float camera_pos[3]; } e_data = {NULL}; /* Engine data */ +extern char datatoc_default_frag_glsl[]; extern char datatoc_ltc_lib_glsl[]; extern char datatoc_bsdf_lut_frag_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; @@ -71,6 +72,8 @@ extern char datatoc_probe_frag_glsl[]; extern char datatoc_probe_geom_glsl[]; extern char datatoc_probe_vert_glsl[]; +extern Material defmaterial; + /* Van der Corput sequence */ /* From http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html */ static float radical_inverse(int i) { @@ -213,24 +216,26 @@ static void EEVEE_engine_init(void *ved) } if (!e_data.default_lit) { - char *lib_str = NULL; + char *frag_str = NULL; - DynStr *ds_vert = BLI_dynstr_new(); - BLI_dynstr_append(ds_vert, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_vert, datatoc_ltc_lib_glsl); - BLI_dynstr_append(ds_vert, datatoc_bsdf_direct_lib_glsl); - lib_str = BLI_dynstr_get_cstring(ds_vert); - BLI_dynstr_free(ds_vert); + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl); + BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl); + frag_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); - e_data.default_lit = DRW_shader_create_with_lib( - datatoc_lit_surface_vert_glsl, NULL, datatoc_lit_surface_frag_glsl, lib_str, + e_data.default_lit = DRW_shader_create( + datatoc_lit_surface_vert_glsl, NULL, frag_str, "#define MAX_LIGHT 128\n" "#define MAX_SHADOW_CUBE 42\n" "#define MAX_SHADOW_MAP 64\n" "#define MAX_SHADOW_CASCADE 8\n" "#define MAX_CASCADE_NUM 4\n"); - MEM_freeN(lib_str); + MEM_freeN(frag_str); } if (!e_data.shadow_sh) { @@ -409,10 +414,11 @@ static void EEVEE_cache_init(void *vedata) } { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_EQUAL; - psl->pass = DRW_pass_create("Default Light Pass", state); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; + psl->default_pass = DRW_pass_create("Default Shader Pass", state); - stl->g_data->default_lit_grp = DRW_shgroup_create(e_data.default_lit, psl->pass); + /* NOTE : this shading grp does not contain any geom, it's just here to setup uniforms & textures. */ + stl->g_data->default_lit_grp = DRW_shgroup_create(e_data.default_lit, psl->default_pass); DRW_shgroup_uniform_block(stl->g_data->default_lit_grp, "light_block", stl->light_ubo, 0); DRW_shgroup_uniform_block(stl->g_data->default_lit_grp, "shadow_block", stl->shadow_ubo, 1); DRW_shgroup_uniform_int(stl->g_data->default_lit_grp, "light_count", &stl->lamps->num_light, 1); @@ -425,6 +431,23 @@ static void EEVEE_cache_init(void *vedata) /* NOTE : Adding Shadow Map textures uniform in EEVEE_cache_finish */ } + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; + psl->material_pass = DRW_pass_create("Material Shader Pass", state); + + /* NOTE : this shading grp does not contain any geom, it's just here to setup uniforms & textures. */ + stl->g_data->material_lit_grp = DRW_shgroup_create(e_data.default_lit, psl->material_pass); + DRW_shgroup_uniform_block(stl->g_data->material_lit_grp, "light_block", stl->light_ubo, 0); + DRW_shgroup_uniform_block(stl->g_data->material_lit_grp, "shadow_block", stl->shadow_ubo, 1); + DRW_shgroup_uniform_int(stl->g_data->material_lit_grp, "light_count", &stl->lamps->num_light, 1); + DRW_shgroup_uniform_float(stl->g_data->material_lit_grp, "lodMax", &stl->probes->lodmax, 1); + DRW_shgroup_uniform_vec3(stl->g_data->material_lit_grp, "shCoefs[0]", (float *)stl->probes->shcoefs, 9); + DRW_shgroup_uniform_vec3(stl->g_data->material_lit_grp, "cameraPos", e_data.camera_pos, 1); + DRW_shgroup_uniform_texture(stl->g_data->material_lit_grp, "ltcMat", e_data.ltc_mat, 0); + DRW_shgroup_uniform_texture(stl->g_data->material_lit_grp, "brdfLut", e_data.brdf_lut, 1); + DRW_shgroup_uniform_texture(stl->g_data->material_lit_grp, "probeFiltered", txl->probe_pool, 2); + /* NOTE : Adding Shadow Map textures uniform in EEVEE_cache_finish */ + } { /* Final pass : Map HDR color to LDR color. * Write result to the default color buffer */ @@ -453,7 +476,22 @@ static void EEVEE_cache_populate(void *vedata, Object *ob) /* Depth Prepass */ DRW_shgroup_call_add((do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp, geom, ob->obmat); - DRW_shgroup_call_add(stl->g_data->default_lit_grp, geom, ob->obmat); + /* Get per-material split surface */ + struct Batch **mat_geom = DRW_cache_object_surface_material_get(ob); + for (int i = 0; i < MAX2(1, ob->totcol); ++i) { + Material *ma = give_current_material(ob, i + 1); + + if (ma == NULL) + ma = &defmaterial; + + DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit, psl->material_pass); + DRW_shgroup_uniform_vec3(shgrp, "diffuse_col", &ma->r, 1); + DRW_shgroup_uniform_vec3(shgrp, "specular_col", &ma->specr, 1); + DRW_shgroup_uniform_short(shgrp, "hardness", &ma->har, 1); + DRW_shgroup_call_add(shgrp, mat_geom[i], ob->obmat); + } + // GPUMaterial *gpumat = GPU_material_from_nodetree(struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options) + // DRW_shgroup_call_add(stl->g_data->shadow_shgrp, geom, ob->obmat); eevee_cascade_shadow_shgroup(psl, stl, geom, ob->obmat); eevee_cube_shadow_shgroup(psl, stl, geom, ob->obmat); @@ -475,6 +513,10 @@ static void EEVEE_cache_finish(void *vedata) DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowMaps", txl->shadow_depth_map_pool, 4); DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowCubes", txl->shadow_depth_cube_pool, 5); DRW_shgroup_uniform_texture(stl->g_data->default_lit_grp, "shadowCascades", txl->shadow_depth_cascade_pool, 6); + + DRW_shgroup_uniform_texture(stl->g_data->material_lit_grp, "shadowMaps", txl->shadow_depth_map_pool, 4); + DRW_shgroup_uniform_texture(stl->g_data->material_lit_grp, "shadowCubes", txl->shadow_depth_cube_pool, 5); + DRW_shgroup_uniform_texture(stl->g_data->material_lit_grp, "shadowCascades", txl->shadow_depth_cascade_pool, 6); } static void EEVEE_draw_scene(void *vedata) @@ -505,7 +547,8 @@ static void EEVEE_draw_scene(void *vedata) DRW_draw_pass(psl->depth_pass); DRW_draw_pass(psl->depth_pass_cull); - DRW_draw_pass(psl->pass); + DRW_draw_pass(psl->default_pass); + DRW_draw_pass(psl->material_pass); /* Restore default framebuffer */ DRW_framebuffer_texture_detach(dtxl->depth); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 48c991aecf9..02dc32ddd9a 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -45,7 +45,8 @@ typedef struct EEVEE_PassList { struct DRWPass *depth_pass; struct DRWPass *depth_pass_cull; - struct DRWPass *pass; + struct DRWPass *default_pass; + struct DRWPass *material_pass; struct DRWPass *tonemap; } EEVEE_PassList; @@ -174,6 +175,7 @@ typedef struct EEVEE_LampEngineData { typedef struct g_data{ struct DRWShadingGroup *default_lit_grp; + struct DRWShadingGroup *material_lit_grp; struct DRWShadingGroup *shadow_shgrp; struct DRWShadingGroup *depth_shgrp; struct DRWShadingGroup *depth_shgrp_cull; diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 5762ca45b71..fddc9c54cb2 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -271,6 +271,13 @@ vec3 mrp_area(LightData ld, ShadingData sd, vec3 dir, inout float roughness, out return closest_point_on_rectangle / len; } +/* Fresnel */ +vec3 F_schlick(vec3 f0, float cos_theta) +{ + float fac = pow(1.0 - cos_theta, 5); + return f0 + (1.0 - f0) * fac; +} + /* GGX */ float D_ggx_opti(float NH, float a2) { diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl new file mode 100644 index 00000000000..02ececf7a68 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -0,0 +1,10 @@ + +uniform vec3 diffuse_col; +uniform vec3 specular_col; +uniform int hardness; + +void main() +{ + float roughness = 1.0 - float(hardness) / 511.0; + fragColor = vec4(eevee_surface_lit(worldNormal, diffuse_col, specular_col, roughness), 1.0); +} 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 7e0c0462b30..dca3c99453e 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -198,6 +198,14 @@ float light_visibility(LightData ld, ShadingData sd) return vis; } +vec3 light_fresnel(LightData ld, ShadingData sd, vec3 f0) +{ + vec3 H = normalize(sd.L + sd.V); + float NH = max(dot(sd.N, H), 1e-8); + + return F_schlick(f0, NH); +} + /* Calculation common to all bsdfs */ float light_common(inout LightData ld, inout ShadingData sd) { @@ -223,22 +231,15 @@ float light_common(inout LightData ld, inout ShadingData sd) return vis; } -void main() +vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness) { ShadingData sd; - sd.N = normalize(worldNormal); + sd.N = normalize(world_normal); sd.V = (ProjectionMatrix[3][3] == 0.0) /* if perspective */ ? normalize(cameraPos - worldPosition) : normalize(eye); sd.W = worldPosition; sd.R = reflect(-sd.V, sd.N); - - /* hardcoded test vars */ - vec3 albedo = mix(vec3(0.0, 0.0, 0.0), vec3(0.8, 0.8, 0.8), saturate(worldPosition.y/2)); - vec3 f0 = mix(vec3(0.83, 0.5, 0.1), vec3(0.03, 0.03, 0.03), saturate(worldPosition.y/2)); - vec3 specular = mix(f0, vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0)); - float roughness = saturate(worldPosition.x/lodMax); - sd.spec_dominant_dir = get_specular_dominant_dir(sd.N, sd.R, roughness); vec3 radiance = vec3(0.0); @@ -255,8 +256,9 @@ void main() float vis = light_visibility(ld, sd); float spec = light_specular(ld, sd, roughness); float diff = light_diffuse(ld, sd); + vec3 fresnel = light_fresnel(ld, sd, f0); - radiance += vis * (albedo * diff + specular * spec) * ld.l_color; + radiance += vis * (albedo * diff + fresnel * spec) * ld.l_color; } /* Envmaps */ @@ -267,5 +269,5 @@ void main() radiance += spherical_harmonics(sd.N, shCoefs) * albedo; - fragColor = vec4(radiance, 1.0); + return radiance; } \ No newline at end of file diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index cf86a6a81e8..93fd8d610ea 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -30,6 +30,7 @@ #include "BKE_context.h" #include "BKE_layer.h" +#include "BKE_material.h" #include "BKE_scene.h" #include "BLI_listbase.h" @@ -270,6 +271,7 @@ void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); +void DRW_shgroup_uniform_short(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize); void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize); diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 259d066d4f4..f28e7ac3d6f 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -469,6 +469,16 @@ Batch *DRW_cache_object_surface_get(Object *ob) } } +Batch **DRW_cache_object_surface_material_get(struct Object *ob) +{ + switch (ob->type) { + case OB_MESH: + return DRW_cache_mesh_surface_shaded_get(ob); + default: + return NULL; + } +} + /** \} */ @@ -1586,6 +1596,15 @@ Batch *DRW_cache_mesh_surface_get(Object *ob) return DRW_mesh_batch_cache_get_triangles_with_normals(me); } +/* Return list of batches */ +Batch **DRW_cache_mesh_surface_shaded_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); + + Mesh *me = ob->data; + return DRW_mesh_batch_cache_get_surface_shaded(me); +} + Batch *DRW_cache_mesh_surface_verts_get(Object *ob) { BLI_assert(ob->type == OB_MESH); @@ -1734,12 +1753,4 @@ Batch *DRW_cache_lattice_vert_overlay_get(Object *ob) return DRW_lattice_batch_cache_get_overlay_verts(lt); } -/** \} */ - - -#if 0 /* TODO */ -struct Batch *DRW_cache_surface_material_get(Object *ob, int nr) { - /* TODO */ - return NULL; -} -#endif +/** \} */ \ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 17e9467d1d9..ad122ac5222 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -40,6 +40,7 @@ struct Batch *DRW_cache_screenspace_circle_get(void); /* Common Object */ struct Batch *DRW_cache_object_surface_get(struct Object *ob); +struct Batch **DRW_cache_object_surface_material_get(struct Object *ob); /* Empties */ struct Batch *DRW_cache_plain_axes_get(void); @@ -91,6 +92,7 @@ struct Batch *DRW_cache_mesh_wire_outline_get(struct Object *ob); struct Batch *DRW_cache_mesh_surface_get(struct Object *ob); struct Batch *DRW_cache_mesh_surface_verts_get(struct Object *ob); struct Batch *DRW_cache_mesh_verts_get(struct Object *ob); +struct Batch **DRW_cache_mesh_surface_shaded_get(struct Object *ob); /* Curve */ diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index e4318aa576a..c988a5703dc 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -67,6 +67,7 @@ struct Batch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt); /* Mesh */ +struct Batch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me); struct Batch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me); struct Batch *DRW_mesh_batch_cache_get_all_triangles(struct Mesh *me); struct Batch *DRW_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index eaf854edacb..66fd0663927 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -73,6 +73,11 @@ static int mesh_render_polys_len_get(Mesh *me) return me->edit_btmesh ? me->edit_btmesh->bm->totface : me->totpoly; } +static int mesh_render_mat_ct_get(Mesh *me) +{ + return MAX2(1, me->totcol); +} + static int UNUSED_FUNCTION(mesh_render_loops_len_get)(Mesh *me) { return me->edit_btmesh ? me->edit_btmesh->bm->totloop : me->totloop; @@ -101,6 +106,7 @@ typedef struct MeshRenderData { int tri_len; int loop_len; int poly_len; + int mat_ct; int loose_vert_len; int loose_edge_len; @@ -171,6 +177,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) { MeshRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__); rdata->types = types; + rdata->mat_ct = mesh_render_mat_ct_get(me); if (me->edit_btmesh) { BMEditMesh *embm = me->edit_btmesh; @@ -329,6 +336,12 @@ static int mesh_render_data_looptri_len_get(const MeshRenderData *rdata) return rdata->tri_len; } +static int mesh_render_data_mat_ct_get(const MeshRenderData *rdata) +{ + BLI_assert(rdata->types & MR_DATATYPE_POLY); + return rdata->mat_ct; +} + static int UNUSED_FUNCTION(mesh_render_data_loops_len_get)(const MeshRenderData *rdata) { BLI_assert(rdata->types & MR_DATATYPE_LOOP); @@ -520,6 +533,28 @@ static bool mesh_render_data_looptri_vert_indices_get( return true; } +static bool mesh_render_data_looptri_mat_index_get( + const MeshRenderData *rdata, const int tri_idx, + short *r_face_mat) +{ + BLI_assert(rdata->types & (MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (rdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)rdata->edit_bmesh->looptris[tri_idx]; + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } + *r_face_mat = ((BMFace *)bm_looptri[0]->f)->mat_nr; + } + else { + const int poly_idx = rdata->mlooptri[tri_idx].poly; ; + const MPoly *poly = &rdata->mpoly[poly_idx]; ; + *r_face_mat = poly->mat_nr; + } + + return true; +} + /** * Version of #mesh_render_data_looptri_verts_indices_get that assigns * edge indices too \a r_edges_idx (-1 for non-existant edges). @@ -853,6 +888,12 @@ typedef struct MeshBatchCache { Batch *points_with_normals; Batch *fancy_edges; /* owns its vertex buffer (not shared) */ + /* Maybe have shaded_triangles_data split into pos_nor and uv_tangent + * to minimise data transfer for skinned mesh. */ + VertexBuffer *shaded_triangles_data; + ElementList **shaded_triangles_in_order; + Batch **shaded_triangles; + /* TODO : split in 2 buffers to avoid unnecessary * data transfer when selecting/deselecting * and combine into one batch and use offsets to render @@ -868,6 +909,7 @@ typedef struct MeshBatchCache { int tri_len; int poly_len; int vert_len; + int mat_ct; bool is_editmode; } MeshBatchCache; @@ -881,6 +923,11 @@ static bool mesh_batch_cache_valid(Mesh *me) return false; } + /* XXX find another place for this */ + if (cache->mat_ct != mesh_render_mat_ct_get(me)) { + cache->is_dirty = true; + } + if (cache->is_editmode != (me->edit_btmesh != NULL)) { return false; } @@ -895,7 +942,8 @@ static bool mesh_batch_cache_valid(Mesh *me) else if ((cache->vert_len != mesh_render_verts_len_get(me)) || (cache->edge_len != mesh_render_edges_len_get(me)) || (cache->tri_len != mesh_render_looptri_len_get(me)) || - (cache->poly_len != mesh_render_polys_len_get(me))) + (cache->poly_len != mesh_render_polys_len_get(me)) || + (cache->mat_ct != mesh_render_mat_ct_get(me))) { return false; } @@ -924,6 +972,8 @@ static void mesh_batch_cache_init(Mesh *me) cache->vert_len = mesh_render_verts_len_get(me); } + cache->mat_ct = mesh_render_mat_ct_get(me); + cache->is_dirty = false; } @@ -983,6 +1033,21 @@ static void mesh_batch_cache_clear(Mesh *me) VERTEXBUFFER_DISCARD_SAFE(cache->pos_with_normals); BATCH_DISCARD_ALL_SAFE(cache->fancy_edges); + + VERTEXBUFFER_DISCARD_SAFE(cache->shaded_triangles_data); + if (cache->shaded_triangles_in_order) { + for (int i = 0; i < cache->mat_ct; ++i) { + ELEMENTLIST_DISCARD_SAFE(cache->shaded_triangles_in_order[i]); + } + } + if (cache->shaded_triangles) { + for (int i = 0; i < cache->mat_ct; ++i) { + BATCH_DISCARD_SAFE(cache->shaded_triangles[i]); + } + } + + MEM_SAFE_FREE(cache->shaded_triangles_in_order); + MEM_SAFE_FREE(cache->shaded_triangles); } void DRW_mesh_batch_cache_free(Mesh *me) @@ -993,6 +1058,64 @@ void DRW_mesh_batch_cache_free(Mesh *me) /* Batch cache usage. */ +static VertexBuffer *mesh_batch_cache_get_shading_data(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (cache->shaded_triangles_data == NULL) { + unsigned int vidx = 0, nidx = 0; + + static VertexFormat format = { 0 }; + static unsigned int pos_id, nor_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + /* TODO add tangent, UVs */ + pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); + nor_id = VertexFormat_add_attrib(&format, "nor", COMP_I16, 3, NORMALIZE_INT_TO_FLOAT); + } + + const int tri_len = mesh_render_data_looptri_len_get(rdata); + + VertexBuffer *vbo = cache->shaded_triangles_data = VertexBuffer_create_with_format(&format); + + const int vbo_len_capacity = tri_len * 3; + int vbo_len_used = 0; + VertexBuffer_allocate_data(vbo, vbo_len_capacity); + + /* TODO deduplicate all verts and make use of ElementList in mesh_batch_cache_get_shaded_triangles_in_order. */ + for (int i = 0; i < tri_len; i++) { + float *tri_vert_cos[3]; + short *tri_nor, *tri_vert_nors[3]; + bool is_smooth; + + if (mesh_render_data_looptri_cos_nors_smooth_get( + rdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors, &is_smooth)) + { + if (is_smooth) { + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[0]); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[1]); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_vert_nors[2]); + } + else { + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(vbo, nor_id, nidx++, tri_nor); + } + + VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[0]); + VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[1]); + VertexBuffer_set_attrib(vbo, pos_id, vidx++, tri_vert_cos[2]); + } + } + vbo_len_used = vidx; + + if (vbo_len_capacity != vbo_len_used) { + VertexBuffer_resize_data(vbo, vbo_len_used); + } + } + return cache->shaded_triangles_data; +} + static VertexBuffer *mesh_batch_cache_get_pos_and_normals(MeshRenderData *rdata, MeshBatchCache *cache) { BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); @@ -1048,6 +1171,7 @@ static VertexBuffer *mesh_batch_cache_get_pos_and_normals(MeshRenderData *rdata, } return cache->pos_with_normals; } + static VertexBuffer *mesh_batch_cache_get_pos_and_nor_in_order(MeshRenderData *rdata, MeshBatchCache *cache) { BLI_assert(rdata->types & MR_DATATYPE_VERT); @@ -1118,6 +1242,54 @@ static ElementList *mesh_batch_cache_get_triangles_in_order(MeshRenderData *rdat return cache->triangles_in_order; } +static ElementList **mesh_batch_cache_get_shaded_triangles_in_order(MeshRenderData *rdata, MeshBatchCache *cache) +{ + BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY)); + + if (cache->shaded_triangles_in_order == NULL) { + const int tri_len = mesh_render_data_looptri_len_get(rdata); + const int mat_ct = mesh_render_data_mat_ct_get(rdata); + + int *mat_tri_len = MEM_callocN(sizeof(*mat_tri_len) * mat_ct, "mat_tri_len"); + cache->shaded_triangles_in_order = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_ct, "shaded_triangles_in_order"); + ElementListBuilder *elb = MEM_callocN(sizeof(*elb) * mat_ct, "shaded ElementListBuilder"); + + for (int i = 0; i < tri_len; ++i) { + short ma_id; + if (mesh_render_data_looptri_mat_index_get(rdata, i, &ma_id)) { + mat_tri_len[ma_id] += 1; + } + } + + /* Init ELBs. */ + for (int i = 0; i < mat_ct; ++i) { + ElementListBuilder_init(&elb[i], PRIM_TRIANGLES, mat_tri_len[i], tri_len * 3); + } + + /* Populate ELBs. */ + unsigned int nidx = 0; + for (int i = 0; i < tri_len; ++i) { + short ma_id; + + /* TODO deduplicate verts see mesh_batch_cache_get_shading_data */ + if (mesh_render_data_looptri_mat_index_get(rdata, i, &ma_id)) { + add_triangle_vertices(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2); + nidx += 3; + } + } + + /* Build ELBs. */ + for (int i = 0; i < mat_ct; ++i) { + cache->shaded_triangles_in_order[i] = ElementList_build(&elb[i]); + } + + MEM_freeN(mat_tri_len); + MEM_freeN(elb); + } + + return cache->shaded_triangles_in_order; +} + Batch *DRW_mesh_batch_cache_get_all_edges(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -1445,4 +1617,28 @@ Batch *DRW_mesh_batch_cache_get_overlay_facedots(Mesh *me) return cache->overlay_facedots; } +Batch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->shaded_triangles == NULL) { + /* create batch from DM */ + MeshRenderData *rdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPTRI | MR_DATATYPE_POLY); + + const int mat_ct = mesh_render_data_mat_ct_get(rdata); + + cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_ct, "shaded triangles batches"); + + ElementList **el = mesh_batch_cache_get_shaded_triangles_in_order(rdata, cache); + + for (int i = 0; i < mat_ct; ++i) { + cache->shaded_triangles[i] = Batch_create(PRIM_TRIANGLES, mesh_batch_cache_get_shading_data(rdata, cache), el[i]); + } + + mesh_render_data_free(rdata); + } + + return cache->shaded_triangles; +} + #undef MESH_RENDER_FUNCTION diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 501c7d2dba0..6046db874b8 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -84,6 +84,7 @@ extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; /* Structures */ typedef enum { DRW_UNIFORM_BOOL, + DRW_UNIFORM_SHORT, DRW_UNIFORM_INT, DRW_UNIFORM_FLOAT, DRW_UNIFORM_TEXTURE, @@ -660,6 +661,11 @@ void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize, 0); } +void DRW_shgroup_uniform_short(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) +{ + DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT, value, 1, arraysize, 0); +} + void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) { DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize, 0); @@ -1042,6 +1048,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup) DRWInterface *interface = shgroup->interface; GPUTexture *tex; + int val; if (DST.shader != shgroup->shader) { if (DST.shader) GPU_shader_unbind(); @@ -1063,6 +1070,11 @@ static void draw_shgroup(DRWShadingGroup *shgroup) DRWBoundTexture *bound_tex; switch (uni->type) { + case DRW_UNIFORM_SHORT: + val = (int)*((short *)uni->value); + GPU_shader_uniform_vector_int( + shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)&val); + break; case DRW_UNIFORM_BOOL: case DRW_UNIFORM_INT: GPU_shader_uniform_vector_int(