mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-28 18:51:12 +00:00
10c687ecd5
- [Feature Adaptive GPU Rendering of Catmull-Clark Surfaces](http://research.microsoft.com/en-us/um/people/cloop/tog2012.pdf). - New API architecture : we are planning to lock on to this new framework as the basis for backward compatibility, which we will enforce from Release 1.0 onward. Subsequent releases of OpenSubdiv should not break client code. - DirectX 11 support - and much more...
309 lines
12 KiB
C++
309 lines
12 KiB
C++
//
|
|
// Copyright (C) Pixar. All rights reserved.
|
|
//
|
|
// This license governs use of the accompanying software. If you
|
|
// use the software, you accept this license. If you do not accept
|
|
// the license, do not use the software.
|
|
//
|
|
// 1. Definitions
|
|
// The terms "reproduce," "reproduction," "derivative works," and
|
|
// "distribution" have the same meaning here as under U.S.
|
|
// copyright law. A "contribution" is the original software, or
|
|
// any additions or changes to the software.
|
|
// A "contributor" is any person or entity that distributes its
|
|
// contribution under this license.
|
|
// "Licensed patents" are a contributor's patent claims that read
|
|
// directly on its contribution.
|
|
//
|
|
// 2. Grant of Rights
|
|
// (A) Copyright Grant- Subject to the terms of this license,
|
|
// including the license conditions and limitations in section 3,
|
|
// each contributor grants you a non-exclusive, worldwide,
|
|
// royalty-free copyright license to reproduce its contribution,
|
|
// prepare derivative works of its contribution, and distribute
|
|
// its contribution or any derivative works that you create.
|
|
// (B) Patent Grant- Subject to the terms of this license,
|
|
// including the license conditions and limitations in section 3,
|
|
// each contributor grants you a non-exclusive, worldwide,
|
|
// royalty-free license under its licensed patents to make, have
|
|
// made, use, sell, offer for sale, import, and/or otherwise
|
|
// dispose of its contribution in the software or derivative works
|
|
// of the contribution in the software.
|
|
//
|
|
// 3. Conditions and Limitations
|
|
// (A) No Trademark License- This license does not grant you
|
|
// rights to use any contributor's name, logo, or trademarks.
|
|
// (B) If you bring a patent claim against any contributor over
|
|
// patents that you claim are infringed by the software, your
|
|
// patent license from such contributor to the software ends
|
|
// automatically.
|
|
// (C) If you distribute any portion of the software, you must
|
|
// retain all copyright, patent, trademark, and attribution
|
|
// notices that are present in the software.
|
|
// (D) If you distribute any portion of the software in source
|
|
// code form, you may do so only under this license by including a
|
|
// complete copy of this license with your distribution. If you
|
|
// distribute any portion of the software in compiled or object
|
|
// code form, you may only do so under a license that complies
|
|
// with this license.
|
|
// (E) The software is licensed "as-is." You bear the risk of
|
|
// using it. The contributors give no express warranties,
|
|
// guarantees or conditions. You may have additional consumer
|
|
// rights under your local laws which this license cannot change.
|
|
// To the extent permitted under your local laws, the contributors
|
|
// exclude the implied warranties of merchantability, fitness for
|
|
// a particular purpose and non-infringement.
|
|
//
|
|
#ifndef HBRSUBDIVISION_H
|
|
#define HBRSUBDIVISION_H
|
|
|
|
#include "../version.h"
|
|
|
|
namespace OpenSubdiv {
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
template <class T> class HbrFace;
|
|
template <class T> class HbrVertex;
|
|
template <class T> class HbrHalfedge;
|
|
template <class T> class HbrMesh;
|
|
template <class T> class HbrSubdivision {
|
|
public:
|
|
HbrSubdivision<T>()
|
|
: creaseSubdivision(k_CreaseNormal) {}
|
|
|
|
virtual ~HbrSubdivision<T>() {}
|
|
|
|
virtual HbrSubdivision<T>* Clone() const = 0;
|
|
|
|
// How to subdivide a face
|
|
virtual void Refine(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
|
|
|
|
// Subdivide a face only at a particular vertex (creating one child)
|
|
virtual HbrFace<T>* RefineFaceAtVertex(HbrMesh<T>* mesh, HbrFace<T>* face, HbrVertex<T>* vertex) = 0;
|
|
|
|
// Refine all faces around a particular vertex
|
|
virtual void RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex);
|
|
|
|
// Given an edge, try to ensure the edge's opposite exists by
|
|
// forcing refinement up the hierarchy
|
|
virtual void GuaranteeNeighbor(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
|
|
|
|
// Given an vertex, ensure all faces in the ring around it exist
|
|
// by forcing refinement up the hierarchy
|
|
virtual void GuaranteeNeighbors(HbrMesh<T>* mesh, HbrVertex<T>* vertex) = 0;
|
|
|
|
// Returns true if the vertex, edge, or face has a limit point,
|
|
// curve, or surface associated with it
|
|
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrFace<T>* /* face */) { return true; }
|
|
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrHalfedge<T>* /* edge */) { return true; }
|
|
virtual bool HasLimit(HbrMesh<T>* /* mesh */, HbrVertex<T>* /* vertex */) { return true; }
|
|
|
|
// How to turn faces, edges, and vertices into vertices
|
|
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrFace<T>* face) = 0;
|
|
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrHalfedge<T>* edge) = 0;
|
|
virtual HbrVertex<T>* Subdivide(HbrMesh<T>* mesh, HbrVertex<T>* vertex) = 0;
|
|
|
|
// Returns true if the vertex is extraordinary in the subdivision scheme
|
|
virtual bool VertexIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrVertex<T>* /* vertex */) { return false; }
|
|
|
|
// Returns true if the face is extraordinary in the subdivision scheme
|
|
virtual bool FaceIsExtraordinary(HbrMesh<T> const * /* mesh */, HbrFace<T>* /* face */) { return false; }
|
|
|
|
// Crease subdivision rules. When subdividing a edge with a crease
|
|
// strength, we get two child subedges, and we need to determine
|
|
// what weights to assign these subedges. The "normal" rule
|
|
// is to simply assign the current edge's crease strength - 1
|
|
// to both of the child subedges. The "Chaikin" rule looks at the
|
|
// current edge and incident edges to the current edge's end
|
|
// vertices, and weighs them; for more information consult
|
|
// the Geri's Game paper.
|
|
enum CreaseSubdivision {
|
|
k_CreaseNormal,
|
|
k_CreaseChaikin
|
|
};
|
|
CreaseSubdivision GetCreaseSubdivisionMethod() const { return creaseSubdivision; }
|
|
void SetCreaseSubdivisionMethod(CreaseSubdivision method) { creaseSubdivision = method; }
|
|
|
|
// Figures out how to assign a crease weight on an edge to its
|
|
// subedge. The subedge must be a child of the parent edge
|
|
// (either subedge->GetOrgVertex() or subedge->GetDestVertex()
|
|
// == edge->Subdivide()). The vertex supplied must NOT be
|
|
// a parent of the subedge; it is either the origin or
|
|
// destination vertex of edge.
|
|
void SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* vertex, HbrHalfedge<T>* subedge);
|
|
|
|
// Returns the expected number of children faces after subdivision
|
|
// for a face with the given number of vertices.
|
|
virtual int GetFaceChildrenCount(int nvertices) const = 0;
|
|
|
|
protected:
|
|
CreaseSubdivision creaseSubdivision;
|
|
|
|
// Helper routine for subclasses: for a given vertex, sums
|
|
// contributions from surrounding vertices
|
|
void AddSurroundingVerticesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, float weight, T* data);
|
|
|
|
// Helper routine for subclasses: for a given vertex with a crease
|
|
// mask, adds contributions from the two crease edges
|
|
void AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data);
|
|
|
|
private:
|
|
// Helper class used by AddSurroundingVerticesWithWeight
|
|
class SmoothSubdivisionVertexOperator : public HbrVertexOperator<T> {
|
|
public:
|
|
SmoothSubdivisionVertexOperator(T* data, bool meshHasEdits, float weight)
|
|
: m_data(data),
|
|
m_meshHasEdits(meshHasEdits),
|
|
m_weight(weight)
|
|
{
|
|
}
|
|
virtual void operator() (HbrVertex<T> &vertex) {
|
|
// Must ensure vertex edits have been applied
|
|
if (m_meshHasEdits) {
|
|
vertex.GuaranteeNeighbors();
|
|
}
|
|
m_data->AddWithWeight(vertex.GetData(), m_weight);
|
|
}
|
|
private:
|
|
T* m_data;
|
|
const bool m_meshHasEdits;
|
|
const float m_weight;
|
|
};
|
|
|
|
// Helper class used by AddCreaseEdgesWithWeight
|
|
class CreaseSubdivisionHalfedgeOperator : public HbrHalfedgeOperator<T> {
|
|
public:
|
|
CreaseSubdivisionHalfedgeOperator(HbrVertex<T> *vertex, T* data, bool meshHasEdits, bool next, float weight)
|
|
: m_vertex(vertex),
|
|
m_data(data),
|
|
m_meshHasEdits(meshHasEdits),
|
|
m_next(next),
|
|
m_weight(weight),
|
|
m_count(0)
|
|
{
|
|
}
|
|
virtual void operator() (HbrHalfedge<T> &edge) {
|
|
if (m_count < 2 && edge.IsSharp(m_next)) {
|
|
HbrVertex<T>* a = edge.GetDestVertex();
|
|
if (a == m_vertex) a = edge.GetOrgVertex();
|
|
// Must ensure vertex edits have been applied
|
|
if (m_meshHasEdits) {
|
|
a->GuaranteeNeighbors();
|
|
}
|
|
m_data->AddWithWeight(a->GetData(), m_weight);
|
|
m_count++;
|
|
}
|
|
}
|
|
private:
|
|
HbrVertex<T>* m_vertex;
|
|
T* m_data;
|
|
const bool m_meshHasEdits;
|
|
const bool m_next;
|
|
const float m_weight;
|
|
int m_count;
|
|
};
|
|
|
|
private:
|
|
// Helper class used by RefineAtVertex.
|
|
class RefineFaceAtVertexOperator : public HbrFaceOperator<T> {
|
|
public:
|
|
RefineFaceAtVertexOperator(HbrSubdivision<T>* subdivision, HbrMesh<T>* mesh, HbrVertex<T> *vertex)
|
|
: m_subdivision(subdivision),
|
|
m_mesh(mesh),
|
|
m_vertex(vertex)
|
|
{
|
|
}
|
|
virtual void operator() (HbrFace<T> &face) {
|
|
m_subdivision->RefineFaceAtVertex(m_mesh, &face, m_vertex);
|
|
}
|
|
private:
|
|
HbrSubdivision<T>* const m_subdivision;
|
|
HbrMesh<T>* const m_mesh;
|
|
HbrVertex<T>* const m_vertex;
|
|
};
|
|
|
|
};
|
|
|
|
template <class T>
|
|
void
|
|
HbrSubdivision<T>::RefineAtVertex(HbrMesh<T>* mesh, HbrVertex<T>* vertex) {
|
|
GuaranteeNeighbors(mesh, vertex);
|
|
RefineFaceAtVertexOperator op(this, mesh, vertex);
|
|
vertex->ApplyOperatorSurroundingFaces(op);
|
|
}
|
|
|
|
template <class T>
|
|
void
|
|
HbrSubdivision<T>::SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* vertex, HbrHalfedge<T>* subedge) {
|
|
|
|
float sharpness = edge->GetSharpness();
|
|
|
|
// In all methods, if the parent edge is infinitely sharp, the
|
|
// child edge is also infinitely sharp
|
|
if (sharpness >= HbrHalfedge<T>::k_InfinitelySharp) {
|
|
subedge->SetSharpness(HbrHalfedge<T>::k_InfinitelySharp);
|
|
}
|
|
|
|
// Chaikin's curve subdivision: use 3/4 of the parent sharpness,
|
|
// plus 1/4 of crease sharpnesses incident to vertex
|
|
else if (creaseSubdivision == HbrSubdivision<T>::k_CreaseChaikin) {
|
|
|
|
float childsharp = 0.0f;
|
|
|
|
// Add 1/4 of the sharpness of all crease edges incident to
|
|
// the vertex (other than this crease edge)
|
|
std::vector<HbrHalfedge<T>*> edges;
|
|
vertex->GuaranteeNeighbors();
|
|
vertex->GetSurroundingEdges(std::back_inserter(edges));
|
|
|
|
int n = 0;
|
|
for (typename std::vector<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {
|
|
if (*ei == edge) continue;
|
|
if ((*ei)->GetSharpness() > HbrHalfedge<T>::k_Smooth) {
|
|
childsharp += (*ei)->GetSharpness();
|
|
n++;
|
|
}
|
|
}
|
|
|
|
if (n) {
|
|
childsharp = childsharp * 0.25f / n;
|
|
}
|
|
|
|
// Add 3/4 of the sharpness of this crease edge
|
|
childsharp += sharpness * 0.75f;
|
|
childsharp -= 1.0f;
|
|
if (childsharp < (float) HbrHalfedge<T>::k_Smooth) {
|
|
childsharp = (float) HbrHalfedge<T>::k_Smooth;
|
|
}
|
|
subedge->SetSharpness(childsharp);
|
|
|
|
} else {
|
|
sharpness -= 1.0f;
|
|
if (sharpness < (float) HbrHalfedge<T>::k_Smooth) {
|
|
sharpness = (float) HbrHalfedge<T>::k_Smooth;
|
|
}
|
|
subedge->SetSharpness(sharpness);
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
void
|
|
HbrSubdivision<T>::AddSurroundingVerticesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, float weight, T* data) {
|
|
SmoothSubdivisionVertexOperator op(data, mesh->HasVertexEdits(), weight);
|
|
vertex->ApplyOperatorSurroundingVertices(op);
|
|
}
|
|
|
|
template <class T>
|
|
void
|
|
HbrSubdivision<T>::AddCreaseEdgesWithWeight(HbrMesh<T>* mesh, HbrVertex<T>* vertex, bool next, float weight, T* data) {
|
|
CreaseSubdivisionHalfedgeOperator op(vertex, data, mesh->HasVertexEdits(), next, weight);
|
|
vertex->ApplyOperatorSurroundingEdges(op);
|
|
}
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
using namespace OPENSUBDIV_VERSION;
|
|
|
|
} // end namespace OpenSubdiv
|
|
|
|
#endif /* HBRSUBDIVISION_H */
|