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