Lagrange
Loading...
Searching...
No Matches
TopologyRefinerFactory.h
1/*
2 * Copyright 2024 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12// No #pragma once at the top of this file, this is on purpose.
13
14#include <lagrange/Logger.h>
15#include <lagrange/internal/attribute_string_utils.h>
16#include <lagrange/internal/visit_attribute.h>
17#include <lagrange/utils/assert.h>
18#include <lagrange/utils/fmt/format.h>
19
20namespace OpenSubdiv {
21namespace OPENSUBDIV_VERSION {
22
23namespace Far {
24
25// Specify the number of vertices, faces, face-vertices, etc.
26template <>
27bool TopologyRefinerFactory<ConverterType>::resizeComponentTopology(
28 TopologyRefiner& refiner,
29 const ConverterType& conv)
30{
31 const auto& mesh = conv.mesh;
32
33 // Number of vertices
34 int num_vertices = static_cast<int>(mesh.get_num_vertices());
35 setNumBaseVertices(refiner, num_vertices);
36
37 // Number of faces and face-vertices (corners)
38 int num_facets = static_cast<int>(mesh.get_num_facets());
39 setNumBaseFaces(refiner, num_facets);
40 for (int facet = 0; facet < num_facets; ++facet) {
41 int nv = static_cast<int>(mesh.get_facet_size(facet));
42 setNumBaseFaceVertices(refiner, facet, nv);
43 }
44
45 return true;
46}
47
48// Specify the relationships between vertices, faces, etc. ie the face-vertices, vertex-faces,
49// edge-vertices, etc.
50template <>
51bool TopologyRefinerFactory<ConverterType>::assignComponentTopology(
52 TopologyRefiner& refiner,
53 const ConverterType& conv)
54{
55 const auto& mesh = conv.mesh;
56 using Far::IndexArray;
57
58 // Face relations
59 int num_facets = static_cast<int>(mesh.get_num_facets());
60 for (int facet = 0; facet < num_facets; ++facet) {
61 IndexArray dst_facet_vertices = getBaseFaceVertices(refiner, facet);
62
63 auto fv = mesh.get_facet_vertices(facet);
64 for (size_t lv = 0; lv < fv.size(); ++lv) {
65 dst_facet_vertices[lv] = static_cast<int>(fv[lv]);
66 }
67 }
68
69 return true;
70};
71
72// (Optional) Specify edge or vertex sharpness or face holes.
73template <>
74bool TopologyRefinerFactory<ConverterType>::assignComponentTags(
75 TopologyRefiner& refiner,
76 const ConverterType& conv)
77{
78 const auto& mesh = conv.mesh;
79 const auto& options = conv.options;
80
81 if (options.edge_sharpness_attr.has_value()) {
83 mesh,
84 options.edge_sharpness_attr.value(),
85 [&](auto&& attr) {
86 using AttributeType = std::decay_t<decltype(attr)>;
87 using ValueType = typename AttributeType::ValueType;
88 la_runtime_assert(attr.get_num_channels() == 1);
89 la_runtime_assert(
90 std::is_floating_point_v<ValueType>,
91 lagrange::format(
92 "Edge sharpness attribute must use a floating point type. Received: {}",
93 lagrange::internal::value_type_name<ValueType>()));
94 la_runtime_assert(attr.get_element_type() == lagrange::AttributeElement::Edge);
95 if constexpr (AttributeType::IsIndexed) {
96 la_runtime_assert("Edge sharpness cannot be an indexed attribute");
97 } else {
98 lagrange::logger().debug("Using edge sharpness attribute");
99 auto values = attr.get_all();
100 for (int e = 0; e < static_cast<int>(values.size()); ++e) {
101 auto v = mesh.get_edge_vertices(e);
102 Index idx = findBaseEdge(refiner, v[0], v[1]);
103
104 if (idx != INDEX_INVALID) {
105 float s = static_cast<float>(ValueType(10.0) * values[e]);
106 setBaseEdgeSharpness(refiner, idx, s);
107 } else {
108 char msg[1024];
109 snprintf(
110 msg,
111 1024,
112 "Edge %d specified to be sharp does not exist (%d, %d)",
113 e,
114 static_cast<int>(v[0]),
115 static_cast<int>(v[1]));
116 reportInvalidTopology(
117 Vtr::internal::Level::TOPOLOGY_INVALID_CREASE_EDGE,
118 msg,
119 conv);
120 }
121 }
122 }
123 });
124 }
125
126 if (options.vertex_sharpness_attr.has_value()) {
128 mesh,
129 options.vertex_sharpness_attr.value(),
130 [&](auto&& attr) {
131 using AttributeType = std::decay_t<decltype(attr)>;
132 using ValueType = typename AttributeType::ValueType;
133 la_runtime_assert(attr.get_num_channels() == 1);
134 la_runtime_assert(attr.get_element_type() == lagrange::AttributeElement::Vertex);
135 la_runtime_assert(
136 std::is_floating_point_v<ValueType>,
137 lagrange::format(
138 "Vertex sharpness attribute must use a floating point type. Received: {}",
139 lagrange::internal::value_type_name<ValueType>()));
140 if constexpr (AttributeType::IsIndexed) {
141 la_runtime_assert("Vertex sharpness cannot be an indexed attribute");
142 } else {
143 lagrange::logger().debug("Using vertex sharpness attribute");
144 auto values = attr.get_all();
145 for (int v = 0; v < static_cast<int>(values.size()); ++v) {
146 float s = static_cast<float>(ValueType(10.0) * values[v]);
147 setBaseVertexSharpness(refiner, v, s);
148 }
149 }
150 });
151 }
152
153 if (options.face_hole_attr.has_value()) {
155 mesh,
156 options.face_hole_attr.value(),
157 [&](auto&& attr) {
158 using AttributeType = std::decay_t<decltype(attr)>;
159 using ValueType = typename AttributeType::ValueType;
160 la_runtime_assert(attr.get_num_channels() == 1);
161 la_runtime_assert(
162 std::is_integral_v<ValueType>,
163 lagrange::format(
164 "Face holes attribute must use an integral type. Received: {}",
165 lagrange::internal::value_type_name<ValueType>()));
166 if constexpr (AttributeType::IsIndexed) {
167 la_runtime_assert("Face holes cannot be an indexed attribute");
168 } else {
169 lagrange::logger().debug("Using facet hole attribute");
170 auto values = attr.get_all();
171 for (int f = 0; f < static_cast<int>(values.size()); ++f) {
172 if (values[f] != ValueType(0)) {
173 lagrange::logger().debug("Setting facet f{} as a hole", f);
174 setBaseFaceHole(refiner, f, true);
175 }
176 }
177 }
178 });
179 }
180
181 return true;
182}
183
184
185// (Optional) Specify face-varying data per face.
186template <>
187bool TopologyRefinerFactory<ConverterType>::assignFaceVaryingTopology(
188 TopologyRefiner& refiner,
189 const ConverterType& conv)
190{
191 const auto& mesh = conv.mesh;
192
193 // TODO: Only define one fvar channel for each different set of indices (factorize shared set of
194 // indices)?
195 for (lagrange::AttributeId attr_id : conv.face_varying_attributes) {
196 lagrange::internal::visit_attribute_read(mesh, attr_id, [&](auto&& attr) {
197 using AttributeType = std::decay_t<decltype(attr)>;
198 if constexpr (!AttributeType::IsIndexed) {
200 false,
201 lagrange::format(
202 "Face varying attributes must indexed attributes. Received: {}",
203 lagrange::internal::to_string(attr.get_element_type())));
204 } else {
205 int num_values = static_cast<int>(attr.values().get_num_elements());
206 auto src_indices = attr.indices().get_all();
207
208 int channel = createBaseFVarChannel(refiner, num_values);
209
210 for (int f = 0, src_next = 0; f < static_cast<int>(mesh.get_num_facets()); ++f) {
211 IndexArray dst_indices = getBaseFaceFVarValues(refiner, f, channel);
212
213 for (int lv = 0; lv < dst_indices.size(); ++lv) {
214 dst_indices[lv] = src_indices[src_next++];
215 }
216 }
217 }
218 });
219 }
220 return true;
221}
222
223// (Optional) Control run-time topology validation and error reporting.
224template <>
225void TopologyRefinerFactory<ConverterType>::reportInvalidTopology(
226 TopologyError /* errCode */,
227 const char* msg,
228 const ConverterType& /* mesh */)
229{
230 //
231 // Optional topology validation error reporting:
232 // This method is called whenever the factory encounters topology validation
233 // errors. By default, nothing is reported
234 //
235 lagrange::logger().warn("[opensubdiv] {}", msg);
236}
237
238} // namespace Far
239
240} // namespace OPENSUBDIV_VERSION
241} // namespace OpenSubdiv
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
uint32_t AttributeId
Identified to be used to access an attribute.
Definition AttributeFwd.h:73
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:175
LA_CORE_API std::string_view to_string(AttributeElement element)
Returns a string representation of an attribute element type.
Definition attribute_string_utils.cpp:22
void visit_attribute_read(const SurfaceMesh< Scalar, Index > &mesh, AttributeId id, Func &&func)
Definition visit_attribute.h:39