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