[Bf-blender-cvs] [f6eccd367cf] blender2.8: Subsurf: Subdivide polygons to the same resolution
Sergey Sharybin
noreply at git.blender.org
Mon Jul 23 19:17:14 CEST 2018
Commit: f6eccd367cf7ef504ebeef332b62a86d928f5542
Author: Sergey Sharybin
Date: Mon Jul 23 18:40:04 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBf6eccd367cf7ef504ebeef332b62a86d928f5542
Subsurf: Subdivide polygons to the same resolution
Previously it was ptex faces which were subdividing to the same
resolution. This was looking like more details for non-quad faces,
but was also causing discontinuity in the edge where quad touches
non-quad polygon.
Now ptex faces which are coming from non-quad faces are subdivided
at a half of resolution, matching old behavior and solving
discontinuity problem.
===================================================================
M source/blender/blenkernel/BKE_subdiv.h
M source/blender/blenkernel/intern/subdiv.c
M source/blender/blenkernel/intern/subdiv_mesh.c
===================================================================
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index a1792866255..003dc7a37d3 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -94,26 +94,6 @@ typedef struct Subdiv {
*/
SubdivSettings settings;
- /* Total number of ptex faces on subdivision level 0.
- *
- * Ptex face is what is internally used by OpenSubdiv for evaluator. It is
- * a quad face, which corresponds to Blender's legacy Catmull Clark grids.
- *
- * Basically, here is a correspondence between polygons and ptex faces:
- * - Triangle consists of 3 PTex faces.
- * - Quad is a single PTex face.
- * - N-gon is N PTex faces.
- *
- * This value is initialized in BKE_subdiv_new_from_FOO() and is read-only
- * after this.
- */
- int num_ptex_faces;
-
- /* Indexed by base face index, element indicates total number of ptex faces
- * created for preceding base faces.
- */
- int *face_ptex_offset;
-
/* Topology refiner includes all the glue logic to feed Blender side
* topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
* drawer.
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 794da2d3477..0bf969b7de2 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -42,23 +42,6 @@
# include "opensubdiv_topology_refiner_capi.h"
#endif
-#ifdef WITH_OPENSUBDIV
-static void update_subdiv_after_topology_change(Subdiv *subdiv)
-{
- /* Count ptex faces. */
- subdiv->num_ptex_faces = subdiv->topology_refiner->getNumPtexFaces(
- subdiv->topology_refiner);
- /* Initialize offset of base faces in ptex indices. */
- MEM_SAFE_FREE(subdiv->face_ptex_offset);
- subdiv->face_ptex_offset = MEM_malloc_arrayN(subdiv->num_ptex_faces,
- sizeof(int),
- "subdiv ptex offset");
- subdiv->topology_refiner->fillFacePtexIndexOffset(
- subdiv->topology_refiner,
- subdiv->face_ptex_offset);
-}
-#endif
-
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
struct OpenSubdiv_Converter *converter)
{
@@ -79,7 +62,6 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
subdiv->settings = *settings;
subdiv->topology_refiner = osd_topology_refiner;
subdiv->evaluator = NULL;
- update_subdiv_after_topology_change(subdiv);
BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
subdiv->stats = stats;
return subdiv;
@@ -113,7 +95,6 @@ void BKE_subdiv_free(Subdiv *subdiv)
if (subdiv->topology_refiner != NULL) {
openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
}
- MEM_SAFE_FREE(subdiv->face_ptex_offset);
MEM_freeN(subdiv);
#endif
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 83f2069ea0f..eb47d9158d3 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -38,27 +38,40 @@
#include "BKE_mesh.h"
-/* TODO(sergey): Somehow move this to subdiv code? */
-static int mpoly_ptex_faces_count_get(const MPoly *mp)
+#include "MEM_guardedalloc.h"
+
+/* =============================================================================
+ * General helpers.
+ */
+
+/* Number of ptex faces for a given polygon. */
+BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
{
- if (mp->totloop == 4) {
- return 1;
- }
- else {
- return mp->totloop;
- }
+ return (poly->totloop == 4) ? 1 : poly->totloop;
}
-static int num_edges_per_ptex_get(const int resolution)
+BLI_INLINE int num_edges_per_ptex_face_get(const int resolution)
{
return 2 * (resolution - 1) * resolution;
}
-static int num_polys_per_ptex_get(const int resolution)
+/* Number of subdivision polygons per ptex face. */
+BLI_INLINE int num_polys_per_ptex_get(const int resolution)
{
return (resolution - 1) * (resolution - 1);
}
+/* Subdivision resolution per given polygon's ptex faces. */
+BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
+{
+ return (poly->totloop == 4) ? (resolution)
+ : ((resolution >> 1) + 1);
+}
+
+/* =============================================================================
+ * Mesh subdivision context.
+ */
+
typedef struct SubdivMeshContext {
const Mesh *coarse_mesh;
Subdiv *subdiv;
@@ -72,8 +85,127 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
+
+ /* Indexed by coarse polygon index, indicates offset in subdivided mesh
+ * vertices, edges and polygons arrays, where first element of the poly
+ * begins.
+ */
+ int *subdiv_vertex_offset;
+ int *subdiv_edge_offset;
+ int *subdiv_polygon_offset;
+ /* Indexed by base face index, element indicates total number of ptex faces
+ * created for preceding base faces.
+ */
+ int *face_ptex_offset;
+
+ /* Counters of geometry in subdivided mesh, initialized as a part of
+ * offsets calculation.
+ */
+ int num_subdiv_vertices;
+ int num_subdiv_edges;
+ int num_subdiv_loops;
+ int num_subdiv_polygons;
} SubdivMeshContext;
+static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ ctx->num_uv_layers =
+ CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ ctx->uv_layers[layer_index] = CustomData_get_layer_n(
+ &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
+ }
+}
+
+static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ /* Pointers to original indices layers. */
+ ctx->vert_origindex = CustomData_get_layer(
+ &subdiv_mesh->vdata, CD_ORIGINDEX);
+ ctx->edge_origindex = CustomData_get_layer(
+ &subdiv_mesh->edata, CD_ORIGINDEX);
+ ctx->loop_origindex = CustomData_get_layer(
+ &subdiv_mesh->ldata, CD_ORIGINDEX);
+ ctx->poly_origindex = CustomData_get_layer(
+ &subdiv_mesh->pdata, CD_ORIGINDEX);
+ /* UV layers interpolation. */
+ subdiv_mesh_ctx_cache_uv_layers(ctx);
+}
+
+static void subdiv_mesh_ctx_init_offsets(SubdivMeshContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ /* Allocate memory. */
+ ctx->subdiv_vertex_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_vertex_offset),
+ "vertex_offset");
+ ctx->subdiv_edge_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_edge_offset),
+ "subdiv_edge_offset");
+ ctx->subdiv_polygon_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_polygon_offset),
+ "subdiv_polygon_offset");
+ ctx->face_ptex_offset = MEM_malloc_arrayN(coarse_mesh->totpoly,
+ sizeof(*ctx->face_ptex_offset),
+ "face_ptex_offset");
+ /* Fill in offsets. */
+ int vertex_offset = 0;
+ int edge_offset = 0;
+ int polygon_offset = 0;
+ int face_ptex_offset = 0;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int ptex_face_resolution = ptex_face_resolution_get(
+ coarse_poly, ctx->settings->resolution);
+ const int ptex_face_resolution2 =
+ ptex_face_resolution * ptex_face_resolution;
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
+ ctx->subdiv_edge_offset[poly_index] = edge_offset;
+ ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
+ ctx->face_ptex_offset[poly_index] = face_ptex_offset;
+ vertex_offset += num_ptex_faces_per_poly * ptex_face_resolution2;
+ edge_offset += num_ptex_faces_per_poly *
+ num_edges_per_ptex_face_get(ptex_face_resolution);
+ polygon_offset +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(ptex_face_resolution);
+ face_ptex_offset += num_ptex_faces_per_poly;
+ }
+ ctx->num_subdiv_vertices = vertex_offset;
+ ctx->num_subdiv_edges = edge_offset;
+ ctx->num_subdiv_polygons = polygon_offset;
+ ctx->num_subdiv_loops = 4 * ctx->num_subdiv_polygons;
+}
+
+static void subdiv_mesh_ctx_init(SubdivMeshContext *ctx)
+{
+ subdiv_mesh_ctx_init_offsets(ctx);
+}
+
+static void subdiv_mesh_ctx_init_result(SubdivMeshContext *ctx)
+{
+ subdiv_mesh_ctx_cache_custom_data_layers(ctx);
+}
+
+static void subdiv_mesh_ctx_free(SubdivMeshContext *ctx)
+{
+ MEM_freeN(ctx->subdiv_vertex_offset);
+ MEM_freeN(ctx->subdiv_edge_offset);
+ MEM_freeN(ctx->face_ptex_offset);
+}
+
+/* =============================================================================
+ * Loop custom data copy helpers.
+ */
+
typedef struct LoopsOfPtex {
/* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
const MLoop *first_loop;
@@ -112,6 +244,10 @@ static void loops_of_ptex_get(
}
}
+/* =============================================================================
+ * Edge custom data copy helpers.
+ */
+
typedef struct EdgesOfPtex {
/* First edge of the ptex, starts at ptex (0, 0) and goes in u direction. */
const MEdge *first_edge;
@@ -145,6 +281,10 @@ static void edges_of_ptex_get(
}
}
+/* =============================================================================
+ * Vertex custom data interpolation helpers.
+ */
+
/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
* exception cases all over the code.
*/
@@ -285,6 +425,10 @@ static void vertex_interpolation_end(
}
}
+/* =============================================================================
+ * Loop custom data interpolation helpers.
+ */
+
typedef struct LoopsForInterpolation {
/* This field points to a loop data which is to be used for interpolation.
* The idea is to avoid unnecessary allocations for regular faces, where
@@ -413,6 +557,10 @@ static
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list