Blender V4.3
topology_refiner_factory.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2015 Blender Foundation
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 *
5 * Author: Sergey Sharybin. */
6
7#ifdef _MSC_VER
8# include <iso646.h>
9#endif
10
12
13#include <cassert>
14#include <cstdio>
15
16#include <opensubdiv/far/topologyRefinerFactory.h>
17
20
22
27
28typedef OpenSubdiv::Far::TopologyRefinerFactory<TopologyRefinerData> TopologyRefinerFactoryType;
29
30namespace OpenSubdiv {
31namespace OPENSUBDIV_VERSION {
32namespace Far {
33
34template<>
35inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
36 TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
37{
39
40 const OpenSubdiv_Converter *converter = cb_data.converter;
41 MeshTopology *base_mesh_topology = cb_data.base_mesh_topology;
42
43 // Vertices.
44 const int num_vertices = converter->getNumVertices(converter);
45 base_mesh_topology->setNumVertices(num_vertices);
46 setNumBaseVertices(refiner, num_vertices);
47
48 // Edges.
49 //
50 // NOTE: Always store edges in the base mesh topology so then comparison can
51 // happen, but only provide edges to TopologyRefiner if full topology is
52 // specified (if full topology is not specified then topology refiner must
53 // not see any edges, which will indicate to it that winding and edges are to
54 // be reconstructed).
55 //
56 // NOTE: it is a possible use case when user code does not need crease at all
57 // (which is the only real reason why converter would want to provide edges in
58 // the case of partial topology specification). So it might be so getNumEdges
59 // callback is nullptr.
60 if (converter->getNumEdges != nullptr) {
61 const int num_edges = converter->getNumEdges(converter);
62 base_mesh_topology->setNumEdges(num_edges);
63 }
64
65 // Faces and face-vertices.
66 const int num_faces = converter->getNumFaces(converter);
67 base_mesh_topology->setNumFaces(num_faces);
68 setNumBaseFaces(refiner, num_faces);
69 for (int face_index = 0; face_index < num_faces; ++face_index) {
70 const int num_face_vertices = converter->getNumFaceVertices(converter, face_index);
71 base_mesh_topology->setNumFaceVertices(face_index, num_face_vertices);
72 setNumBaseFaceVertices(refiner, face_index, num_face_vertices);
73 }
74
75 // If converter does not provide full topology, we are done.
76 //
77 // The rest is needed to define relations between faces-of-edge and
78 // edges-of-vertex, which is not available for partially specified mesh.
79 if (!converter->specifiesFullTopology(converter)) {
80 base_mesh_topology->finishResizeTopology();
81 return true;
82 }
83
84 // Edges and edge-faces.
85 const int num_edges = converter->getNumEdges(converter);
86 setNumBaseEdges(refiner, num_edges);
87 for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
88 const int num_edge_faces = converter->getNumEdgeFaces(converter, edge_index);
89 setNumBaseEdgeFaces(refiner, edge_index, num_edge_faces);
90 }
91
92 // Vertex-faces and vertex-edges.
93 for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
94 const int num_vert_edges = converter->getNumVertexEdges(converter, vertex_index);
95 const int num_vert_faces = converter->getNumVertexFaces(converter, vertex_index);
96 setNumBaseVertexEdges(refiner, vertex_index, num_vert_edges);
97 setNumBaseVertexFaces(refiner, vertex_index, num_vert_faces);
98 }
99
100 base_mesh_topology->finishResizeTopology();
101 return true;
102}
103
104template<>
105inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
106 TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
107{
109 using Far::IndexArray;
110
111 const OpenSubdiv_Converter *converter = cb_data.converter;
112 MeshTopology *base_mesh_topology = cb_data.base_mesh_topology;
113
114 const bool full_topology_specified = converter->specifiesFullTopology(converter);
115
116 // Vertices of face.
117 const int num_faces = converter->getNumFaces(converter);
118 for (int face_index = 0; face_index < num_faces; ++face_index) {
119 IndexArray dst_face_verts = getBaseFaceVertices(refiner, face_index);
120 converter->getFaceVertices(converter, face_index, &dst_face_verts[0]);
121
122 base_mesh_topology->setFaceVertexIndices(
123 face_index, dst_face_verts.size(), &dst_face_verts[0]);
124 }
125
126 // If converter does not provide full topology, we are done.
127 //
128 // The rest is needed to define relations between faces-of-edge and
129 // edges-of-vertex, which is not available for partially specified mesh.
130 if (!full_topology_specified) {
131 return true;
132 }
133
134 // Vertex relations.
135 const int num_vertices = converter->getNumVertices(converter);
136 std::vector<int> vertex_faces, vertex_edges;
137 for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
138 // Vertex-faces.
139 IndexArray dst_vertex_faces = getBaseVertexFaces(refiner, vertex_index);
140 const int num_vertex_faces = converter->getNumVertexFaces(converter, vertex_index);
141 vertex_faces.resize(num_vertex_faces);
142 converter->getVertexFaces(converter, vertex_index, &vertex_faces[0]);
143
144 // Vertex-edges.
145 IndexArray dst_vertex_edges = getBaseVertexEdges(refiner, vertex_index);
146 const int num_vertex_edges = converter->getNumVertexEdges(converter, vertex_index);
147 vertex_edges.resize(num_vertex_edges);
148 converter->getVertexEdges(converter, vertex_index, &vertex_edges[0]);
149 memcpy(&dst_vertex_edges[0], &vertex_edges[0], sizeof(int) * num_vertex_edges);
150 memcpy(&dst_vertex_faces[0], &vertex_faces[0], sizeof(int) * num_vertex_faces);
151 }
152
153 // Edge relations.
154 const int num_edges = converter->getNumEdges(converter);
155 for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
156 // Vertices this edge connects.
157 IndexArray dst_edge_vertices = getBaseEdgeVertices(refiner, edge_index);
158 converter->getEdgeVertices(converter, edge_index, &dst_edge_vertices[0]);
159
160 // Faces adjacent to this edge.
161 IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge_index);
162 converter->getEdgeFaces(converter, edge_index, &dst_edge_faces[0]);
163 }
164
165 // Face relations.
166 for (int face_index = 0; face_index < num_faces; ++face_index) {
167 IndexArray dst_face_edges = getBaseFaceEdges(refiner, face_index);
168 converter->getFaceEdges(converter, face_index, &dst_face_edges[0]);
169 }
170
171 populateBaseLocalIndices(refiner);
172
173 return true;
174}
175
176template<>
177inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
178 TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
179{
181 using OpenSubdiv::Sdc::Crease;
182
183 const OpenSubdiv_Converter *converter = cb_data.converter;
184 MeshTopology *base_mesh_topology = cb_data.base_mesh_topology;
185
186 const bool full_topology_specified = converter->specifiesFullTopology(converter);
187 if (full_topology_specified || converter->getEdgeVertices != NULL) {
188 const int num_edges = converter->getNumEdges(converter);
189 for (int edge_index = 0; edge_index < num_edges; ++edge_index) {
190 const float sharpness = converter->getEdgeSharpness(converter, edge_index);
191 if (sharpness < 1e-6f) {
192 continue;
193 }
194
195 int edge_vertices[2];
196 converter->getEdgeVertices(converter, edge_index, edge_vertices);
197 base_mesh_topology->setEdgeVertexIndices(edge_index, edge_vertices[0], edge_vertices[1]);
198 base_mesh_topology->setEdgeSharpness(edge_index, sharpness);
199
200 if (full_topology_specified) {
201 setBaseEdgeSharpness(refiner, edge_index, sharpness);
202 }
203 else {
204 // TODO(sergey): Should be a faster way to find reconstructed edge to
205 // specify sharpness for (assuming, findBaseEdge has linear complexity).
206 const int base_edge_index = findBaseEdge(refiner, edge_vertices[0], edge_vertices[1]);
207 if (base_edge_index == OpenSubdiv::Far::INDEX_INVALID) {
208 printf("OpenSubdiv Error: failed to find reconstructed edge\n");
209 return false;
210 }
211 setBaseEdgeSharpness(refiner, base_edge_index, sharpness);
212 }
213 }
214 }
215
216 // OpenSubdiv expects non-manifold vertices to be sharp but at the time it
217 // handles correct cases when vertex is a corner of plane. Currently mark
218 // vertices which are adjacent to a loose edge as sharp, but this decision
219 // needs some more investigation.
220 const int num_vertices = converter->getNumVertices(converter);
221 for (int vertex_index = 0; vertex_index < num_vertices; ++vertex_index) {
222 ConstIndexArray vertex_edges = getBaseVertexEdges(refiner, vertex_index);
223 if (converter->isInfiniteSharpVertex(converter, vertex_index)) {
224 base_mesh_topology->setVertexSharpness(vertex_index, Crease::SHARPNESS_INFINITE);
225 setBaseVertexSharpness(refiner, vertex_index, Crease::SHARPNESS_INFINITE);
226 continue;
227 }
228
229 // Get sharpness provided by the converter.
230 float sharpness = 0.0f;
231 if (converter->getVertexSharpness != NULL) {
232 sharpness = converter->getVertexSharpness(converter, vertex_index);
233 base_mesh_topology->setVertexSharpness(vertex_index, sharpness);
234 }
235
236 // If its vertex where 2 non-manifold edges meet adjust vertex sharpness to
237 // the edges.
238 // This way having a plane with all 4 edges set to be sharp produces sharp
239 // corners in the subdivided result.
240 if (vertex_edges.size() == 2) {
241 const int edge0 = vertex_edges[0], edge1 = vertex_edges[1];
242 const float sharpness0 = refiner._levels[0]->getEdgeSharpness(edge0);
243 const float sharpness1 = refiner._levels[0]->getEdgeSharpness(edge1);
244 // TODO(sergey): Find a better mixing between edge and vertex sharpness.
245 sharpness += std::min(sharpness0, sharpness1);
246 sharpness = std::min(sharpness, 10.0f);
247 }
248
249 setBaseVertexSharpness(refiner, vertex_index, sharpness);
250 }
251 return true;
252}
253
254template<>
255inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
256 TopologyRefiner &refiner, const TopologyRefinerData &cb_data)
257{
258 const OpenSubdiv_Converter *converter = cb_data.converter;
259 if (converter->getNumUVLayers == NULL) {
260 assert(converter->precalcUVLayer == NULL);
261 assert(converter->getNumUVCoordinates == NULL);
262 assert(converter->getFaceCornerUVIndex == NULL);
263 assert(converter->finishUVLayer == NULL);
264 return true;
265 }
266 const int num_layers = converter->getNumUVLayers(converter);
267 if (num_layers <= 0) {
268 // No UV maps, we can skip any face-varying data.
269 return true;
270 }
271 const int num_faces = getNumBaseFaces(refiner);
272 for (int layer_index = 0; layer_index < num_layers; ++layer_index) {
273 converter->precalcUVLayer(converter, layer_index);
274 const int num_uvs = converter->getNumUVCoordinates(converter);
275 // Fill in per-corner index of the UV.
276 const int channel = createBaseFVarChannel(refiner, num_uvs);
277 // TODO(sergey): Need to check whether converter changed the winding of
278 // face to match OpenSubdiv's expectations.
279 for (int face_index = 0; face_index < num_faces; ++face_index) {
280 Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner, face_index, channel);
281 for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
282 const int uv_index = converter->getFaceCornerUVIndex(converter, face_index, corner);
283 dst_face_uvs[corner] = uv_index;
284 }
285 }
286 converter->finishUVLayer(converter);
287 }
288 return true;
289}
290
291template<>
292inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
293 TopologyError /*errCode*/, const char *msg, const TopologyRefinerData & /*mesh*/)
294{
295 printf("OpenSubdiv Error: %s\n", msg);
296}
297
298} /* namespace Far */
299} /* namespace OPENSUBDIV_VERSION */
300} /* namespace OpenSubdiv */
301
302namespace blender::opensubdiv {
303
304static OpenSubdiv::Sdc::Options getSDCOptions(OpenSubdiv_Converter *converter)
305{
306 using OpenSubdiv::Sdc::Options;
307
308 const Options::FVarLinearInterpolation linear_interpolation = getFVarLinearInterpolationFromCAPI(
309 converter->getFVarLinearInterpolation(converter));
310
312 options.SetVtxBoundaryInterpolation(
314 options.SetCreasingMethod(Options::CREASE_UNIFORM);
315 options.SetFVarLinearInterpolation(linear_interpolation);
316
317 return options;
318}
319
320static TopologyRefinerFactoryType::Options getTopologyRefinerOptions(
321 OpenSubdiv_Converter *converter)
322{
323 using OpenSubdiv::Sdc::SchemeType;
324
325 OpenSubdiv::Sdc::Options sdc_options = getSDCOptions(converter);
326
327 const SchemeType scheme_type = getSchemeTypeFromCAPI(converter->getSchemeType(converter));
328 TopologyRefinerFactoryType::Options topology_options(scheme_type, sdc_options);
329
330 // NOTE: When debugging topology conversion related functionality it is helpful to set this
331 // to truth. In all other cases leave it at false. so debugging of other areas is not affected
332 // by performance penalty happening in this module.
333 topology_options.validateFullTopology = false;
334
335 return topology_options;
336}
337
340{
341 using OpenSubdiv::Far::TopologyRefiner;
342
344
345 TopologyRefinerData cb_data;
346 cb_data.converter = converter;
348
349 // Create OpenSubdiv descriptor for the topology refiner.
350 TopologyRefinerFactoryType::Options topology_refiner_options = getTopologyRefinerOptions(
351 converter);
352 TopologyRefiner *topology_refiner = TopologyRefinerFactoryType::Create(cb_data,
353 topology_refiner_options);
354 if (topology_refiner == nullptr) {
355 return nullptr;
356 }
357
358 // Create Blender-side object holding all necessary data for the topology refiner.
359 TopologyRefinerImpl *topology_refiner_impl = new TopologyRefinerImpl();
360 topology_refiner_impl->topology_refiner = topology_refiner;
361 topology_refiner_impl->settings = settings;
362 topology_refiner_impl->base_mesh_topology = std::move(base_mesh_topology);
363
364 return topology_refiner_impl;
365}
366
367} // namespace blender::opensubdiv
OpenSubdiv::Far::TopologyRefiner * topology_refiner
OpenSubdiv_TopologyRefinerSettings settings
static TopologyRefinerImpl * createFromConverter(OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings &settings)
#define printf
CCL_NAMESPACE_BEGIN struct Options options
#define NULL
OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation getVtxBoundaryInterpolationFromCAPI(OpenSubdiv_VtxBoundaryInterpolation boundary_interpolation)
OpenSubdiv::Sdc::SchemeType getSchemeTypeFromCAPI(OpenSubdiv_SchemeType type)
static OpenSubdiv::Sdc::Options getSDCOptions(OpenSubdiv_Converter *converter)
static TopologyRefinerFactoryType::Options getTopologyRefinerOptions(OpenSubdiv_Converter *converter)
OpenSubdiv::Sdc::Options::FVarLinearInterpolation getFVarLinearInterpolationFromCAPI(OpenSubdiv_FVarLinearInterpolation linear_interpolation)
int(* getFaceCornerUVIndex)(const OpenSubdiv_Converter *converter, const int face_index, const int corner_index)
int(* getNumFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index)
int(* getNumEdges)(const OpenSubdiv_Converter *converter)
void(* precalcUVLayer)(const OpenSubdiv_Converter *converter, const int layer_index)
float(* getEdgeSharpness)(const OpenSubdiv_Converter *converter, const int edge_index)
int(* getNumVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index)
void(* getVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_faces)
void(* getVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index, int *vertex_edges)
OpenSubdiv_FVarLinearInterpolation(* getFVarLinearInterpolation)(const OpenSubdiv_Converter *converter)
int(* getNumFaces)(const OpenSubdiv_Converter *converter)
bool(* specifiesFullTopology)(const OpenSubdiv_Converter *converter)
int(* getNumUVCoordinates)(const OpenSubdiv_Converter *converter)
void(* getFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index, int *face_vertices)
OpenSubdiv_VtxBoundaryInterpolation(* getVtxBoundaryInterpolation)(const OpenSubdiv_Converter *converter)
int(* getNumUVLayers)(const OpenSubdiv_Converter *converter)
int(* getNumEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge_index)
bool(* isInfiniteSharpVertex)(const OpenSubdiv_Converter *converter, const int vertex_index)
float(* getVertexSharpness)(const OpenSubdiv_Converter *converter, const int vertex_index)
OpenSubdiv_SchemeType(* getSchemeType)(const OpenSubdiv_Converter *converter)
void(* getEdgeVertices)(const OpenSubdiv_Converter *converter, const int edge_index, int edge_vertices[2])
int(* getNumVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index)
int(* getNumVertices)(const OpenSubdiv_Converter *converter)
void(* getFaceEdges)(const OpenSubdiv_Converter *converter, const int face_index, int *face_edges)
void(* finishUVLayer)(const OpenSubdiv_Converter *converter)
void(* getEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge, int *edge_faces)
blender::opensubdiv::MeshTopology * base_mesh_topology
const OpenSubdiv_Converter * converter
OpenSubdiv::Far::TopologyRefinerFactory< TopologyRefinerData > TopologyRefinerFactoryType