mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-09-19 14:20:00 +00:00
314 lines
9.0 KiB
C++
314 lines
9.0 KiB
C++
//
|
|
// Copyright 2021 Pixar
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
|
// with the following modification; you may not use this file except in
|
|
// compliance with the Apache License and the following modification to it:
|
|
// Section 6. Trademarks. is deleted and replaced with:
|
|
//
|
|
// 6. Trademarks. This License does not grant permission to use the trade
|
|
// names, trademarks, service marks, or product names of the Licensor
|
|
// and its affiliates, except as required to comply with Section 4(c) of
|
|
// the License and to reproduce the content of the NOTICE file.
|
|
//
|
|
// You may obtain a copy of the Apache License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the Apache License with the above modification is
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the Apache License for the specific
|
|
// language governing permissions and limitations under the Apache License.
|
|
//
|
|
#ifndef OPENSUBDIV3_REGRESSION_BFR_EVALUATE_TYPES_H
|
|
#define OPENSUBDIV3_REGRESSION_BFR_EVALUATE_TYPES_H
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
|
|
//
|
|
// Simple interpolatable struct for (x,y,z) positions and normals:
|
|
//
|
|
template <typename REAL>
|
|
struct Vec3 {
|
|
Vec3<REAL>() { }
|
|
Vec3<REAL>(REAL x, REAL y, REAL z) { p[0] = x, p[1] = y, p[2] = z; }
|
|
|
|
// Clear() and AddWithWeight() required for interpolation:
|
|
void Clear( void * =0 ) { p[0] = p[1] = p[2] = 0.0f; }
|
|
|
|
void AddWithWeight(Vec3<REAL> const & src, REAL weight) {
|
|
p[0] += weight * src.p[0];
|
|
p[1] += weight * src.p[1];
|
|
p[2] += weight * src.p[2];
|
|
}
|
|
|
|
// Element access via []:
|
|
REAL const & operator[](int i) const { return p[i]; }
|
|
REAL & operator[](int i) { return p[i]; }
|
|
|
|
// Element access via []:
|
|
REAL const * Coords() const { return p; }
|
|
REAL * Coords() { return p; }
|
|
|
|
// Additional useful mathematical operations:
|
|
Vec3<REAL> operator-(Vec3<REAL> const & x) const {
|
|
return Vec3<REAL>(p[0] - x.p[0], p[1] - x.p[1], p[2] - x.p[2]);
|
|
}
|
|
Vec3<REAL> operator+(Vec3<REAL> const & x) const {
|
|
return Vec3<REAL>(p[0] + x.p[0], p[1] + x.p[1], p[2] + x.p[2]);
|
|
}
|
|
Vec3<REAL> operator*(REAL s) const {
|
|
return Vec3<REAL>(p[0] * s, p[1] * s, p[2] * s);
|
|
}
|
|
Vec3<REAL> Cross(Vec3<REAL> const & x) const {
|
|
return Vec3<REAL>(p[1]*x.p[2] - p[2]*x.p[1],
|
|
p[2]*x.p[0] - p[0]*x.p[2],
|
|
p[0]*x.p[1] - p[1]*x.p[0]);
|
|
}
|
|
REAL Dot(Vec3<REAL> const & x) const {
|
|
return p[0]*x.p[0] + p[1]*x.p[1] + p[2]*x.p[2];
|
|
}
|
|
REAL Length() const {
|
|
return std::sqrt(this->Dot(*this));
|
|
}
|
|
|
|
// Static method to compute normal vector:
|
|
static
|
|
Vec3<REAL> ComputeNormal(Vec3<REAL> const & Du, Vec3<REAL> const & Dv,
|
|
REAL eps = 0.0f) {
|
|
Vec3<REAL> N = Du.Cross(Dv);
|
|
REAL lenSqrd = N.Dot(N);
|
|
if (lenSqrd <= eps) return Vec3<REAL>(0.0f, 0.0f, 0.0f);
|
|
return N * (1.0f / std::sqrt(lenSqrd));
|
|
}
|
|
|
|
// Member variables (XYZ coordinates):
|
|
REAL p[3];
|
|
};
|
|
|
|
typedef Vec3<float> Vec3f;
|
|
typedef Vec3<double> Vec3d;
|
|
|
|
|
|
//
|
|
// Simple struct to hold the results of a face evaluation:
|
|
//
|
|
template <typename REAL>
|
|
struct EvalResults {
|
|
EvalResults() : evalPosition(true),
|
|
eval1stDeriv(true),
|
|
eval2ndDeriv(false),
|
|
evalUV(false),
|
|
useStencils(false) { }
|
|
|
|
bool evalPosition;
|
|
bool eval1stDeriv;
|
|
bool eval2ndDeriv;
|
|
bool evalUV;
|
|
bool useStencils;
|
|
|
|
std::vector< Vec3<REAL> > p;
|
|
std::vector< Vec3<REAL> > du;
|
|
std::vector< Vec3<REAL> > dv;
|
|
std::vector< Vec3<REAL> > duu;
|
|
std::vector< Vec3<REAL> > duv;
|
|
std::vector< Vec3<REAL> > dvv;
|
|
|
|
std::vector< Vec3<REAL> > uv;
|
|
|
|
void Resize(int size) {
|
|
if (evalPosition) {
|
|
p.resize(size);
|
|
if (eval1stDeriv) {
|
|
du.resize(size);
|
|
dv.resize(size);
|
|
if (eval2ndDeriv) {
|
|
duu.resize(size);
|
|
duv.resize(size);
|
|
dvv.resize(size);
|
|
}
|
|
}
|
|
}
|
|
if (evalUV) {
|
|
uv.resize(size);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// Simple struct to hold the differences between two vectors:
|
|
//
|
|
template <typename REAL>
|
|
class VectorDelta {
|
|
public:
|
|
typedef std::vector< Vec3<REAL> > VectorVec3;
|
|
|
|
public:
|
|
// Member variables:
|
|
std::vector< Vec3<REAL> > const * vectorA;
|
|
std::vector< Vec3<REAL> > const * vectorB;
|
|
|
|
int numDeltas;
|
|
REAL maxDelta;
|
|
REAL tolerance;
|
|
|
|
public:
|
|
VectorDelta(REAL epsilon = 0.0f) :
|
|
vectorA(0), vectorB(0),
|
|
numDeltas(0), maxDelta(0.0f),
|
|
tolerance(epsilon) { }
|
|
|
|
void
|
|
Compare(VectorVec3 const & a, VectorVec3 const & b) {
|
|
|
|
assert(a.size() == b.size());
|
|
|
|
vectorA = &a;
|
|
vectorB = &b;
|
|
|
|
numDeltas = 0;
|
|
maxDelta = 0.0f;
|
|
|
|
for (size_t i = 0; i < a.size(); ++i) {
|
|
REAL const * ai = a[i].Coords();
|
|
REAL const * bi = b[i].Coords();
|
|
|
|
REAL dx = std::abs(ai[0] - bi[0]);
|
|
REAL dy = std::abs(ai[1] - bi[1]);
|
|
REAL dz = std::abs(ai[2] - bi[2]);
|
|
if ((dx > tolerance) || (dy > tolerance) || (dz > tolerance)) {
|
|
++ numDeltas;
|
|
|
|
if (maxDelta < dx) maxDelta = dx;
|
|
if (maxDelta < dy) maxDelta = dy;
|
|
if (maxDelta < dz) maxDelta = dz;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename REAL>
|
|
class FaceDelta {
|
|
public:
|
|
// Member variables:
|
|
bool hasDeltas;
|
|
bool hasGeomDeltas;
|
|
bool hasUVDeltas;
|
|
|
|
int numPDeltas;
|
|
int numD1Deltas;
|
|
int numD2Deltas;
|
|
int numUVDeltas;
|
|
|
|
REAL maxPDelta;
|
|
REAL maxD1Delta;
|
|
REAL maxD2Delta;
|
|
REAL maxUVDelta;
|
|
|
|
public:
|
|
FaceDelta() { Clear(); }
|
|
|
|
void Clear() {
|
|
std::memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
void AddPDelta(VectorDelta<REAL> const & pDelta) {
|
|
if (pDelta.numDeltas) {
|
|
numPDeltas = pDelta.numDeltas;
|
|
maxPDelta = pDelta.maxDelta;
|
|
hasDeltas = hasGeomDeltas = true;
|
|
}
|
|
}
|
|
void AddDuDelta(VectorDelta<REAL> const & duDelta) {
|
|
if (duDelta.numDeltas) {
|
|
numD1Deltas += duDelta.numDeltas;
|
|
maxD1Delta = std::max(maxD1Delta, duDelta.maxDelta);
|
|
hasDeltas = hasGeomDeltas = true;
|
|
}
|
|
}
|
|
void AddDvDelta(VectorDelta<REAL> const & dvDelta) {
|
|
if (dvDelta.numDeltas) {
|
|
numD1Deltas += dvDelta.numDeltas;
|
|
maxD1Delta = std::max(maxD1Delta, dvDelta.maxDelta);
|
|
hasDeltas = hasGeomDeltas = true;
|
|
}
|
|
}
|
|
void AddDuuDelta(VectorDelta<REAL> const & duuDelta) {
|
|
if (duuDelta.numDeltas) {
|
|
numD2Deltas += duuDelta.numDeltas;
|
|
maxD2Delta = std::max(maxD2Delta, duuDelta.maxDelta);
|
|
hasDeltas = hasGeomDeltas = true;
|
|
}
|
|
}
|
|
void AddDuvDelta(VectorDelta<REAL> const & duvDelta) {
|
|
if (duvDelta.numDeltas) {
|
|
numD2Deltas += duvDelta.numDeltas;
|
|
maxD2Delta = std::max(maxD2Delta, duvDelta.maxDelta);
|
|
hasDeltas = hasGeomDeltas = true;
|
|
}
|
|
}
|
|
void AddDvvDelta(VectorDelta<REAL> const & dvvDelta) {
|
|
if (dvvDelta.numDeltas) {
|
|
numD2Deltas += dvvDelta.numDeltas;
|
|
maxD2Delta = std::max(maxD2Delta, dvvDelta.maxDelta);
|
|
hasDeltas = hasGeomDeltas = true;
|
|
}
|
|
}
|
|
void AddUVDelta(VectorDelta<REAL> const & uvDelta) {
|
|
if (uvDelta.numDeltas) {
|
|
numUVDeltas = uvDelta.numDeltas;
|
|
maxUVDelta = uvDelta.maxDelta;
|
|
hasDeltas = hasUVDeltas = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename REAL>
|
|
class MeshDelta {
|
|
public:
|
|
// Member variables:
|
|
int numFacesWithDeltas;
|
|
int numFacesWithGeomDeltas;
|
|
int numFacesWithUVDeltas;
|
|
|
|
int numFacesWithPDeltas;
|
|
int numFacesWithD1Deltas;
|
|
int numFacesWithD2Deltas;
|
|
|
|
REAL maxPDelta;
|
|
REAL maxD1Delta;
|
|
REAL maxD2Delta;
|
|
REAL maxUVDelta;
|
|
|
|
public:
|
|
MeshDelta() { Clear(); }
|
|
|
|
void Clear() {
|
|
std::memset(this, 0, sizeof(*this));
|
|
}
|
|
|
|
void AddFace(FaceDelta<REAL> const & faceDelta) {
|
|
|
|
numFacesWithDeltas += faceDelta.hasDeltas;
|
|
numFacesWithGeomDeltas += faceDelta.hasGeomDeltas;
|
|
numFacesWithUVDeltas += faceDelta.hasUVDeltas;
|
|
|
|
numFacesWithPDeltas += (faceDelta.numPDeltas > 0);
|
|
numFacesWithD1Deltas += (faceDelta.numD1Deltas > 0);
|
|
numFacesWithD2Deltas += (faceDelta.numD2Deltas > 0);
|
|
|
|
maxPDelta = std::max(maxPDelta, faceDelta.maxPDelta);
|
|
maxD1Delta = std::max(maxD1Delta, faceDelta.maxD1Delta);
|
|
maxD2Delta = std::max(maxD2Delta, faceDelta.maxD2Delta);
|
|
maxUVDelta = std::max(maxUVDelta, faceDelta.maxUVDelta);
|
|
}
|
|
};
|
|
|
|
#endif /* OPENSUBDIV3_REGRESSION_BFR_EVALUATE_TYPES_H */
|