Blender  V3.3
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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a vector
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
static void linear_interpolation(const T &a, const T &b, MutableSpan< T > dst)
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
#define min(a, b)
Definition: sort.c:35
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