Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/intern/draw_cache_impl_subdivision.cc
| Show First 20 Lines • Show All 527 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name DRWSubdivCache | /** \name DRWSubdivCache | ||||
| * \{ */ | * \{ */ | ||||
| static bool draw_subdiv_cache_need_polygon_data(const DRWSubdivCache *cache) | |||||
| { | |||||
| return cache->subdiv && cache->subdiv->evaluator && cache->num_subdiv_loops != 0; | |||||
| } | |||||
| static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache) | static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache) | ||||
| { | { | ||||
| GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset); | GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset); | ||||
| MEM_SAFE_FREE(cache->mat_start); | MEM_SAFE_FREE(cache->mat_start); | ||||
| MEM_SAFE_FREE(cache->mat_end); | MEM_SAFE_FREE(cache->mat_end); | ||||
| } | } | ||||
| static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache) | static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache) | ||||
| Show All 16 Lines | void draw_subdiv_cache_free(DRWSubdivCache *cache) | ||||
| GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency); | GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency); | ||||
| cache->resolution = 0; | cache->resolution = 0; | ||||
| cache->num_subdiv_loops = 0; | cache->num_subdiv_loops = 0; | ||||
| cache->num_subdiv_edges = 0; | cache->num_subdiv_edges = 0; | ||||
| cache->num_subdiv_verts = 0; | cache->num_subdiv_verts = 0; | ||||
| cache->num_subdiv_triangles = 0; | cache->num_subdiv_triangles = 0; | ||||
| cache->num_coarse_poly = 0; | cache->num_coarse_poly = 0; | ||||
| cache->num_subdiv_quads = 0; | cache->num_subdiv_quads = 0; | ||||
| cache->may_have_loose_geom = false; | |||||
| draw_subdiv_free_edit_mode_cache(cache); | draw_subdiv_free_edit_mode_cache(cache); | ||||
| draw_subdiv_cache_free_material_data(cache); | draw_subdiv_cache_free_material_data(cache); | ||||
| draw_patch_map_free(&cache->gpu_patch_map); | draw_patch_map_free(&cache->gpu_patch_map); | ||||
| if (cache->ubo) { | if (cache->ubo) { | ||||
| GPU_uniformbuf_free(cache->ubo); | GPU_uniformbuf_free(cache->ubo); | ||||
| cache->ubo = nullptr; | cache->ubo = nullptr; | ||||
| } | } | ||||
| MEM_SAFE_FREE(cache->loose_geom.edges); | |||||
| MEM_SAFE_FREE(cache->loose_geom.verts); | |||||
| cache->loose_geom.edge_len = 0; | |||||
| cache->loose_geom.vert_len = 0; | |||||
| cache->loose_geom.loop_len = 0; | |||||
| } | } | ||||
| /* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of | /* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of | ||||
| * each uint (one per coarse face), #SUBDIV_COARSE_FACE_FLAG_OFFSET tells where they are in the | * each uint (one per coarse face), #SUBDIV_COARSE_FACE_FLAG_OFFSET tells where they are in the | ||||
| * packed bits. */ | * packed bits. */ | ||||
| #define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u | #define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u | ||||
| #define SUBDIV_COARSE_FACE_FLAG_SELECT 2u | #define SUBDIV_COARSE_FACE_FLAG_SELECT 2u | ||||
| #define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u | #define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u | ||||
| ▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | |||||
| static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context, | static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context, | ||||
| const int num_vertices, | const int num_vertices, | ||||
| const int num_edges, | const int num_edges, | ||||
| const int num_loops, | const int num_loops, | ||||
| const int num_polygons, | const int num_polygons, | ||||
| const int *subdiv_polygon_offset) | const int *subdiv_polygon_offset) | ||||
| { | { | ||||
| if (num_loops == 0) { | /* num_loops does not take into account meshes with only loose geometry, which might be meshes | ||||
| * used as custom bone shapes, so let's check the num_vertices also. */ | |||||
| if (num_vertices == 0 && num_loops == 0) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); | DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); | ||||
| DRWSubdivCache *cache = ctx->cache; | DRWSubdivCache *cache = ctx->cache; | ||||
| /* Set topology information. */ | /* Set topology information only if we have loops. */ | ||||
| if (num_loops != 0) { | |||||
| cache->num_subdiv_edges = (uint)num_edges; | cache->num_subdiv_edges = (uint)num_edges; | ||||
| cache->num_subdiv_loops = (uint)num_loops; | cache->num_subdiv_loops = (uint)num_loops; | ||||
| cache->num_subdiv_verts = (uint)num_vertices; | cache->num_subdiv_verts = (uint)num_vertices; | ||||
| cache->num_subdiv_quads = (uint)num_polygons; | cache->num_subdiv_quads = (uint)num_polygons; | ||||
| cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset)); | cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset)); | ||||
| } | |||||
| cache->may_have_loose_geom = num_vertices != 0 || num_edges != 0; | |||||
| /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after | /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after | ||||
| * it was sent to the device, since we may use the data while building other buffers on the CPU | * it was sent to the device, since we may use the data while building other buffers on the CPU | ||||
| * side. */ | * side. */ | ||||
| cache->patch_coords = GPU_vertbuf_calloc(); | cache->patch_coords = GPU_vertbuf_calloc(); | ||||
| GPU_vertbuf_init_with_format_ex( | GPU_vertbuf_init_with_format_ex( | ||||
| cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); | cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); | ||||
| GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops); | GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops); | ||||
| Show All 22 Lines | static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context, | ||||
| ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index; | ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index; | ||||
| ctx->v_origindex = static_cast<int *>( | ctx->v_origindex = static_cast<int *>( | ||||
| CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX)); | CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX)); | ||||
| ctx->e_origindex = static_cast<int *>( | ctx->e_origindex = static_cast<int *>( | ||||
| CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX)); | CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX)); | ||||
| if (cache->num_subdiv_verts) { | |||||
| ctx->vert_origindex_map = static_cast<int *>( | ctx->vert_origindex_map = static_cast<int *>( | ||||
| MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map")); | MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map")); | ||||
| for (int i = 0; i < num_vertices; i++) { | for (int i = 0; i < num_vertices; i++) { | ||||
| ctx->vert_origindex_map[i] = -1; | ctx->vert_origindex_map[i] = -1; | ||||
| } | } | ||||
| } | |||||
| if (cache->num_subdiv_edges) { | |||||
| ctx->edge_origindex_map = static_cast<int *>( | ctx->edge_origindex_map = static_cast<int *>( | ||||
| MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map")); | MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map")); | ||||
| for (int i = 0; i < num_edges; i++) { | for (int i = 0; i < num_edges; i++) { | ||||
| ctx->edge_origindex_map[i] = -1; | ctx->edge_origindex_map[i] = -1; | ||||
| } | } | ||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context, | static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context, | ||||
| void *UNUSED(tls), | void *UNUSED(tls), | ||||
| const int UNUSED(ptex_face_index), | const int UNUSED(ptex_face_index), | ||||
| const float UNUSED(u), | const float UNUSED(u), | ||||
| Show All 26 Lines | static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context, | ||||
| const int coarse_edge_index, | const int coarse_edge_index, | ||||
| const int subdiv_edge_index, | const int subdiv_edge_index, | ||||
| const bool UNUSED(is_loose), | const bool UNUSED(is_loose), | ||||
| const int UNUSED(subdiv_v1), | const int UNUSED(subdiv_v1), | ||||
| const int UNUSED(subdiv_v2)) | const int UNUSED(subdiv_v2)) | ||||
| { | { | ||||
| DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); | DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); | ||||
| if (!ctx->edge_origindex_map) { | |||||
| return; | |||||
| } | |||||
| int coarse_index = coarse_edge_index; | int coarse_index = coarse_edge_index; | ||||
| if (coarse_index != -1) { | if (coarse_index != -1) { | ||||
| if (ctx->e_origindex) { | if (ctx->e_origindex) { | ||||
| coarse_index = ctx->e_origindex[coarse_index]; | coarse_index = ctx->e_origindex[coarse_index]; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | static bool draw_subdiv_build_cache(DRWSubdivCache *cache, | ||||
| DRWCacheBuildingContext cache_building_context; | DRWCacheBuildingContext cache_building_context; | ||||
| memset(&cache_building_context, 0, sizeof(DRWCacheBuildingContext)); | memset(&cache_building_context, 0, sizeof(DRWCacheBuildingContext)); | ||||
| cache_building_context.coarse_mesh = mesh_eval; | cache_building_context.coarse_mesh = mesh_eval; | ||||
| cache_building_context.settings = &to_mesh_settings; | cache_building_context.settings = &to_mesh_settings; | ||||
| cache_building_context.cache = cache; | cache_building_context.cache = cache; | ||||
| do_subdiv_traversal(&cache_building_context, subdiv); | do_subdiv_traversal(&cache_building_context, subdiv); | ||||
| if (cache->num_subdiv_loops == 0) { | if (cache->num_subdiv_loops == 0 && cache->num_subdiv_verts == 0 && | ||||
| !cache->may_have_loose_geom) { | |||||
| /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further. | /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further. | ||||
| * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly. | * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly. | ||||
| */ | */ | ||||
| MEM_SAFE_FREE(cache->subdiv_polygon_offset); | MEM_SAFE_FREE(cache->subdiv_polygon_offset); | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Only build polygon related data if we have polygons. */ | |||||
| if (cache->num_subdiv_loops != 0) { | |||||
| /* Build buffers for the PatchMap. */ | /* Build buffers for the PatchMap. */ | ||||
| draw_patch_map_build(&cache->gpu_patch_map, subdiv); | draw_patch_map_build(&cache->gpu_patch_map, subdiv); | ||||
| cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); | cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); | ||||
| // Build patch coordinates for all the face dots | /* Build patch coordinates for all the face dots. */ | ||||
| cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), | cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), | ||||
| mesh_eval->totpoly); | mesh_eval->totpoly); | ||||
| CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data( | CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *) | ||||
| cache->fdots_patch_coords); | GPU_vertbuf_get_data(cache->fdots_patch_coords); | ||||
| for (int i = 0; i < mesh_eval->totpoly; i++) { | for (int i = 0; i < mesh_eval->totpoly; i++) { | ||||
| const int ptex_face_index = cache->face_ptex_offset[i]; | const int ptex_face_index = cache->face_ptex_offset[i]; | ||||
| if (mesh_eval->mpoly[i].totloop == 4) { | if (mesh_eval->mpoly[i].totloop == 4) { | ||||
| /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */ | /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */ | ||||
| blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f); | blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f); | ||||
| } | } | ||||
| else { | else { | ||||
| /* For N-gons, since they are split into quads from the center, and since the center is | /* For N-gons, since they are split into quads from the center, and since the center is | ||||
| * chosen to be the top right corner of each quad, the center coordinate of the coarse face | * chosen to be the top right corner of each quad, the center coordinate of the coarse face | ||||
| * is any one of those top right corners with `u = v = 1.0`. */ | * is any one of those top right corners with `u = v = 1.0`. */ | ||||
| blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f); | blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f); | ||||
| } | } | ||||
| } | } | ||||
| cache->resolution = to_mesh_settings.resolution; | |||||
| cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer( | cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer( | ||||
| cache->subdiv_polygon_offset, mesh_eval->totpoly); | cache->subdiv_polygon_offset, mesh_eval->totpoly); | ||||
| cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset, | cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset, | ||||
| mesh_eval->totpoly + 1); | mesh_eval->totpoly + 1); | ||||
| cache->num_coarse_poly = mesh_eval->totpoly; | |||||
| build_vertex_face_adjacency_maps(cache); | build_vertex_face_adjacency_maps(cache); | ||||
| } | |||||
| cache->resolution = to_mesh_settings.resolution; | |||||
| cache->num_coarse_poly = mesh_eval->totpoly; | |||||
| /* Cleanup. */ | /* Cleanup. */ | ||||
| MEM_freeN(cache_building_context.vert_origindex_map); | MEM_SAFE_FREE(cache_building_context.vert_origindex_map); | ||||
| MEM_freeN(cache_building_context.edge_origindex_map); | MEM_SAFE_FREE(cache_building_context.edge_origindex_map); | ||||
| return true; | return true; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name DRWSubdivUboStorage. | /** \name DRWSubdivUboStorage. | ||||
| ▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache, | ||||
| draw_subdiv_ubo_update_and_bind( | draw_subdiv_ubo_update_and_bind( | ||||
| cache, shader, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask); | cache, shader, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask); | ||||
| GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1); | GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1); | ||||
| } | } | ||||
| void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor) | void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor) | ||||
| { | { | ||||
| if (!draw_subdiv_cache_need_polygon_data(cache)) { | |||||
| /* Happens on meshes with only loose geometry. */ | |||||
| return; | |||||
| } | |||||
| Subdiv *subdiv = cache->subdiv; | Subdiv *subdiv = cache->subdiv; | ||||
| OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; | OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; | ||||
| OpenSubdiv_Buffer src_buffer_interface; | OpenSubdiv_Buffer src_buffer_interface; | ||||
| GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, | GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, | ||||
| get_subdiv_vertex_format()); | get_subdiv_vertex_format()); | ||||
| evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface); | evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface); | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_nor) | ||||
| GPU_vertbuf_discard(src_buffer); | GPU_vertbuf_discard(src_buffer); | ||||
| } | } | ||||
| void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, | void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, | ||||
| GPUVertBuf *uvs, | GPUVertBuf *uvs, | ||||
| const int face_varying_channel, | const int face_varying_channel, | ||||
| const int dst_offset) | const int dst_offset) | ||||
| { | { | ||||
| if (!draw_subdiv_cache_need_polygon_data(cache)) { | |||||
| /* Happens on meshes with only loose geometry. */ | |||||
| return; | |||||
| } | |||||
| Subdiv *subdiv = cache->subdiv; | Subdiv *subdiv = cache->subdiv; | ||||
| OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; | OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; | ||||
| OpenSubdiv_Buffer src_buffer_interface; | OpenSubdiv_Buffer src_buffer_interface; | ||||
| GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, get_uvs_format()); | GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, get_uvs_format()); | ||||
| evaluator->wrapFVarSrcBuffer(evaluator, face_varying_channel, &src_buffer_interface); | evaluator->wrapFVarSrcBuffer(evaluator, face_varying_channel, &src_buffer_interface); | ||||
| OpenSubdiv_Buffer patch_arrays_buffer_interface; | OpenSubdiv_Buffer patch_arrays_buffer_interface; | ||||
| ▲ Show 20 Lines • Show All 205 Lines • ▼ Show 20 Lines | void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache, | ||||
| /* Cleanup. */ | /* Cleanup. */ | ||||
| GPU_shader_unbind(); | GPU_shader_unbind(); | ||||
| } | } | ||||
| void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, | void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, | ||||
| GPUIndexBuf *subdiv_tris, | GPUIndexBuf *subdiv_tris, | ||||
| const int material_count) | const int material_count) | ||||
| { | { | ||||
| if (!draw_subdiv_cache_need_polygon_data(cache)) { | |||||
| /* Happens on meshes with only loose geometry. */ | |||||
| return; | |||||
| } | |||||
| const bool do_single_material = material_count <= 1; | const bool do_single_material = material_count <= 1; | ||||
| const char *defines = "#define SUBDIV_POLYGON_OFFSET\n"; | const char *defines = "#define SUBDIV_POLYGON_OFFSET\n"; | ||||
| if (do_single_material) { | if (do_single_material) { | ||||
| defines = | defines = | ||||
| "#define SUBDIV_POLYGON_OFFSET\n" | "#define SUBDIV_POLYGON_OFFSET\n" | ||||
| "#define SINGLE_MATERIAL\n"; | "#define SINGLE_MATERIAL\n"; | ||||
| } | } | ||||
| Show All 20 Lines | void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, | ||||
| GPU_shader_unbind(); | GPU_shader_unbind(); | ||||
| } | } | ||||
| void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache, | void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache, | ||||
| GPUVertBuf *fdots_pos, | GPUVertBuf *fdots_pos, | ||||
| GPUVertBuf *fdots_nor, | GPUVertBuf *fdots_nor, | ||||
| GPUIndexBuf *fdots_indices) | GPUIndexBuf *fdots_indices) | ||||
| { | { | ||||
| if (!draw_subdiv_cache_need_polygon_data(cache)) { | |||||
| /* Happens on meshes with only loose geometry. */ | |||||
| return; | |||||
| } | |||||
| Subdiv *subdiv = cache->subdiv; | Subdiv *subdiv = cache->subdiv; | ||||
| OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; | OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; | ||||
| OpenSubdiv_Buffer src_buffer_interface; | OpenSubdiv_Buffer src_buffer_interface; | ||||
| GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, | GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, | ||||
| get_subdiv_vertex_format()); | get_subdiv_vertex_format()); | ||||
| evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface); | evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface); | ||||
| ▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache, | ||||
| /* Cleanup. */ | /* Cleanup. */ | ||||
| GPU_shader_unbind(); | GPU_shader_unbind(); | ||||
| } | } | ||||
| void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, | void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, | ||||
| GPUVertBuf *pos_nor, | GPUVertBuf *pos_nor, | ||||
| GPUVertBuf *lnor) | GPUVertBuf *lnor) | ||||
| { | { | ||||
| if (!draw_subdiv_cache_need_polygon_data(cache)) { | |||||
| /* Happens on meshes with only loose geometry. */ | |||||
| return; | |||||
| } | |||||
| GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n"); | GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n"); | ||||
| GPU_shader_bind(shader); | GPU_shader_bind(shader); | ||||
| /* Inputs */ | /* Inputs */ | ||||
| GPU_vertbuf_bind_as_ssbo(pos_nor, 1); | GPU_vertbuf_bind_as_ssbo(pos_nor, 1); | ||||
| GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 2); | GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 2); | ||||
| /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */ | /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */ | ||||
| GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0); | GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0); | ||||
| ▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | static bool draw_subdiv_create_requested_buffers(const Scene *scene, | ||||
| Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true); | Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true); | ||||
| if (!subdiv) { | if (!subdiv) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (!BKE_subdiv_eval_begin_from_mesh( | if (!BKE_subdiv_eval_begin_from_mesh( | ||||
| subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) { | subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) { | ||||
| /* This could happen in two situations: | |||||
| * - OpenSubdiv is disabled. | |||||
| * - Something totally bad happened, and OpenSubdiv rejected our | |||||
| * topology. | |||||
| * In either way, we can't safely continue. However, we still have to handle potential loose | |||||
| * geometry, which is done separately. */ | |||||
jbakker: Could add a comment that we continue for loose geometry? | |||||
| if (mesh_eval->totpoly) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| } | |||||
| DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache); | DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache); | ||||
| if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) { | if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges); | const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges); | ||||
| Show All 19 Lines | static bool draw_subdiv_create_requested_buffers(const Scene *scene, | ||||
| mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); | mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr); | ||||
| mesh_render_data_free(mr); | mesh_render_data_free(mr); | ||||
| return true; | return true; | ||||
| } | } | ||||
| void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache) | |||||
| { | |||||
| const int coarse_loose_vert_len = cache->loose_geom.vert_len; | |||||
| const int coarse_loose_edge_len = cache->loose_geom.edge_len; | |||||
| if (coarse_loose_vert_len == 0 && coarse_loose_edge_len == 0) { | |||||
| /* Nothing to do. */ | |||||
| return; | |||||
| } | |||||
| if (subdiv_cache->loose_geom.edges || subdiv_cache->loose_geom.verts) { | |||||
| /* Already processed. */ | |||||
| return; | |||||
| } | |||||
| const Mesh *coarse_mesh = subdiv_cache->mesh; | |||||
| const bool is_simple = subdiv_cache->subdiv->settings.is_simple; | |||||
| const int resolution = subdiv_cache->resolution; | |||||
| const int resolution_1 = resolution - 1; | |||||
| const float inv_resolution_1 = 1.0f / (float)resolution_1; | |||||
| const int num_subdiv_vertices_per_coarse_edge = resolution - 2; | |||||
| const int num_subdivided_edge = coarse_loose_edge_len * | |||||
| (num_subdiv_vertices_per_coarse_edge + 1); | |||||
| /* Each edge will store data for its 2 verts, that way we can keep the overall logic simple, here | |||||
| * and in the buffer extractors. Although it duplicates memory (and work), the buffers also store | |||||
| * duplicate values. */ | |||||
| const int num_subdivided_verts = num_subdivided_edge * 2; | |||||
| DRWSubdivLooseEdge *loose_subd_edges = static_cast<DRWSubdivLooseEdge *>( | |||||
| MEM_callocN(sizeof(DRWSubdivLooseEdge) * num_subdivided_edge, "DRWSubdivLooseEdge")); | |||||
| DRWSubdivLooseVertex *loose_subd_verts = static_cast<DRWSubdivLooseVertex *>( | |||||
| MEM_callocN(sizeof(DRWSubdivLooseVertex) * (num_subdivided_verts + coarse_loose_vert_len), | |||||
| "DRWSubdivLooseEdge")); | |||||
| int subd_edge_offset = 0; | |||||
| int subd_vert_offset = 0; | |||||
| /* Subdivide each loose coarse edge. */ | |||||
| for (int i = 0; i < coarse_loose_edge_len; i++) { | |||||
| const int coarse_edge_index = cache->loose_geom.edges[i]; | |||||
| const MEdge *coarse_edge = &coarse_mesh->medge[cache->loose_geom.edges[i]]; | |||||
| /* Perform interpolation of each vertex. */ | |||||
| for (int i = 0; i < resolution - 1; i++, subd_edge_offset++) { | |||||
| DRWSubdivLooseEdge &subd_edge = loose_subd_edges[subd_edge_offset]; | |||||
| subd_edge.coarse_edge_index = coarse_edge_index; | |||||
| /* First vert. */ | |||||
| DRWSubdivLooseVertex &subd_v1 = loose_subd_verts[subd_vert_offset]; | |||||
| subd_v1.coarse_vertex_index = (i == 0) ? coarse_edge->v1 : -1u; | |||||
| const float u1 = i * inv_resolution_1; | |||||
| BKE_subdiv_mesh_interpolate_position_on_edge( | |||||
| coarse_mesh, coarse_edge, is_simple, u1, subd_v1.co); | |||||
| subd_edge.loose_subdiv_v1_index = subd_vert_offset++; | |||||
| /* Second vert. */ | |||||
| DRWSubdivLooseVertex &subd_v2 = loose_subd_verts[subd_vert_offset]; | |||||
| subd_v2.coarse_vertex_index = ((i + 1) == resolution - 1) ? coarse_edge->v2 : -1u; | |||||
| const float u2 = (i + 1) * inv_resolution_1; | |||||
| BKE_subdiv_mesh_interpolate_position_on_edge( | |||||
| coarse_mesh, coarse_edge, is_simple, u2, subd_v2.co); | |||||
| subd_edge.loose_subdiv_v2_index = subd_vert_offset++; | |||||
| } | |||||
| } | |||||
| /* Copy the remaining loose_verts. */ | |||||
| for (int i = 0; i < coarse_loose_vert_len; i++) { | |||||
| const int coarse_vertex_index = cache->loose_geom.verts[i]; | |||||
| const MVert &coarse_vertex = coarse_mesh->mvert[coarse_vertex_index]; | |||||
| DRWSubdivLooseVertex &subd_v = loose_subd_verts[subd_vert_offset++]; | |||||
| subd_v.coarse_vertex_index = cache->loose_geom.verts[i]; | |||||
| copy_v3_v3(subd_v.co, coarse_vertex.co); | |||||
| } | |||||
| subdiv_cache->loose_geom.edges = loose_subd_edges; | |||||
| subdiv_cache->loose_geom.verts = loose_subd_verts; | |||||
| subdiv_cache->loose_geom.edge_len = num_subdivided_edge; | |||||
| subdiv_cache->loose_geom.vert_len = coarse_loose_vert_len; | |||||
| subdiv_cache->loose_geom.loop_len = num_subdivided_edge * 2 + coarse_loose_vert_len; | |||||
| } | |||||
| blender::Span<DRWSubdivLooseEdge> draw_subdiv_cache_get_loose_edges(const DRWSubdivCache *cache) | |||||
| { | |||||
| return {cache->loose_geom.edges, static_cast<int64_t>(cache->loose_geom.edge_len)}; | |||||
| } | |||||
| blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWSubdivCache *cache) | |||||
| { | |||||
| return {cache->loose_geom.verts + cache->loose_geom.edge_len * 2, | |||||
| static_cast<int64_t>(cache->loose_geom.vert_len)}; | |||||
| } | |||||
| static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr; | static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr; | ||||
| void DRW_create_subdivision(const Scene *scene, | void DRW_create_subdivision(const Scene *scene, | ||||
| Object *ob, | Object *ob, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| struct MeshBatchCache *batch_cache, | struct MeshBatchCache *batch_cache, | ||||
| MeshBufferCache *mbc, | MeshBufferCache *mbc, | ||||
| const bool is_editmode, | const bool is_editmode, | ||||
| ▲ Show 20 Lines • Show All 85 Lines • Show Last 20 Lines | |||||
Could add a comment that we continue for loose geometry?