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
26
27// Specify the number of vertices, faces, face-vertices, etc.
28template <>
29bool TopologyRefinerFactory<ConverterType>::resizeComponentTopology(
30 TopologyRefiner& refiner,
31 const ConverterType& conv)
32{
33 const auto& mesh = conv.mesh;
34
35 // Number of vertices
36 int num_vertices = static_cast<int>(mesh.get_num_vertices());
37 setNumBaseVertices(refiner, num_vertices);
38
39 // Number of faces and face-vertices (corners)
40 int num_facets = static_cast<int>(mesh.get_num_facets());
41 setNumBaseFaces(refiner, num_facets);
42 for (int facet = 0; facet < num_facets; ++facet) {
43 int nv = static_cast<int>(mesh.get_facet_size(facet));
44 setNumBaseFaceVertices(refiner, facet, nv);
45 }
46
47 return true;
48}
49
50// Specify the relationships between vertices, faces, etc. ie the face-vertices, vertex-faces,
51// edge-vertices, etc.
52template <>
53bool TopologyRefinerFactory<ConverterType>::assignComponentTopology(
54 TopologyRefiner& refiner,
55 const ConverterType& conv)
56{
57 const auto& mesh = conv.mesh;
58 using Far::IndexArray;
59
60 // Face relations
61 int num_facets = static_cast<int>(mesh.get_num_facets());
62 for (int facet = 0; facet < num_facets; ++facet) {
63 IndexArray dst_facet_vertices = getBaseFaceVertices(refiner, facet);
64
65 auto fv = mesh.get_facet_vertices(facet);
66 for (size_t lv = 0; lv < fv.size(); ++lv) {
67 dst_facet_vertices[lv] = static_cast<int>(fv[lv]);
68 }
69 }
70
71 return true;
72};
73
74// (Optional) Specify edge or vertex sharpness or face holes.
75template <>
76bool TopologyRefinerFactory<ConverterType>::assignComponentTags(
77 TopologyRefiner& refiner,
78 const ConverterType& conv)
79{
80 const auto& mesh = conv.mesh;
81 const auto& options = conv.options;
82
83 if (options.edge_sharpness_attr.has_value()) {
85 mesh,
86 options.edge_sharpness_attr.value(),
87 [&](auto&& attr) {
88 using AttributeType = std::decay_t<decltype(attr)>;
89 using ValueType = typename AttributeType::ValueType;
90 la_runtime_assert(attr.get_num_channels() == 1);
91 la_runtime_assert(
92 std::is_floating_point_v<ValueType>,
93 lagrange::format(
94 "Edge sharpness attribute must use a floating point type. Received: {}",
95 lagrange::internal::value_type_name<ValueType>()));
96 la_runtime_assert(attr.get_element_type() == lagrange::AttributeElement::Edge);
97 if constexpr (AttributeType::IsIndexed) {
98 la_runtime_assert("Edge sharpness cannot be an indexed attribute");
99 } else {
100 lagrange::logger().debug("Using edge sharpness attribute");
101 auto values = attr.get_all();
102 for (int e = 0; e < static_cast<int>(values.size()); ++e) {
103 auto v = mesh.get_edge_vertices(e);
104 Index idx = findBaseEdge(refiner, v[0], v[1]);
105
106 if (idx != INDEX_INVALID) {
107 float s = static_cast<float>(ValueType(10.0) * values[e]);
108 setBaseEdgeSharpness(refiner, idx, s);
109 } else {
110 char msg[1024];
111 snprintf(
112 msg,
113 1024,
114 "Edge %d specified to be sharp does not exist (%d, %d)",
115 e,
116 static_cast<int>(v[0]),
117 static_cast<int>(v[1]));
118 reportInvalidTopology(
119 Vtr::internal::Level::TOPOLOGY_INVALID_CREASE_EDGE,
120 msg,
121 conv);
122 }
123 }
124 }
125 });
126 }
127
128 if (options.vertex_sharpness_attr.has_value()) {
130 mesh,
131 options.vertex_sharpness_attr.value(),
132 [&](auto&& attr) {
133 using AttributeType = std::decay_t<decltype(attr)>;
134 using ValueType = typename AttributeType::ValueType;
135 la_runtime_assert(attr.get_num_channels() == 1);
136 la_runtime_assert(attr.get_element_type() == lagrange::AttributeElement::Vertex);
137 la_runtime_assert(
138 std::is_floating_point_v<ValueType>,
139 lagrange::format(
140 "Vertex sharpness attribute must use a floating point type. Received: {}",
141 lagrange::internal::value_type_name<ValueType>()));
142 if constexpr (AttributeType::IsIndexed) {
143 la_runtime_assert("Vertex sharpness cannot be an indexed attribute");
144 } else {
145 lagrange::logger().debug("Using vertex sharpness attribute");
146 auto values = attr.get_all();
147 for (int v = 0; v < static_cast<int>(values.size()); ++v) {
148 float s = static_cast<float>(ValueType(10.0) * values[v]);
149 setBaseVertexSharpness(refiner, v, s);
150 }
151 }
152 });
153 }
154
155 if (options.face_hole_attr.has_value()) {
157 mesh,
158 options.face_hole_attr.value(),
159 [&](auto&& attr) {
160 using AttributeType = std::decay_t<decltype(attr)>;
161 using ValueType = typename AttributeType::ValueType;
162 la_runtime_assert(attr.get_num_channels() == 1);
163 la_runtime_assert(
164 std::is_integral_v<ValueType>,
165 lagrange::format(
166 "Face holes attribute must use an integral type. Received: {}",
167 lagrange::internal::value_type_name<ValueType>()));
168 if constexpr (AttributeType::IsIndexed) {
169 la_runtime_assert("Face holes cannot be an indexed attribute");
170 } else {
171 lagrange::logger().debug("Using facet hole attribute");
172 auto values = attr.get_all();
173 for (int f = 0; f < static_cast<int>(values.size()); ++f) {
174 if (values[f] != ValueType(0)) {
175 lagrange::logger().debug("Setting facet f{} as a hole", f);
176 setBaseFaceHole(refiner, f, true);
177 }
178 }
179 }
180 });
181 }
182
183 return true;
184}
185
186
187// (Optional) Specify face-varying data per face.
188template <>
189bool TopologyRefinerFactory<ConverterType>::assignFaceVaryingTopology(
190 TopologyRefiner& refiner,
191 const ConverterType& conv)
192{
193 const auto& mesh = conv.mesh;
194
195 // TODO: Only define one fvar channel for each different set of indices (factorize shared set of
196 // indices)?
197 for (lagrange::AttributeId attr_id : conv.face_varying_attributes) {
198 lagrange::internal::visit_attribute_read(mesh, attr_id, [&](auto&& attr) {
199 using AttributeType = std::decay_t<decltype(attr)>;
200 if constexpr (!AttributeType::IsIndexed) {
202 false,
203 lagrange::format(
204 "Face varying attributes must indexed attributes. Received: {}",
205 lagrange::internal::to_string(attr.get_element_type())));
206 } else {
207 int num_values = static_cast<int>(attr.values().get_num_elements());
208 auto src_indices = attr.indices().get_all();
209
210 int channel = createBaseFVarChannel(refiner, num_values);
211
212 for (int f = 0, src_next = 0; f < static_cast<int>(mesh.get_num_facets()); ++f) {
213 IndexArray dst_indices = getBaseFaceFVarValues(refiner, f, channel);
214
215 for (int lv = 0; lv < dst_indices.size(); ++lv) {
216 dst_indices[lv] = src_indices[src_next++];
217 }
218 }
219 }
220 });
221 }
222 return true;
223}
224
225// (Optional) Control run-time topology validation and error reporting.
226template <>
227void TopologyRefinerFactory<ConverterType>::reportInvalidTopology(
228 TopologyError /* errCode */,
229 const char* msg,
230 const ConverterType& /* mesh */)
231{
232 //
233 // Optional topology validation error reporting:
234 // This method is called whenever the factory encounters topology validation
235 // errors. By default, nothing is reported
236 //
237 lagrange::logger().warn("[opensubdiv] {}", msg);
238}
239
241
242} // namespace Far
243
244} // namespace OPENSUBDIV_VERSION
245} // 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:177
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