14#include <lagrange/Mesh.h>
15#include <lagrange/MeshTrait.h>
16#include <lagrange/create_mesh.h>
17#include <lagrange/utils/range.h>
20#include <lagrange/utils/warnoff.h>
21#include <opensubdiv/far/primvarRefiner.h>
22#include <opensubdiv/far/topologyDescriptor.h>
23#include <lagrange/utils/warnon.h>
32namespace subdivision {
39template <
typename MeshType>
42 using VertexType =
typename MeshType::VertexType;
47 void Clear(
void* = 0) { m_position.setZero(); }
48 void AddWithWeight(
OSDVertex const& src,
float weight)
50 m_position += (weight * src.m_position);
54 void SetPosition(
const VertexType& pos) { m_position = pos; }
55 const VertexType& GetPosition()
const {
return m_position; }
58 VertexType m_position;
62template <
typename MeshType>
65 using UVType =
typename MeshType::UVType;
67 OSDUV(
OSDUV const& src) { m_position = src.m_position; }
70 void Clear(
void* = 0) { m_position.setZero(); }
71 void AddWithWeight(
OSDUV const& src,
float weight) { m_position += (weight * src.m_position); }
74 void SetPosition(
const UVType& pos) { m_position = pos; }
75 const UVType& GetPosition()
const {
return m_position; }
87template <
typename input_meshType,
typename output_meshType>
88std::unique_ptr<output_meshType> subdivide_mesh(
89 const input_meshType& input_mesh,
90 SubdivisionScheme scheme_type,
92 OpenSubdiv::Sdc::Options::VtxBoundaryInterpolation vertexInterp =
93 OpenSubdiv::Sdc::Options::VTX_BOUNDARY_EDGE_ONLY,
94 OpenSubdiv::Sdc::Options::FVarLinearInterpolation primvarInterp =
95 OpenSubdiv::Sdc::Options::FVAR_LINEAR_ALL)
99 std::is_same<typename input_meshType::Index, typename output_meshType::Index>::value,
100 "Meshes must have same Index type");
102 using namespace OpenSubdiv;
103 using Descriptor = Far::TopologyDescriptor;
104 using namespace internal;
105 using OSDIndex = Vtr::Index;
107 if (scheme_type == SubdivisionScheme::SCHEME_LOOP) {
109 input_mesh.get_vertex_per_facet() == 3,
110 "Loop Subdivision only supports triangle meshes");
114 Sdc::Options options;
115 options.SetVtxBoundaryInterpolation(vertexInterp);
116 options.SetFVarLinearInterpolation(primvarInterp);
119 const auto num_vertices = input_mesh.get_num_vertices();
120 const auto num_facets = input_mesh.get_num_facets();
121 const auto input_vertex_per_facet = input_mesh.get_vertex_per_facet();
122 const auto output_vertex_per_facet = output_meshType::FacetArray::ColsAtCompileTime==Eigen::Dynamic?
123 input_vertex_per_facet:output_meshType::FacetArray::ColsAtCompileTime;
125 if (input_vertex_per_facet == 3 && output_vertex_per_facet == 4) {
128 "Only non-zero-level subdivision is supported when the input is triangle and the "
129 "output is quadrangle.");
134 desc.numVertices = num_vertices;
135 desc.numFaces = num_facets;
137 std::vector<int> verts_per_face(num_facets, input_vertex_per_facet);
138 desc.numVertsPerFace = verts_per_face.data();
140 const auto& facets = input_mesh.get_facets();
141 std::vector<OSDIndex> vert_indices;
142 vert_indices.resize(num_facets * input_vertex_per_facet);
143 for (
auto i :
range(desc.numFaces)) {
144 for (
auto j :
range(input_vertex_per_facet)) {
145 vert_indices[i * input_vertex_per_facet + j] = safe_cast<OSDIndex>(facets(i, j));
148 desc.vertIndicesPerFace = vert_indices.data();
152 const bool hasUvs = input_mesh.is_uv_initialized();
153 std::vector<OSDIndex> uv_indices;
154 const int channelUV = 0;
155 const int numChannels = 1;
156 Descriptor::FVarChannel channels[numChannels];
158 channels[channelUV].numValues = (int)input_mesh.get_uv().rows();
159 const auto& inputUVIndices = input_mesh.get_uv_indices();
160 uv_indices.resize(inputUVIndices.size());
161 for (
auto i :
range(desc.numFaces)) {
162 for (
auto j :
range(input_vertex_per_facet)) {
163 uv_indices[i * input_vertex_per_facet + j] =
164 safe_cast<OSDIndex>(inputUVIndices(i, j));
167 channels[channelUV].valueIndices = uv_indices.data();
170 desc.numFVarChannels = numChannels;
171 desc.fvarChannels = channels;
175 std::unique_ptr<Far::TopologyRefiner> refiner(Far::TopologyRefinerFactory<Descriptor>::Create(
176 desc, Far::TopologyRefinerFactory<Descriptor>::Options(scheme_type, options)));
181 Far::TopologyRefiner::UniformOptions refineOptions(maxlevel);
182 refineOptions.fullTopologyInLastLevel =
true;
183 refiner->RefineUniform(refineOptions);
188 std::vector<OSDVertex<output_meshType>> vbuffer(refiner->GetNumVerticesTotal());
189 OSDVertex<output_meshType>* outputVerts = &vbuffer[0];
191 int nInputVerts = input_mesh.get_num_vertices();
192 for (
int i = 0; i < nInputVerts; ++i)
193 outputVerts[i].SetPosition(
194 input_mesh.get_vertices().row(i).template cast<typename output_meshType::Scalar>());
196 OSDUV<output_meshType>* outputUvs =
nullptr;
197 std::vector<OSDUV<output_meshType>> fvBufferUV;
200 fvBufferUV.resize(refiner->GetNumFVarValuesTotal(channelUV));
201 outputUvs = &fvBufferUV[0];
203 for (
int i = 0; i < input_mesh.get_uv().rows(); ++i) {
204 outputUvs[i].SetPosition(
205 input_mesh.get_uv().row(i).template cast<typename output_meshType::Scalar>());
210 Far::PrimvarRefiner primvarRefiner(*refiner);
211 OSDVertex<output_meshType>* srcVert = outputVerts;
212 OSDUV<output_meshType>* srcFVarUV = outputUvs;
214 for (
int level = 1; level <= maxlevel; ++level) {
215 OSDVertex<output_meshType>* dstVert =
216 srcVert + refiner->GetLevel(level - 1).GetNumVertices();
217 OSDUV<output_meshType>* dstFVarUV = outputUvs;
219 dstFVarUV = srcFVarUV + refiner->GetLevel(level - 1).GetNumFVarValues(channelUV);
221 primvarRefiner.Interpolate(level, srcVert, dstVert);
223 if (hasUvs) primvarRefiner.InterpolateFaceVarying(level, srcFVarUV, dstFVarUV, channelUV);
225 if (hasUvs) srcFVarUV = dstFVarUV;
231 Far::TopologyLevel
const& refLastLevel = refiner->GetLevel(maxlevel);
232 int nOutputVerts = refLastLevel.GetNumVertices();
233 int nOutputFaces = refLastLevel.GetNumFaces();
234 bool triangulate =
false;
235 if (scheme_type == SubdivisionScheme::SCHEME_LOOP) {
237 assert(output_vertex_per_facet == 3);
240 assert(output_vertex_per_facet == 3 || output_vertex_per_facet == 4);
241 if (output_vertex_per_facet == 3) {
243 if (maxlevel > 0 || input_vertex_per_facet > 3) {
251 int firstOfLastVerts = refiner->GetNumVerticesTotal() - nOutputVerts;
252 typename output_meshType::VertexArray V;
253 V.resize(nOutputVerts, 3);
254 for (
int iVert = 0; iVert < nOutputVerts; ++iVert) {
255 typename output_meshType::VertexType pos =
256 outputVerts[firstOfLastVerts + iVert].GetPosition();
261 typename output_meshType::FacetArray F;
262 F.resize(nOutputFaces, F.cols());
263 for (
int iFace = 0; iFace < refLastLevel.GetNumFaces(); ++iFace) {
264 Far::ConstIndexArray facetIndices = refLastLevel.GetFaceVertices(iFace);
266 F(iFace * 2, 0) = facetIndices[0];
267 F(iFace * 2, 1) = facetIndices[1];
268 F(iFace * 2, 2) = facetIndices[2];
269 F(iFace * 2 + 1, 0) = facetIndices[0];
270 F(iFace * 2 + 1, 1) = facetIndices[2];
271 F(iFace * 2 + 1, 2) = facetIndices[3];
273 for (
int i = 0; i < facetIndices.size(); ++i) {
274 F(iFace, i) = facetIndices[i];
279 std::unique_ptr<output_meshType> output_mesh =
create_mesh(std::move(V), std::move(F));
283 int nOutputUvs = refLastLevel.GetNumFVarValues(channelUV);
284 int firstOfLastUvs = refiner->GetNumFVarValuesTotal(channelUV) - nOutputUvs;
285 typename output_meshType::UVArray
UV;
286 typename output_meshType::FacetArray UVF;
287 UV.resize(nOutputUvs, 2);
288 UVF.resize(nOutputFaces, output_vertex_per_facet);
289 for (
int iFVVert = 0; iFVVert < nOutputUvs; ++iFVVert) {
290 typename output_meshType::UVType uv = outputUvs[firstOfLastUvs + iFVVert].GetPosition();
291 UV.row(iFVVert) = uv;
293 for (
int iFace = 0; iFace < refLastLevel.GetNumFaces(); ++iFace) {
294 Far::ConstIndexArray uvIndices = refLastLevel.GetFaceFVarValues(iFace, channelUV);
296 UVF(iFace * 2, 0) = uvIndices[0];
297 UVF(iFace * 2, 1) = uvIndices[1];
298 UVF(iFace * 2, 2) = uvIndices[2];
299 UVF(iFace * 2 + 1, 0) = uvIndices[0];
300 UVF(iFace * 2 + 1, 1) = uvIndices[2];
301 UVF(iFace * 2 + 1, 2) = uvIndices[3];
303 for (
int i = 0; i < uvIndices.size(); ++i) {
304 UVF(iFace, i) = uvIndices[i];
308 output_mesh->initialize_uv(UV, UVF);
@ UV
Mesh attribute must have exactly 2 channels.
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
SchemeType
Subdivision scheme.
Definition: mesh_subdivision.h:29
Main namespace for Lagrange.
Definition: AABBIGL.h:30
auto create_mesh(const Eigen::MatrixBase< DerivedV > &vertices, const Eigen::MatrixBase< DerivedF > &facets)
This function create a new mesh given the vertex and facet arrays by copying data into the Mesh objec...
Definition: create_mesh.h:39
MeshTrait class provide compiler check for different mesh types.
Definition: MeshTrait.h:108
Definition: mesh_subdivision.h:64
Definition: mesh_subdivision.h:41