Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h73
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/subdiv.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement.c46
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement_multires.c440
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c66
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c291
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c8
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c6
9 files changed, 903 insertions, 31 deletions
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index c4628cb9da7..887eff6e7dc 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -29,9 +29,12 @@
#include "BLI_sys_types.h"
struct Mesh;
+struct MultiresModifierData;
+struct Object;
struct OpenSubdiv_Converter;
struct OpenSubdiv_Evaluator;
struct OpenSubdiv_TopologyRefiner;
+struct Subdiv;
/** \file BKE_subdiv.h
* \ingroup bke
@@ -92,22 +95,47 @@ typedef struct SubdivStats {
double begin_timestamp_[NUM_SUBDIV_STATS_VALUES];
} SubdivStats;
+/* Functor which evaluates dispalcement at a given (u, v) of given ptex face. */
+typedef struct SubdivDisplacement {
+ /* Return displacement which is to be added to the original coordinate.
+ *
+ * NOTE: This function is supposed to return "continuous" displacement for
+ * each pf PTex faces created for special (non-quad) polygon. This means,
+ * if displacement is stored on per-corner manner (like MDisps for multires)
+ * this is up the displacement implementation to average boundaries of the
+ * displacement grids if needed.
+ *
+ * Averaging of displacement for vertices created for over coarse vertices
+ * and edges is done by subdiv code.
+ */
+ void (*eval_displacement)(struct SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3]);
+
+ /* Free the data, not the evaluator itself. */
+ void (*free)(struct SubdivDisplacement *displacement);
+
+ void *user_data;
+} SubdivDisplacement;
+
typedef struct Subdiv {
/* Settings this subdivision surface is created for.
*
* It is read-only after assignment in BKE_subdiv_new_from_FOO().
*/
SubdivSettings settings;
-
/* 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.
*/
struct OpenSubdiv_TopologyRefiner *topology_refiner;
-
/* CPU side evaluator. */
struct OpenSubdiv_Evaluator *evaluator;
-
+ /* Optional displacement evaluator. */
+ struct SubdivDisplacement *displacement_evaluator;
+ /* Statistics for debugging. */
SubdivStats stats;
} Subdiv;
@@ -148,29 +176,49 @@ void BKE_subdiv_eval_limit_point(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3]);
+ float r_P[3]);
void BKE_subdiv_eval_limit_point_and_derivatives(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3], float dPdu[3], float dPdv[3]);
+ float r_P[3], float r_dPdu[3], float r_dPdv[3]);
void BKE_subdiv_eval_limit_point_and_normal(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3], float N[3]);
+ float r_P[3], float r_N[3]);
void BKE_subdiv_eval_limit_point_and_short_normal(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3], short N[3]);
+ float r_P[3], short r_N[3]);
void BKE_subdiv_eval_face_varying(
Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
const float u, const float v,
- float varying[2]);
+ float r_varying[2]);
+
+/* NOTE: Expects derivatives to be correct.
+ *
+ * TODO(sergey): This is currently used together with
+ * BKE_subdiv_eval_final_point() which cas easily evaluate derivatives.
+ * Would be nice to have dispalcement evaluation function which does not require
+ * knowing derivatives ahead of a time.
+ */
+void BKE_subdiv_eval_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3]);
+
+void BKE_subdiv_eval_final_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3]);
/* Patch queries at given resolution.
*
@@ -220,4 +268,13 @@ struct Mesh *BKE_subdiv_to_mesh(
const SubdivToMeshSettings *settings,
const struct Mesh *coarse_mesh);
+/* ============================ DISPLACEMENT API ============================ */
+
+void BKE_subdiv_displacement_attach_from_multires(
+ Subdiv *subdiv,
+ const struct Object *object,
+ const struct MultiresModifierData *mmd);
+
+void BKE_subdiv_displacement_detach(Subdiv *subdiv);
+
#endif /* __BKE_SUBDIV_H__ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 646665cdec2..aeb4830127d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -194,6 +194,8 @@ set(SRC
intern/subdiv.c
intern/subdiv_converter.c
intern/subdiv_converter_mesh.c
+ intern/subdiv_displacement.c
+ intern/subdiv_displacement_multires.c
intern/subdiv_eval.c
intern/subdiv_mesh.c
intern/subdiv_stats.c
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 4f630e8c38c..f847d62018a 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -90,6 +90,7 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
subdiv->settings = *settings;
subdiv->topology_refiner = osd_topology_refiner;
subdiv->evaluator = NULL;
+ subdiv->displacement_evaluator = NULL;
BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
subdiv->stats = stats;
return subdiv;
@@ -116,5 +117,6 @@ void BKE_subdiv_free(Subdiv *subdiv)
if (subdiv->topology_refiner != NULL) {
openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
}
+ BKE_subdiv_displacement_detach(subdiv);
MEM_freeN(subdiv);
}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement.c b/source/blender/blenkernel/intern/subdiv_displacement.c
new file mode 100644
index 00000000000..a6af6f45e59
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_displacement.c
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_displacement.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+void BKE_subdiv_displacement_detach(Subdiv *subdiv)
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ if (subdiv->displacement_evaluator->free != NULL) {
+ subdiv->displacement_evaluator->free(subdiv->displacement_evaluator);
+ }
+ MEM_freeN(subdiv->displacement_evaluator);
+ subdiv->displacement_evaluator = NULL;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
new file mode 100644
index 00000000000..ce42fa16438
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
@@ -0,0 +1,440 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_displacement.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+
+#include "MEM_guardedalloc.h"
+
+typedef struct PolyCornerIndex {
+ int poly_index;
+ int corner;
+} PolyCornerIndex;
+
+typedef struct MultiresDisplacementData {
+ int grid_size;
+ const MPoly *mpoly;
+ const MDisps *mdisps;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex.
+ */
+ PolyCornerIndex *ptex_poly_corner;
+} MultiresDisplacementData;
+
+/* Denotes which grid to use to average value of the displacement read from the
+ * grid which corresponds to the ptex face.
+ */
+typedef enum eAverageWith {
+ AVERAGE_WITH_NONE,
+ AVERAGE_WITH_ALL,
+ AVERAGE_WITH_PREV,
+ AVERAGE_WITH_NEXT,
+} eAverageWith;
+
+/* Coordinates within grid has different convention from PTex coordinates.
+ * This function converts the latter ones to former.
+ */
+BLI_INLINE void ptex_uv_to_grid_uv(const float ptex_u, const float ptex_v,
+ float *r_grid_u, float *r_grid_v)
+{
+ *r_grid_u = 1.0f - ptex_v;
+ *r_grid_v = 1.0f - ptex_u;
+}
+
+/* Simplified version of mdisp_rot_face_to_crn, only handles quad and
+ * works in normalized coordinates.
+ *
+ * NOTE: Output coordinates are in ptex coordinates.
+ */
+BLI_INLINE int rotate_quad_to_corner(const float u, const float v,
+ float *r_u, float *r_v)
+{
+ int corner;
+ if (u <= 0.5f && v <= 0.5f) {
+ corner = 0;
+ *r_u = 2.0f * u;
+ *r_v = 2.0f * v;
+ }
+ else if (u > 0.5f && v <= 0.5f) {
+ corner = 1;
+ *r_u = 2.0f * v;
+ *r_v = 2.0f * (1.0f - u);
+ }
+ else if (u > 0.5f && v > 0.5f) {
+ corner = 2;
+ *r_u = 2.0f * (1.0f - u);
+ *r_v = 2.0f * (1.0f - v);
+ }
+ else if (u <= 0.5f && v >= 0.5f) {
+ corner = 3;
+ *r_u = 2.0f * (1.0f - v);
+ *r_v = 2.0f * u;
+ }
+ else {
+ BLI_assert(!"Unexpected corner configuration");
+ }
+ return corner;
+}
+
+static int displacement_get_grid_and_coord(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const float u, const float v,
+ const MDisps **r_displacement_grid,
+ float *grid_u, float *grid_v)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_displacement_grid = &data->mdisps[start_grid_index + corner];
+ ptex_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_displacement_grid = &data->mdisps[start_grid_index];
+ ptex_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
+}
+
+static const MDisps *displacement_get_next_grid(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner
+ : poly_corner->corner;
+ const int next_corner = (effective_corner + 1) % poly->totloop;
+ return &data->mdisps[poly->loopstart + next_corner];
+}
+
+static const MDisps *displacement_get_prev_grid(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner
+ : poly_corner->corner;
+ const int prev_corner =
+ (effective_corner - 1 + poly->totloop) % poly->totloop;
+ return &data->mdisps[poly->loopstart + prev_corner];
+}
+
+/* NOTE: Derivatives are in ptex face space. */
+BLI_INLINE void construct_tangent_matrix(float tangent_matrix[3][3],
+ const float dPdu[3],
+ const float dPdv[3],
+ const int corner)
+{
+ if (corner == 0) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 1) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 2) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ }
+ else if (corner == 3) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ }
+ cross_v3_v3v3(tangent_matrix[2], dPdu, dPdv);
+ normalize_v3(tangent_matrix[0]);
+ normalize_v3(tangent_matrix[1]);
+ normalize_v3(tangent_matrix[2]);
+}
+
+BLI_INLINE eAverageWith read_displacement_grid(
+ const MDisps *displacement_grid,
+ const int grid_size,
+ const float grid_u, const float grid_v,
+ float r_tangent_D[3])
+{
+ if (displacement_grid->disps == NULL) {
+ zero_v3(r_tangent_D);
+ return AVERAGE_WITH_NONE;
+ }
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]);
+ if (x == 0 && y == 0) {
+ return AVERAGE_WITH_ALL;
+ }
+ else if (x == 0) {
+ return AVERAGE_WITH_PREV;
+ }
+ else if (y == 0) {
+ return AVERAGE_WITH_NEXT;
+ }
+ return AVERAGE_WITH_NONE;
+}
+
+static void average_with_all(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float UNUSED(grid_u), const float UNUSED(grid_v),
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ for (int current_corner = 0;
+ current_corner < poly->totloop;
+ current_corner++)
+ {
+ if (current_corner == corner) {
+ continue;
+ }
+ const MDisps *displacement_grid =
+ &data->mdisps[poly->loopstart + current_corner];
+ const float *current_tangent_D = displacement_grid->disps[0];
+ r_tangent_D[2] += current_tangent_D[2];
+ }
+ r_tangent_D[2] /= (float)poly->totloop;
+}
+
+static void average_with_next(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float grid_u, const float UNUSED(grid_v),
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ const MDisps *next_displacement_grid = displacement_get_next_grid(
+ displacement, ptex_face_index, corner);
+ float next_tangent_D[3];
+ read_displacement_grid(next_displacement_grid, grid_size,
+ 0.0f, grid_u,
+ next_tangent_D);
+ r_tangent_D[2] += next_tangent_D[2];
+ r_tangent_D[2] *= 0.5f;
+}
+
+static void average_with_prev(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float UNUSED(grid_u), const float grid_v,
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ const MDisps *prev_displacement_grid = displacement_get_prev_grid(
+ displacement, ptex_face_index, corner);
+ float prev_tangent_D[3];
+ read_displacement_grid(prev_displacement_grid, grid_size,
+ grid_v, 0.0f,
+ prev_tangent_D);
+ r_tangent_D[2] += prev_tangent_D[2];
+ r_tangent_D[2] *= 0.5f;
+}
+
+static void average_displacement(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ eAverageWith average_with,
+ const float grid_u, const float grid_v,
+ float r_tangent_D[3])
+{
+ switch (average_with) {
+ case AVERAGE_WITH_ALL:
+ average_with_all(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_PREV:
+ average_with_prev(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_NEXT:
+ average_with_next(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_NONE:
+ break;
+ }
+}
+
+static void eval_displacement(SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ /* Get displacement in tangent space. */
+ const MDisps *displacement_grid;
+ float grid_u, grid_v;
+ int corner = displacement_get_grid_and_coord(displacement,
+ ptex_face_index, u, v,
+ &displacement_grid,
+ &grid_u, &grid_v);
+ /* Read displacement from the current displacement grid and see if any
+ * averaging is needed.
+ */
+ float tangent_D[3];
+ eAverageWith average_with =
+ read_displacement_grid(displacement_grid, grid_size,
+ grid_u, grid_v,
+ tangent_D);
+ average_displacement(displacement,
+ ptex_face_index, corner,
+ average_with, grid_u, grid_v,
+ tangent_D);
+ /* Convert it to the object space. */
+ float tangent_matrix[3][3];
+ construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner);
+ mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
+}
+
+static void free_displacement(SubdivDisplacement *displacement)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
+}
+
+/* TODO(sergey): This seems to be generally used information, which almost
+ * worth adding to a subdiv itself, with possible cache of the value.
+ */
+static int count_num_ptex_faces(const Mesh *mesh)
+{
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
+}
+
+static void displacement_data_init_mapping(SubdivDisplacement *displacement,
+ const Object *object)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const Mesh *mesh = (Mesh *)object->data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
+ sizeof(*data->ptex_poly_corner),
+ "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
+}
+
+static void displacement_init_data(SubdivDisplacement *displacement,
+ const Object *object,
+ const MultiresModifierData *mmd)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ Mesh *mesh = (Mesh *)object->data;
+ data->grid_size = (1 << (mmd->totlvl - 1)) + 1;
+ data->mpoly = mesh->mpoly;
+ data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ displacement_data_init_mapping(displacement, object);
+}
+
+static void displacement_init_functions(SubdivDisplacement *displacement)
+{
+ displacement->eval_displacement = eval_displacement;
+ displacement->free = free_displacement;
+}
+
+void BKE_subdiv_displacement_attach_from_multires(
+ Subdiv *subdiv,
+ const Object *object,
+ const MultiresModifierData *mmd)
+{
+ if (object->type != OB_MESH) {
+ BLI_assert(!"Should never be called for non-mesh objects");
+ return;
+ }
+ /* Make sure we dont' have previously assigned displacement. */
+ BKE_subdiv_displacement_detach(subdiv);
+ /* Allocate all required memory. */
+ SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement),
+ "multires displacement");
+ displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
+ "multires displacement data");
+ displacement_init_data(displacement, object, mmd);
+ displacement_init_functions(displacement);
+ /* Finish. */
+ subdiv->displacement_evaluator = displacement;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index e3754655ea6..7b234683102 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -164,53 +164,53 @@ void BKE_subdiv_eval_limit_point(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3])
+ float r_P[3])
{
BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
ptex_face_index,
u, v,
- P, NULL, NULL);
+ r_P, NULL, NULL);
}
void BKE_subdiv_eval_limit_point_and_derivatives(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3], float dPdu[3], float dPdv[3])
+ float r_P[3], float r_dPdu[3], float r_dPdv[3])
{
subdiv->evaluator->evaluateLimit(subdiv->evaluator,
ptex_face_index,
u, v,
- P, dPdu, dPdv);
+ r_P, r_dPdu, r_dPdv);
}
void BKE_subdiv_eval_limit_point_and_normal(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3], float N[3])
+ float r_P[3], float r_N[3])
{
float dPdu[3], dPdv[3];
BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
ptex_face_index,
u, v,
- P, dPdu, dPdv);
- cross_v3_v3v3(N, dPdu, dPdv);
- normalize_v3(N);
+ r_P, dPdu, dPdv);
+ cross_v3_v3v3(r_N, dPdu, dPdv);
+ normalize_v3(r_N);
}
void BKE_subdiv_eval_limit_point_and_short_normal(
Subdiv *subdiv,
const int ptex_face_index,
const float u, const float v,
- float P[3], short N[3])
+ float r_P[3], short r_N[3])
{
float N_float[3];
BKE_subdiv_eval_limit_point_and_normal(subdiv,
ptex_face_index,
u, v,
- P, N_float);
- normal_float_to_short_v3(N, N_float);
+ r_P, N_float);
+ normal_float_to_short_v3(r_N, N_float);
}
void BKE_subdiv_eval_face_varying(
@@ -218,13 +218,53 @@ void BKE_subdiv_eval_face_varying(
const int face_varying_channel,
const int ptex_face_index,
const float u, const float v,
- float face_varying[2])
+ float r_face_varying[2])
{
subdiv->evaluator->evaluateFaceVarying(subdiv->evaluator,
face_varying_channel,
ptex_face_index,
u, v,
- face_varying);
+ r_face_varying);
+}
+
+void BKE_subdiv_eval_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3])
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ zero_v3(r_D);
+ return;
+ }
+ subdiv->displacement_evaluator->eval_displacement(
+ subdiv->displacement_evaluator,
+ ptex_face_index,
+ u, v,
+ dPdu, dPdv,
+ r_D);
+}
+
+void BKE_subdiv_eval_final_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3])
+{
+ if (subdiv->displacement_evaluator) {
+ float dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv,
+ ptex_face_index, u, v,
+ dPdu, dPdv,
+ D);
+ add_v3_v3(r_P, D);
+ }
+ else {
+ BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
+ }
}
/* =================== Patch queries at given resolution =================== */
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 3d948dc9508..c8f67c2a893 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -668,6 +668,50 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
}
/* =============================================================================
+ * Helper evaluation functions.
+ */
+
+static void eval_final_point_and_vertex_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3])
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv, ptex_face_index, u, v, r_P, r_N);
+ }
+ else {
+ BKE_subdiv_eval_final_point(
+ subdiv, ptex_face_index, u, v, r_P);
+ }
+}
+
+/* =============================================================================
+ * Displacement helpers
+ */
+
+static void subdiv_accumulate_vertex_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ MVert *subdiv_vert)
+{
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv,
+ ptex_face_index, u, v,
+ dPdu, dPdv,
+ D);
+ add_v3_v3(subdiv_vert->co, D);
+ if (subdiv_vert->flag & ME_VERT_TMP_TAG) {
+ mul_v3_fl(subdiv_vert->co, 0.5f);
+ }
+ subdiv_vert->flag |= ME_VERT_TMP_TAG;
+}
+
+/* =============================================================================
* Vertex subdivision process.
*/
@@ -682,6 +726,7 @@ static void subdiv_vertex_data_copy(
Mesh *subdiv_mesh = ctx->subdiv_mesh;
const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert;
const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert;
+ subdiv_vertex->flag &= ~ME_VERT_TMP_TAG;
CustomData_copy_data(&coarse_mesh->vdata,
&ctx->subdiv_mesh->vdata,
coarse_vertex_index,
@@ -700,6 +745,7 @@ static void subdiv_vertex_data_interpolate(
u * (1.0f - v),
u * v,
(1.0f - u) * v};
+ subdiv_vertex->flag &= ~ME_VERT_TMP_TAG;
CustomData_interp(vertex_interpolation->vertex_data,
&ctx->subdiv_mesh->vdata,
vertex_interpolation->vertex_indices,
@@ -711,6 +757,7 @@ static void subdiv_vertex_data_interpolate(
}
}
+
/* Evaluation of corner vertices. They are coming from coarse vertices. */
static void subdiv_evaluate_corner_vertices_regular(
@@ -740,12 +787,19 @@ static void subdiv_evaluate_corner_vertices_regular(
const MVert *coarse_vert = &coarse_mvert[coarse_loop->v];
MVert *subdiv_vert = &subdiv_mvert[
ctx->vertices_corner_offset + coarse_loop->v];
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data fro original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
BKE_subdiv_eval_limit_point_and_short_normal(
subdiv,
ptex_face_index,
weights[corner][0], weights[corner][1],
subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
}
}
@@ -775,12 +829,19 @@ static void subdiv_evaluate_corner_vertices_special(
const MVert *coarse_vert = &coarse_mvert[coarse_loop->v];
MVert *subdiv_vert = &subdiv_mvert[
ctx->vertices_corner_offset + coarse_loop->v];
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data fro original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
BKE_subdiv_eval_limit_point_and_short_normal(
subdiv,
ptex_face_index,
0.0f, 0.0f,
subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
}
}
@@ -795,6 +856,76 @@ static void subdiv_evaluate_corner_vertices(SubdivMeshContext *ctx,
}
}
+static void subdiv_displace_corner_vertices_regular(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ const float weights[4][2] = {{0.0f, 0.0f},
+ {1.0f, 0.0f},
+ {1.0f, 1.0f},
+ {0.0f, 1.0f}};
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_corner_offset + coarse_loop->v];
+ const float u = weights[corner][0];
+ const float v = weights[corner][1];
+ subdiv_accumulate_vertex_displacement(
+ subdiv, ptex_face_index, u, v, subdiv_vert);
+ }
+}
+
+static void subdiv_displace_corner_vertices_special(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_corner_offset + coarse_loop->v];
+ subdiv_accumulate_vertex_displacement(
+ subdiv, ptex_face_index, 0.0f, 0.0f, subdiv_vert);
+ }
+}
+
+static void subdiv_displace_corner_vertices(SubdivMeshContext *ctx)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_displace_corner_vertices_regular(ctx, coarse_poly);
+ }
+ else {
+ subdiv_displace_corner_vertices_special(ctx, coarse_poly);
+ }
+ }
+}
+
/* Evaluation of edge vertices. They are coming from coarse edges. */
static void subdiv_evaluate_edge_vertices_regular(
@@ -851,6 +982,11 @@ static void subdiv_evaluate_edge_vertices_regular(
u = (corner == 1) ? 1.0f : 0.0f;
v = fac;
}
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data fro original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
subdiv_vertex_data_interpolate(ctx,
subdiv_vert,
vertex_interpolation,
@@ -860,6 +996,8 @@ static void subdiv_evaluate_edge_vertices_regular(
ptex_face_index,
u, v,
subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
}
}
}
@@ -913,6 +1051,11 @@ static void subdiv_evaluate_edge_vertices_special(
vertex_index++, subdiv_vert += veretx_delta)
{
float u = vertex_index * inv_ptex_resolution_1;
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data fro original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
subdiv_vertex_data_interpolate(ctx,
subdiv_vert,
vertex_interpolation,
@@ -922,6 +1065,8 @@ static void subdiv_evaluate_edge_vertices_special(
ptex_face_index,
u, 0.0f,
subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
}
const int next_ptex_face_index =
ptex_face_start_index + (corner + 1) % coarse_poly->totloop;
@@ -930,6 +1075,11 @@ static void subdiv_evaluate_edge_vertices_special(
vertex_index++, subdiv_vert += veretx_delta)
{
float v = 1.0f - vertex_index * inv_ptex_resolution_1;
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data fro original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
subdiv_vertex_data_interpolate(ctx,
subdiv_vert,
vertex_interpolation,
@@ -939,6 +1089,8 @@ static void subdiv_evaluate_edge_vertices_special(
next_ptex_face_index,
0.0f, v,
subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
}
}
}
@@ -958,6 +1110,129 @@ static void subdiv_evaluate_edge_vertices(
}
}
+static void subdiv_displace_edge_vertices_regular(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->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;
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge];
+ for (int vertex_index = 0;
+ vertex_index < num_subdiv_vertices_per_coarse_edge;
+ vertex_index++, subdiv_vert++)
+ {
+ float fac = (vertex_index + 1) * inv_resolution_1;
+ if (flip) {
+ fac = 1.0f - fac;
+ }
+ if (corner >= 2) {
+ fac = 1.0f - fac;
+ }
+ float u, v;
+ if ((corner & 1) == 0) {
+ u = fac;
+ v = (corner == 2) ? 1.0f : 0.0f;
+ }
+ else {
+ u = (corner == 1) ? 1.0f : 0.0f;
+ v = fac;
+ }
+ subdiv_accumulate_vertex_displacement(
+ subdiv, ptex_face_index, u, v, subdiv_vert);
+ }
+ }
+}
+
+static void subdiv_displace_edge_vertices_special(
+ SubdivMeshContext *ctx,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(num_vertices_per_ptex_edge - 1);
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
+ int ptex_face_index = ptex_face_start_index;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ MVert *subdiv_vert = &subdiv_mvert[
+ ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge];
+ int veretx_delta = 1;
+ if (flip) {
+ subdiv_vert += num_subdiv_vertices_per_coarse_edge - 1;
+ veretx_delta = -1;
+ }
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge;
+ vertex_index++, subdiv_vert += veretx_delta)
+ {
+ float u = vertex_index * inv_ptex_resolution_1;
+ subdiv_accumulate_vertex_displacement(
+ subdiv, ptex_face_index, u, 0.0f, subdiv_vert);
+ }
+ const int next_ptex_face_index =
+ ptex_face_start_index + (corner + 1) % coarse_poly->totloop;
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge - 1;
+ vertex_index++, subdiv_vert += veretx_delta)
+ {
+ float v = 1.0f - vertex_index * inv_ptex_resolution_1;
+ subdiv_accumulate_vertex_displacement(
+ subdiv, next_ptex_face_index, 0.0f, v, subdiv_vert);
+ }
+ }
+}
+static void subdiv_displace_edge_vertices(SubdivMeshContext *ctx)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_displace_edge_vertices_regular(ctx, coarse_poly);
+ }
+ else {
+ subdiv_displace_edge_vertices_special(ctx, coarse_poly);
+ }
+ }
+}
+
/* Evaluation of inner vertices, they are coming from ptex patches. */
static void subdiv_evaluate_inner_vertices_regular(
@@ -988,7 +1263,7 @@ static void subdiv_evaluate_inner_vertices_regular(
subdiv_vert,
vertex_interpolation,
u, v);
- BKE_subdiv_eval_limit_point_and_short_normal(
+ eval_final_point_and_vertex_normal(
subdiv,
ptex_face_index,
u, v,
@@ -1024,7 +1299,7 @@ static void subdiv_evaluate_inner_vertices_special(
subdiv_vert,
vertex_interpolation,
1.0f, 1.0f);
- BKE_subdiv_eval_limit_point_and_short_normal(
+ eval_final_point_and_vertex_normal(
subdiv,
ptex_face_index,
1.0f, 1.0f,
@@ -1048,7 +1323,7 @@ static void subdiv_evaluate_inner_vertices_special(
subdiv_vert,
vertex_interpolation,
u, v);
- BKE_subdiv_eval_limit_point_and_short_normal(
+ eval_final_point_and_vertex_normal(
subdiv,
ptex_face_index,
u, v,
@@ -2415,9 +2690,14 @@ Mesh *BKE_subdiv_to_mesh(
ctx.subdiv_mesh = result;
subdiv_mesh_ctx_init_result(&ctx);
/* Multi-threaded evaluation. */
- ParallelRangeSettings parallel_range_settings;
BKE_subdiv_stats_begin(&subdiv->stats,
SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ /* Single threaded passes to average displacement on the corner vertices
+ * and boundary edges.
+ */
+ subdiv_displace_corner_vertices(&ctx);
+ subdiv_displace_edge_vertices(&ctx);
+ ParallelRangeSettings parallel_range_settings;
BLI_parallel_range_settings_defaults(&parallel_range_settings);
BLI_task_parallel_range(0, coarse_mesh->totpoly,
&ctx,
@@ -2439,5 +2719,8 @@ Mesh *BKE_subdiv_to_mesh(
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
// BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ if (subdiv->displacement_evaluator != NULL) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index ca60dceb052..4379e6748cc 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -173,11 +173,14 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
const ModifierEvalContext *ctx,
Mesh *mesh)
{
+ Object *object = ctx->object;
Mesh *result = mesh;
MultiresModifierData *mmd = (MultiresModifierData *)md;
SubdivSettings subdiv_settings;
subdiv_settings_init(&subdiv_settings, mmd);
- if (subdiv_settings.level == 0) {
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, mmd, ctx);
+ if (subdiv_settings.level == 0 || mesh_settings.resolution < 3) {
/* NOTE: Shouldn't really happen, is supposed to be catched by
* isDisabled() callback.
*/
@@ -189,8 +192,7 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
/* Happens on bad topology, ut also on empty input mesh. */
return result;
}
- SubdivToMeshSettings mesh_settings;
- subdiv_mesh_settings_init(&mesh_settings, mmd, ctx);
+ BKE_subdiv_displacement_attach_from_multires(subdiv, object, mmd);
result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
/* TODO(sergey): Cache subdiv somehow. */
// BKE_subdiv_stats_print(&subdiv->stats);
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 38683cff42a..a6e85bfb813 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -185,7 +185,9 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
SubsurfModifierData *smd = (SubsurfModifierData *) md;
SubdivSettings subdiv_settings;
subdiv_settings_init(&subdiv_settings, smd);
- if (subdiv_settings.level == 0) {
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
+ if (subdiv_settings.level == 0 || mesh_settings.resolution < 3) {
/* NOTE: Shouldn't really happen, is supposed to be catched by
* isDisabled() callback.
*/
@@ -197,8 +199,6 @@ static Mesh *applyModifier_subdiv(ModifierData *md,
/* Happens on bad topology, ut also on empty input mesh. */
return result;
}
- SubdivToMeshSettings mesh_settings;
- subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
/* TODO(sergey): Cache subdiv somehow. */
// BKE_subdiv_stats_print(&subdiv->stats);