Blender V5.0
mesh_subdivision.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "scene/attribute.h"
6#include "scene/mesh.h"
7
9#include "subd/osd.h"
10#include "subd/patch.h"
11#include "subd/split.h"
12
13#include "util/algorithm.h"
14#include "util/vector.h"
15
17
19{
20 /* reset the number of subdivision vertices, in case the Mesh was not cleared
21 * between calls or data updates */
22 num_subd_added_verts = 0;
23
24#ifdef WITH_OPENSUBDIV
25 OsdMesh osd_mesh(*this);
26 OsdData osd_data;
27
28 if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
29 if (get_num_subd_faces()) {
30 osd_data.build(osd_mesh);
31 }
32 }
33 else
34#endif
35 {
36 /* force linear subdivision if OpenSubdiv is unavailable to avoid
37 * falling into catmull-clark code paths by accident
38 */
39 subdivision_type = SUBDIVISION_LINEAR;
40 }
41
42 /* count patches */
43 const int num_faces = get_num_subd_faces();
44 int num_patches = 0;
45 for (int f = 0; f < num_faces; f++) {
46 SubdFace face = get_subd_face(f);
47
48 if (face.is_quad()) {
49 num_patches++;
50 }
51 else {
52 num_patches += face.num_corners;
53 }
54 }
55
56 /* build patches from faces */
57#ifdef WITH_OPENSUBDIV
58 if (subdivision_type == SUBDIVISION_CATMULL_CLARK) {
59 vector<OsdPatch> osd_patches(num_patches, OsdPatch(osd_data));
60 OsdPatch *patch = osd_patches.data();
61
62 for (int f = 0; f < num_faces; f++) {
63 SubdFace face = get_subd_face(f);
64
65 if (face.is_quad()) {
66 patch->patch_index = face.ptex_offset;
67 patch->from_ngon = false;
68 patch->shader = face.shader;
69 patch->smooth = face.smooth;
70 patch++;
71 }
72 else {
73 for (int corner = 0; corner < face.num_corners; corner++) {
74 patch->patch_index = face.ptex_offset + corner;
75 patch->from_ngon = true;
76 patch->shader = face.shader;
77 patch->smooth = face.smooth;
78 patch++;
79 }
80 }
81 }
82
83 /* Split patches. */
85 split.split_patches(osd_patches.data(), sizeof(OsdPatch));
86
87 /* Setup interpolation. */
88 SubdAttributeInterpolation interpolation(*this, osd_mesh, osd_data);
89
90 /* Dice patches. */
91 EdgeDice dice(params, split.get_num_verts(), split.get_num_triangles(), interpolation);
92 dice.dice(split);
93 }
94 else
95#endif
96 {
97 vector<LinearQuadPatch> linear_patches(num_patches);
98 LinearQuadPatch *patch = linear_patches.data();
99
100 for (int f = 0; f < num_faces; f++) {
101 SubdFace face = get_subd_face(f);
102
103 if (face.is_quad()) {
104 /* Simple quad case. */
105 float3 *hull = patch->hull;
106
107 patch->patch_index = face.ptex_offset;
108 patch->from_ngon = false;
109
110 hull[0] = verts[subd_face_corners[face.start_corner + 0]];
111 hull[1] = verts[subd_face_corners[face.start_corner + 1]];
112 hull[2] = verts[subd_face_corners[face.start_corner + 3]];
113 hull[3] = verts[subd_face_corners[face.start_corner + 2]];
114
115 patch->shader = face.shader;
116 patch->smooth = face.smooth;
117 patch++;
118 }
119 else {
120 /* N-gon split into N quads. */
121 float3 center_vert = zero_float3();
122
123 const float inv_num_corners = 1.0f / float(face.num_corners);
124 for (int corner = 0; corner < face.num_corners; corner++) {
125 center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
126 }
127
128 for (int corner = 0; corner < face.num_corners; corner++) {
129 float3 *hull = patch->hull;
130
131 patch->patch_index = face.ptex_offset + corner;
132 patch->from_ngon = true;
133
134 patch->shader = face.shader;
135 patch->smooth = face.smooth;
136
137 const int v0 = subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)];
138 const int v1 = subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)];
139 const int v3 = subd_face_corners[face.start_corner +
140 mod(corner + face.num_corners - 1, face.num_corners)];
141
142 hull[0] = verts[v0];
143 hull[1] = 0.5f * (verts[v0] + verts[v1]);
144 hull[2] = 0.5f * (verts[v3] + verts[v0]);
145 hull[3] = center_vert;
146
147 patch++;
148 }
149 }
150 }
151
152 /* Split patches. */
154 split.split_patches(linear_patches.data(), sizeof(LinearQuadPatch));
155
156 /* Setup interpolation. */
157#ifdef WITH_OPENSUBDIV
158 SubdAttributeInterpolation interpolation(*this, osd_mesh, osd_data);
159#else
160 SubdAttributeInterpolation interpolation(*this);
161#endif
162
163 /* Dice patches. */
164 EdgeDice dice(params, split.get_num_verts(), split.get_num_triangles(), interpolation);
165 dice.dice(split);
166 }
167
168 // TODO: Free subd base data? Or will this break interactive updates?
169}
170
static void split(const char *text, const char *seps, char ***str, int *count)
void dice(const DiagSplit &split)
Definition dice.cpp:663
float3 hull[4]
Definition patch.h:30
int shader
Definition patch.h:21
bool smooth
Definition patch.h:22
bool from_ngon
Definition patch.h:23
int patch_index
Definition patch.h:20
nullptr float
#define CCL_NAMESPACE_END
static float verts[][3]
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:17
friend class EdgeDice
Definition scene/mesh.h:190
void tessellate(SubdParams &params)
size_t get_num_subd_faces() const
Definition scene/mesh.h:235
SubdFace get_subd_face(const size_t index) const
@ SUBDIVISION_LINEAR
Definition scene/mesh.h:119
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:120
friend class DiagSplit
Definition scene/mesh.h:189