1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2020 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include "multires_reshape.h"
25
26 #include "MEM_guardedalloc.h"
27
28 #include "DNA_mesh_types.h"
29 #include "DNA_meshdata_types.h"
30 #include "DNA_modifier_types.h"
31 #include "DNA_object_types.h"
32
33 #include "BLI_listbase.h"
34 #include "BLI_math_vector.h"
35
36 #include "BKE_customdata.h"
37 #include "BKE_lib_id.h"
38 #include "BKE_mesh.h"
39 #include "BKE_mesh_mapping.h"
40 #include "BKE_mesh_runtime.h"
41 #include "BKE_multires.h"
42 #include "BKE_subdiv_eval.h"
43
44 #include "DEG_depsgraph_query.h"
45
multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext * reshape_context)46 void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context)
47 {
48 Mesh *base_mesh = reshape_context->base_mesh;
49 const MLoop *mloop = base_mesh->mloop;
50 MVert *mvert = base_mesh->mvert;
51 for (int loop_index = 0; loop_index < base_mesh->totloop; ++loop_index) {
52 const MLoop *loop = &mloop[loop_index];
53 MVert *vert = &mvert[loop->v];
54
55 GridCoord grid_coord;
56 grid_coord.grid_index = loop_index;
57 grid_coord.u = 1.0f;
58 grid_coord.v = 1.0f;
59
60 float P[3];
61 float tangent_matrix[3][3];
62 multires_reshape_evaluate_limit_at_grid(reshape_context, &grid_coord, P, tangent_matrix);
63
64 ReshapeConstGridElement grid_element = multires_reshape_orig_grid_element_for_grid_coord(
65 reshape_context, &grid_coord);
66 float D[3];
67 mul_v3_m3v3(D, tangent_matrix, grid_element.displacement);
68
69 add_v3_v3v3(vert->co, P, D);
70 }
71 }
72
73 /* Assumes no is normalized; return value's sign is negative if v is on the other side of the
74 * plane. */
v3_dist_from_plane(const float v[3],const float center[3],const float no[3])75 static float v3_dist_from_plane(const float v[3], const float center[3], const float no[3])
76 {
77 float s[3];
78 sub_v3_v3v3(s, v, center);
79 return dot_v3v3(s, no);
80 }
81
multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext * reshape_context)82 void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context)
83 {
84 if (reshape_context->mmd->simple) {
85 /* Simple subdivisions does not move base mesh verticies, so no refitting is needed. */
86 return;
87 }
88
89 Mesh *base_mesh = reshape_context->base_mesh;
90
91 MeshElemMap *pmap;
92 int *pmap_mem;
93 BKE_mesh_vert_poly_map_create(&pmap,
94 &pmap_mem,
95 base_mesh->mpoly,
96 base_mesh->mloop,
97 base_mesh->totvert,
98 base_mesh->totpoly,
99 base_mesh->totloop);
100
101 float(*origco)[3] = MEM_calloc_arrayN(
102 base_mesh->totvert, sizeof(float[3]), "multires apply base origco");
103 for (int i = 0; i < base_mesh->totvert; i++) {
104 copy_v3_v3(origco[i], base_mesh->mvert[i].co);
105 }
106
107 for (int i = 0; i < base_mesh->totvert; i++) {
108 float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3];
109
110 /* Don't adjust vertices not used by at least one poly. */
111 if (!pmap[i].count) {
112 continue;
113 }
114
115 /* Find center. */
116 int tot = 0;
117 for (int j = 0; j < pmap[i].count; j++) {
118 const MPoly *p = &base_mesh->mpoly[pmap[i].indices[j]];
119
120 /* This double counts, not sure if that's bad or good. */
121 for (int k = 0; k < p->totloop; k++) {
122 const int vndx = base_mesh->mloop[p->loopstart + k].v;
123 if (vndx != i) {
124 add_v3_v3(center, origco[vndx]);
125 tot++;
126 }
127 }
128 }
129 mul_v3_fl(center, 1.0f / tot);
130
131 /* Find normal. */
132 for (int j = 0; j < pmap[i].count; j++) {
133 const MPoly *p = &base_mesh->mpoly[pmap[i].indices[j]];
134 MPoly fake_poly;
135 MLoop *fake_loops;
136 float(*fake_co)[3];
137 float no[3];
138
139 /* Set up poly, loops, and coords in order to call BKE_mesh_calc_poly_normal_coords(). */
140 fake_poly.totloop = p->totloop;
141 fake_poly.loopstart = 0;
142 fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops");
143 fake_co = MEM_malloc_arrayN(p->totloop, sizeof(float[3]), "fake_co");
144
145 for (int k = 0; k < p->totloop; k++) {
146 const int vndx = base_mesh->mloop[p->loopstart + k].v;
147
148 fake_loops[k].v = k;
149
150 if (vndx == i) {
151 copy_v3_v3(fake_co[k], center);
152 }
153 else {
154 copy_v3_v3(fake_co[k], origco[vndx]);
155 }
156 }
157
158 BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops, (const float(*)[3])fake_co, no);
159 MEM_freeN(fake_loops);
160 MEM_freeN(fake_co);
161
162 add_v3_v3(avg_no, no);
163 }
164 normalize_v3(avg_no);
165
166 /* Push vertex away from the plane. */
167 const float dist = v3_dist_from_plane(base_mesh->mvert[i].co, center, avg_no);
168 copy_v3_v3(push, avg_no);
169 mul_v3_fl(push, dist);
170 add_v3_v3(base_mesh->mvert[i].co, push);
171 }
172
173 MEM_freeN(origco);
174 MEM_freeN(pmap);
175 MEM_freeN(pmap_mem);
176
177 /* Vertices were moved around, need to update normals after all the vertices are updated
178 * Probably this is possible to do in the loop above, but this is rather tricky because
179 * we don't know all needed vertices' coordinates there yet. */
180 BKE_mesh_calc_normals(base_mesh);
181 }
182
multires_reshape_apply_base_refine_from_base(MultiresReshapeContext * reshape_context)183 void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
184 {
185 BKE_subdiv_eval_refine_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
186 }
187
multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext * reshape_context)188 void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context)
189 {
190 struct Depsgraph *depsgraph = reshape_context->depsgraph;
191 Object *object = reshape_context->object;
192 MultiresModifierData *mmd = reshape_context->mmd;
193 BLI_assert(depsgraph != NULL);
194 BLI_assert(object != NULL);
195 BLI_assert(mmd != NULL);
196
197 float(*deformed_verts)[3] = BKE_multires_create_deformed_base_mesh_vert_coords(
198 depsgraph, object, mmd, NULL);
199
200 BKE_subdiv_eval_refine_from_mesh(
201 reshape_context->subdiv, reshape_context->base_mesh, deformed_verts);
202
203 MEM_freeN(deformed_verts);
204 }
205