Refactor: Simplify subd patch code
* Remove unused linear patch normals * Renaming for consistency and clarity * Shuffle order of function definitions Pull Request: https://projects.blender.org/blender/blender/pulls/135681
This commit is contained in:
@@ -39,12 +39,8 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
subdivision_type = SUBDIVISION_LINEAR;
|
||||
}
|
||||
|
||||
const int num_faces = get_num_subd_faces();
|
||||
|
||||
Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
|
||||
float3 *vN = (attr_vN) ? attr_vN->data_float3() : nullptr;
|
||||
|
||||
/* count patches */
|
||||
const int num_faces = get_num_subd_faces();
|
||||
int num_patches = 0;
|
||||
for (int f = 0; f < num_faces; f++) {
|
||||
SubdFace face = get_subd_face(f);
|
||||
@@ -97,7 +93,6 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
if (face.is_quad()) {
|
||||
/* Simple quad case. */
|
||||
float3 *hull = patch->hull;
|
||||
float3 *normals = patch->normals;
|
||||
|
||||
patch->patch_index = face.ptex_offset;
|
||||
patch->from_ngon = false;
|
||||
@@ -106,20 +101,7 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
hull[i] = verts[subd_face_corners[face.start_corner + i]];
|
||||
}
|
||||
|
||||
if (face.smooth) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
normals[i] = vN[subd_face_corners[face.start_corner + i]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
const float3 N = face.normal(this);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
normals[i] = N;
|
||||
}
|
||||
}
|
||||
|
||||
swap(hull[2], hull[3]);
|
||||
swap(normals[2], normals[3]);
|
||||
|
||||
patch->shader = face.shader;
|
||||
patch++;
|
||||
@@ -127,17 +109,14 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
else {
|
||||
/* N-gon split into N quads. */
|
||||
float3 center_vert = zero_float3();
|
||||
float3 center_normal = zero_float3();
|
||||
|
||||
const float inv_num_corners = 1.0f / float(face.num_corners);
|
||||
for (int corner = 0; corner < face.num_corners; corner++) {
|
||||
center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
|
||||
center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
|
||||
}
|
||||
|
||||
for (int corner = 0; corner < face.num_corners; corner++) {
|
||||
float3 *hull = patch->hull;
|
||||
float3 *normals = patch->normals;
|
||||
|
||||
patch->patch_index = face.ptex_offset + corner;
|
||||
patch->from_ngon = true;
|
||||
@@ -155,25 +134,6 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
hull[1] = (hull[1] + hull[0]) * 0.5;
|
||||
hull[2] = (hull[2] + hull[0]) * 0.5;
|
||||
|
||||
if (face.smooth) {
|
||||
normals[0] =
|
||||
vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
|
||||
normals[1] =
|
||||
vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
|
||||
normals[2] =
|
||||
vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
|
||||
normals[3] = center_normal;
|
||||
|
||||
normals[1] = (normals[1] + normals[0]) * 0.5;
|
||||
normals[2] = (normals[2] + normals[0]) * 0.5;
|
||||
}
|
||||
else {
|
||||
const float3 N = face.normal(this);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
normals[i] = N;
|
||||
}
|
||||
}
|
||||
|
||||
patch++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ void EdgeDice::reserve(const int num_verts, const int num_triangles)
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeDice::set_vert(Patch *patch, const int index, const float2 uv)
|
||||
void EdgeDice::set_vert(const Patch *patch, const int index, const float2 uv)
|
||||
{
|
||||
float3 P;
|
||||
float3 N;
|
||||
@@ -89,7 +89,7 @@ void EdgeDice::add_triangle(const Patch *patch,
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeDice::stitch_triangles(Subpatch &sub, const int edge)
|
||||
void EdgeDice::stitch_triangles(SubPatch &sub, const int edge)
|
||||
{
|
||||
int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
|
||||
int Mv = max(sub.edge_v0.T, sub.edge_v1.T);
|
||||
@@ -184,7 +184,7 @@ void EdgeDice::stitch_triangles(Subpatch &sub, const int edge)
|
||||
|
||||
QuadDice::QuadDice(const SubdParams ¶ms_) : EdgeDice(params_) {}
|
||||
|
||||
float3 QuadDice::eval_projected(Subpatch &sub, const float2 uv)
|
||||
float3 QuadDice::eval_projected(SubPatch &sub, const float2 uv)
|
||||
{
|
||||
float3 P;
|
||||
|
||||
@@ -196,12 +196,12 @@ float3 QuadDice::eval_projected(Subpatch &sub, const float2 uv)
|
||||
return P;
|
||||
}
|
||||
|
||||
void QuadDice::set_vert(Subpatch &sub, const int index, const float2 uv)
|
||||
void QuadDice::set_vert(SubPatch &sub, const int index, const float2 uv)
|
||||
{
|
||||
EdgeDice::set_vert(sub.patch, index, sub.map_uv(uv));
|
||||
}
|
||||
|
||||
void QuadDice::set_side(Subpatch &sub, const int edge)
|
||||
void QuadDice::set_side(SubPatch &sub, const int edge)
|
||||
{
|
||||
const int t = sub.edges[edge].T;
|
||||
|
||||
@@ -235,7 +235,7 @@ float QuadDice::quad_area(const float3 &a, const float3 &b, const float3 &c, con
|
||||
return triangle_area(a, b, d) + triangle_area(a, d, c);
|
||||
}
|
||||
|
||||
float QuadDice::scale_factor(Subpatch &sub, const int Mu, const int Mv)
|
||||
float QuadDice::scale_factor(SubPatch &sub, const int Mu, const int Mv)
|
||||
{
|
||||
/* estimate area as 4x largest of 4 quads */
|
||||
float3 P[3][3];
|
||||
@@ -266,7 +266,7 @@ float QuadDice::scale_factor(Subpatch &sub, const int Mu, const int Mv)
|
||||
return S;
|
||||
}
|
||||
|
||||
void QuadDice::add_grid(Subpatch &sub, const int Mu, const int Mv, const int offset)
|
||||
void QuadDice::add_grid(SubPatch &sub, const int Mu, const int Mv, const int offset)
|
||||
{
|
||||
/* create inner grid */
|
||||
const float du = 1.0f / (float)Mu;
|
||||
@@ -298,7 +298,7 @@ void QuadDice::add_grid(Subpatch &sub, const int Mu, const int Mv, const int off
|
||||
}
|
||||
}
|
||||
|
||||
void QuadDice::dice(Subpatch &sub)
|
||||
void QuadDice::dice(SubPatch &sub)
|
||||
{
|
||||
/* compute inner grid size with scale factor */
|
||||
int Mu = max(sub.edge_u0.T, sub.edge_u1.T);
|
||||
|
||||
@@ -49,7 +49,7 @@ class EdgeDice {
|
||||
void reserve(const int num_verts, const int num_triangles);
|
||||
|
||||
protected:
|
||||
void set_vert(Patch *patch, const int index, const float2 uv);
|
||||
void set_vert(const Patch *patch, const int index, const float2 uv);
|
||||
void add_triangle(const Patch *patch,
|
||||
const int v0,
|
||||
const int v1,
|
||||
@@ -58,7 +58,7 @@ class EdgeDice {
|
||||
const float2 uv1,
|
||||
const float2 uv2);
|
||||
|
||||
void stitch_triangles(Subpatch &sub, const int edge);
|
||||
void stitch_triangles(SubPatch &sub, const int edge);
|
||||
};
|
||||
|
||||
/* Quad EdgeDice */
|
||||
@@ -67,19 +67,19 @@ class QuadDice : public EdgeDice {
|
||||
public:
|
||||
explicit QuadDice(const SubdParams ¶ms);
|
||||
|
||||
void dice(Subpatch &sub);
|
||||
void dice(SubPatch &sub);
|
||||
|
||||
protected:
|
||||
float3 eval_projected(Subpatch &sub, const float2 uv);
|
||||
float3 eval_projected(SubPatch &sub, const float2 uv);
|
||||
|
||||
void set_vert(Subpatch &sub, const int index, const float2 uv);
|
||||
void set_vert(SubPatch &sub, const int index, const float2 uv);
|
||||
|
||||
void add_grid(Subpatch &sub, const int Mu, const int Mv, const int offset);
|
||||
void add_grid(SubPatch &sub, const int Mu, const int Mv, const int offset);
|
||||
|
||||
void set_side(Subpatch &sub, const int edge);
|
||||
void set_side(SubPatch &sub, const int edge);
|
||||
|
||||
float quad_area(const float3 &a, const float3 &b, const float3 &c, const float3 &d);
|
||||
float scale_factor(Subpatch &sub, const int Mu, const int Mv);
|
||||
float scale_factor(SubPatch &sub, const int Mu, const int Mv);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -362,7 +362,8 @@ void OsdData::build(OsdMesh &osd_mesh)
|
||||
|
||||
/* OsdPatch */
|
||||
|
||||
void OsdPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, const float v)
|
||||
void OsdPatch::eval(
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, const float v) const
|
||||
{
|
||||
const Far::PatchTable::PatchHandle &handle = *osd_data.patch_map->FindPatch(
|
||||
patch_index, (double)u, (double)v);
|
||||
@@ -372,13 +373,11 @@ void OsdPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const floa
|
||||
|
||||
const Far::ConstIndexArray cv = osd_data.patch_table->GetPatchVertices(handle);
|
||||
|
||||
float3 du;
|
||||
float3 dv;
|
||||
if (P) {
|
||||
*P = zero_float3();
|
||||
}
|
||||
du = zero_float3();
|
||||
dv = zero_float3();
|
||||
float3 du = zero_float3();
|
||||
float3 dv = zero_float3();
|
||||
|
||||
for (int i = 0; i < cv.size(); i++) {
|
||||
const float3 p = osd_data.refined_verts[cv[i]].value;
|
||||
@@ -397,10 +396,7 @@ void OsdPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const floa
|
||||
*dPdv = dv;
|
||||
}
|
||||
if (N) {
|
||||
*N = cross(du, dv);
|
||||
|
||||
const float t = len(*N);
|
||||
*N = (t != 0.0f) ? *N / t : make_float3(0.0f, 0.0f, 1.0f);
|
||||
*N = safe_normalize_fallback(cross(du, dv), make_float3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,8 @@ struct OsdPatch final : Patch {
|
||||
OsdData &osd_data;
|
||||
|
||||
explicit OsdPatch(OsdData &data) : osd_data(data) {}
|
||||
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) override;
|
||||
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, const float v)
|
||||
const override;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
@@ -50,21 +50,25 @@ static void decasteljau_bicubic(
|
||||
/* Linear Quad Patch */
|
||||
|
||||
void LinearQuadPatch::eval(
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v)
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) const
|
||||
{
|
||||
const float3 d0 = interp(hull[0], hull[1], u);
|
||||
const float3 d1 = interp(hull[2], hull[3], u);
|
||||
|
||||
*P = interp(d0, d1, v);
|
||||
|
||||
if (dPdu && dPdv) {
|
||||
*dPdu = interp(hull[1] - hull[0], hull[3] - hull[2], v);
|
||||
*dPdv = interp(hull[2] - hull[0], hull[3] - hull[1], u);
|
||||
}
|
||||
if (N || (dPdu && dPdv)) {
|
||||
const float3 dPdu_ = interp(hull[1] - hull[0], hull[3] - hull[2], v);
|
||||
const float3 dPdv_ = interp(hull[2] - hull[0], hull[3] - hull[1], u);
|
||||
|
||||
if (N) {
|
||||
*N = normalize(
|
||||
interp(interp(normals[0], normals[1], u), interp(normals[2], normals[3], u), v));
|
||||
if (dPdu && dPdv) {
|
||||
*dPdu = dPdu_;
|
||||
*dPdv = dPdv_;
|
||||
}
|
||||
|
||||
if (N) {
|
||||
*N = normalize(cross(dPdu_, dPdv_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +85,8 @@ BoundBox LinearQuadPatch::bound()
|
||||
|
||||
/* Bicubic Patch */
|
||||
|
||||
void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v)
|
||||
void BicubicPatch::eval(
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, const float v) const
|
||||
{
|
||||
if (N) {
|
||||
float3 dPdu_;
|
||||
|
||||
@@ -12,10 +12,10 @@ CCL_NAMESPACE_BEGIN
|
||||
class Patch {
|
||||
public:
|
||||
Patch() = default;
|
||||
|
||||
virtual ~Patch() = default;
|
||||
|
||||
virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) = 0;
|
||||
virtual void eval(
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) const = 0;
|
||||
|
||||
int patch_index = 0;
|
||||
int shader = 0;
|
||||
@@ -24,22 +24,23 @@ class Patch {
|
||||
|
||||
/* Linear Quad Patch */
|
||||
|
||||
class LinearQuadPatch : public Patch {
|
||||
class LinearQuadPatch final : public Patch {
|
||||
public:
|
||||
float3 hull[4];
|
||||
float3 normals[4];
|
||||
|
||||
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) override;
|
||||
void eval(
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) const override;
|
||||
BoundBox bound();
|
||||
};
|
||||
|
||||
/* Bicubic Patch */
|
||||
|
||||
class BicubicPatch : public Patch {
|
||||
class BicubicPatch final : public Patch {
|
||||
public:
|
||||
float3 hull[16];
|
||||
|
||||
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) override;
|
||||
void eval(
|
||||
float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, const float u, float v) const override;
|
||||
BoundBox bound();
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ enum {
|
||||
|
||||
DiagSplit::DiagSplit(const SubdParams ¶ms_) : params(params_) {}
|
||||
|
||||
float3 DiagSplit::to_world(Patch *patch, const float2 uv)
|
||||
float3 DiagSplit::to_world(const Patch *patch, const float2 uv)
|
||||
{
|
||||
float3 P;
|
||||
|
||||
@@ -46,7 +46,7 @@ static void order_float2(float2 &a, float2 &b)
|
||||
}
|
||||
}
|
||||
|
||||
int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend, const bool recursive_resolve)
|
||||
int DiagSplit::T(const Patch *patch, float2 Pstart, float2 Pend, const bool recursive_resolve)
|
||||
{
|
||||
order_float2(Pstart, Pend); /* May not be necessary, but better to be safe. */
|
||||
|
||||
@@ -98,8 +98,13 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend, const bool recursive_
|
||||
return res;
|
||||
}
|
||||
|
||||
void DiagSplit::partition_edge(
|
||||
Patch *patch, float2 *P, int *t0, int *t1, const float2 Pstart, const float2 Pend, const int t)
|
||||
void DiagSplit::partition_edge(const Patch *patch,
|
||||
float2 *P,
|
||||
int *t0,
|
||||
int *t1,
|
||||
const float2 Pstart,
|
||||
const float2 Pend,
|
||||
const int t)
|
||||
{
|
||||
if (t == DSPLIT_NON_UNIFORM) {
|
||||
*P = (Pstart + Pend) * 0.5f;
|
||||
@@ -116,7 +121,10 @@ void DiagSplit::partition_edge(
|
||||
}
|
||||
}
|
||||
|
||||
void DiagSplit::limit_edge_factor(int &T, Patch *patch, const float2 Pstart, const float2 Pend)
|
||||
void DiagSplit::limit_edge_factor(int &T,
|
||||
const Patch *patch,
|
||||
const float2 Pstart,
|
||||
const float2 Pend)
|
||||
{
|
||||
const int max_t = 1 << params.max_level;
|
||||
int max_t_for_edge = int(max_t * len(Pstart - Pend));
|
||||
@@ -130,24 +138,24 @@ void DiagSplit::limit_edge_factor(int &T, Patch *patch, const float2 Pstart, con
|
||||
assert(T >= 1 || T == DSPLIT_NON_UNIFORM);
|
||||
}
|
||||
|
||||
void DiagSplit::resolve_edge_factors(Subpatch &sub)
|
||||
void DiagSplit::resolve_edge_factors(SubPatch &sub)
|
||||
{
|
||||
/* Resolve DSPLIT_NON_UNIFORM to actual T value if splitting is no longer possible. */
|
||||
if (sub.edge_u0.T == 1 && sub.edge_u1.T == DSPLIT_NON_UNIFORM) {
|
||||
sub.edge_u1.T = T(sub.patch, sub.c01, sub.c11, true);
|
||||
sub.edge_u1.T = T(sub.patch, sub.uv01, sub.uv11, true);
|
||||
}
|
||||
if (sub.edge_u1.T == 1 && sub.edge_u0.T == DSPLIT_NON_UNIFORM) {
|
||||
sub.edge_u0.T = T(sub.patch, sub.c00, sub.c10, true);
|
||||
sub.edge_u0.T = T(sub.patch, sub.uv00, sub.uv10, true);
|
||||
}
|
||||
if (sub.edge_v0.T == 1 && sub.edge_v1.T == DSPLIT_NON_UNIFORM) {
|
||||
sub.edge_v1.T = T(sub.patch, sub.c11, sub.c10, true);
|
||||
sub.edge_v1.T = T(sub.patch, sub.uv11, sub.uv10, true);
|
||||
}
|
||||
if (sub.edge_v1.T == 1 && sub.edge_v0.T == DSPLIT_NON_UNIFORM) {
|
||||
sub.edge_v0.T = T(sub.patch, sub.c01, sub.c00, true);
|
||||
sub.edge_v0.T = T(sub.patch, sub.uv01, sub.uv00, true);
|
||||
}
|
||||
}
|
||||
|
||||
void DiagSplit::split(Subpatch &sub, const int depth)
|
||||
void DiagSplit::split(SubPatch &sub, const int depth)
|
||||
{
|
||||
if (depth > 32) {
|
||||
/* We should never get here, but just in case end recursion safely. */
|
||||
@@ -191,11 +199,11 @@ void DiagSplit::split(Subpatch &sub, const int depth)
|
||||
if (!split_u && !split_v) {
|
||||
/* Add the unsplit subpatch. */
|
||||
subpatches.push_back(sub);
|
||||
Subpatch &subpatch = subpatches[subpatches.size() - 1];
|
||||
SubPatch &subpatch = subpatches[subpatches.size() - 1];
|
||||
|
||||
/* Update T values and offsets. */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Subpatch::edge_t &edge = subpatch.edges[i];
|
||||
SubPatch::Edge &edge = subpatch.edges[i];
|
||||
|
||||
edge.offset = edge.edge->T;
|
||||
edge.edge->T += edge.T;
|
||||
@@ -203,19 +211,19 @@ void DiagSplit::split(Subpatch &sub, const int depth)
|
||||
}
|
||||
else {
|
||||
/* Copy into new subpatches. */
|
||||
Subpatch sub_a = sub;
|
||||
Subpatch sub_b = sub;
|
||||
SubPatch sub_a = sub;
|
||||
SubPatch sub_b = sub;
|
||||
|
||||
/* Pointers to various subpatch elements. */
|
||||
Subpatch::edge_t *sub_across_0;
|
||||
Subpatch::edge_t *sub_across_1;
|
||||
Subpatch::edge_t *sub_a_across_0;
|
||||
Subpatch::edge_t *sub_a_across_1;
|
||||
Subpatch::edge_t *sub_b_across_0;
|
||||
Subpatch::edge_t *sub_b_across_1;
|
||||
SubPatch::Edge *sub_across_0;
|
||||
SubPatch::Edge *sub_across_1;
|
||||
SubPatch::Edge *sub_a_across_0;
|
||||
SubPatch::Edge *sub_a_across_1;
|
||||
SubPatch::Edge *sub_b_across_0;
|
||||
SubPatch::Edge *sub_b_across_1;
|
||||
|
||||
Subpatch::edge_t *sub_a_split;
|
||||
Subpatch::edge_t *sub_b_split;
|
||||
SubPatch::Edge *sub_a_split;
|
||||
SubPatch::Edge *sub_b_split;
|
||||
|
||||
float2 *Pa;
|
||||
float2 *Pb;
|
||||
@@ -234,10 +242,10 @@ void DiagSplit::split(Subpatch &sub, const int depth)
|
||||
sub_a_split = &sub_a.edge_v1;
|
||||
sub_b_split = &sub_b.edge_v0;
|
||||
|
||||
Pa = &sub_a.c11;
|
||||
Pb = &sub_a.c10;
|
||||
Pc = &sub_b.c01;
|
||||
Pd = &sub_b.c00;
|
||||
Pa = &sub_a.uv11;
|
||||
Pb = &sub_a.uv10;
|
||||
Pc = &sub_b.uv01;
|
||||
Pd = &sub_b.uv00;
|
||||
}
|
||||
else {
|
||||
sub_across_0 = &sub.edge_v0;
|
||||
@@ -250,10 +258,10 @@ void DiagSplit::split(Subpatch &sub, const int depth)
|
||||
sub_a_split = &sub_a.edge_u0;
|
||||
sub_b_split = &sub_b.edge_u1;
|
||||
|
||||
Pa = &sub_a.c10;
|
||||
Pb = &sub_a.c00;
|
||||
Pc = &sub_b.c11;
|
||||
Pd = &sub_b.c01;
|
||||
Pa = &sub_a.uv10;
|
||||
Pb = &sub_a.uv00;
|
||||
Pc = &sub_b.uv11;
|
||||
Pd = &sub_b.uv01;
|
||||
}
|
||||
|
||||
/* Partition edges */
|
||||
@@ -285,7 +293,7 @@ void DiagSplit::split(Subpatch &sub, const int depth)
|
||||
resolve_edge_factors(sub_b);
|
||||
|
||||
/* Create new edge */
|
||||
Edge &edge = *alloc_edge();
|
||||
SubEdge &edge = *alloc_edge();
|
||||
|
||||
sub_a_split->edge = &edge;
|
||||
sub_b_split->edge = &edge;
|
||||
@@ -329,20 +337,20 @@ int DiagSplit::alloc_verts(const int n)
|
||||
return a;
|
||||
}
|
||||
|
||||
Edge *DiagSplit::alloc_edge()
|
||||
SubEdge *DiagSplit::alloc_edge()
|
||||
{
|
||||
edges.emplace_back();
|
||||
return &edges.back();
|
||||
}
|
||||
|
||||
void DiagSplit::split_patches(Patch *patches, const size_t patches_byte_stride)
|
||||
void DiagSplit::split_patches(const Patch *patches, const size_t patches_byte_stride)
|
||||
{
|
||||
int patch_index = 0;
|
||||
|
||||
for (int f = 0; f < params.mesh->get_num_subd_faces(); f++) {
|
||||
Mesh::SubdFace face = params.mesh->get_subd_face(f);
|
||||
|
||||
Patch *patch = (Patch *)(((char *)patches) + patch_index * patches_byte_stride);
|
||||
const Patch *patch = (const Patch *)(((char *)patches) + patch_index * patches_byte_stride);
|
||||
|
||||
if (face.is_quad()) {
|
||||
patch_index++;
|
||||
@@ -362,13 +370,13 @@ void DiagSplit::split_patches(Patch *patches, const size_t patches_byte_stride)
|
||||
post_split();
|
||||
}
|
||||
|
||||
static Edge *create_edge_from_corner(DiagSplit *split,
|
||||
const Mesh *mesh,
|
||||
const Mesh::SubdFace &face,
|
||||
const int corner,
|
||||
bool &reversed,
|
||||
int v0,
|
||||
int v1)
|
||||
static SubEdge *create_edge_from_corner(DiagSplit *split,
|
||||
const Mesh *mesh,
|
||||
const Mesh::SubdFace &face,
|
||||
const int corner,
|
||||
bool &reversed,
|
||||
int v0,
|
||||
int v1)
|
||||
{
|
||||
int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
|
||||
int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
|
||||
@@ -380,7 +388,7 @@ static Edge *create_edge_from_corner(DiagSplit *split,
|
||||
swap(v0, v1);
|
||||
}
|
||||
|
||||
Edge *edge = split->alloc_edge();
|
||||
SubEdge *edge = split->alloc_edge();
|
||||
|
||||
edge->is_stitch_edge = true;
|
||||
edge->stitch_start_vert_index = a;
|
||||
@@ -394,9 +402,9 @@ static Edge *create_edge_from_corner(DiagSplit *split,
|
||||
return edge;
|
||||
}
|
||||
|
||||
void DiagSplit::split_quad(const Mesh::SubdFace &face, Patch *patch)
|
||||
void DiagSplit::split_quad(const Mesh::SubdFace &face, const Patch *patch)
|
||||
{
|
||||
Subpatch subpatch(patch);
|
||||
SubPatch subpatch(patch);
|
||||
|
||||
const int v = alloc_verts(4);
|
||||
|
||||
@@ -432,17 +440,17 @@ void DiagSplit::split_quad(const Mesh::SubdFace &face, Patch *patch)
|
||||
split(subpatch, -2);
|
||||
}
|
||||
|
||||
static Edge *create_split_edge_from_corner(DiagSplit *split,
|
||||
const Mesh *mesh,
|
||||
const Mesh::SubdFace &face,
|
||||
const int corner,
|
||||
const int side,
|
||||
bool &reversed,
|
||||
int v0,
|
||||
int v1,
|
||||
const int vc)
|
||||
static SubEdge *create_split_edge_from_corner(DiagSplit *split,
|
||||
const Mesh *mesh,
|
||||
const Mesh::SubdFace &face,
|
||||
const int corner,
|
||||
const int side,
|
||||
bool &reversed,
|
||||
int v0,
|
||||
int v1,
|
||||
const int vc)
|
||||
{
|
||||
Edge *edge = split->alloc_edge();
|
||||
SubEdge *edge = split->alloc_edge();
|
||||
|
||||
int a = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 0, face.num_corners)];
|
||||
int b = mesh->get_subd_face_corners()[face.start_corner + mod(corner + 1, face.num_corners)];
|
||||
@@ -479,22 +487,22 @@ static Edge *create_split_edge_from_corner(DiagSplit *split,
|
||||
}
|
||||
|
||||
void DiagSplit::split_ngon(const Mesh::SubdFace &face,
|
||||
Patch *patches,
|
||||
const Patch *patches,
|
||||
const size_t patches_byte_stride)
|
||||
{
|
||||
Edge *prev_edge_u0 = nullptr;
|
||||
Edge *first_edge_v0 = nullptr;
|
||||
SubEdge *prev_edge_u0 = nullptr;
|
||||
SubEdge *first_edge_v0 = nullptr;
|
||||
|
||||
for (int corner = 0; corner < face.num_corners; corner++) {
|
||||
Patch *patch = (Patch *)(((char *)patches) + corner * patches_byte_stride);
|
||||
const Patch *patch = (const Patch *)(((char *)patches) + corner * patches_byte_stride);
|
||||
|
||||
Subpatch subpatch(patch);
|
||||
SubPatch subpatch(patch);
|
||||
|
||||
const int v = alloc_verts(4);
|
||||
|
||||
/* Setup edges. */
|
||||
Edge *edge_u1 = alloc_edge();
|
||||
Edge *edge_v1 = alloc_edge();
|
||||
SubEdge *edge_u1 = alloc_edge();
|
||||
SubEdge *edge_v1 = alloc_edge();
|
||||
|
||||
edge_v1->is_stitch_edge = true;
|
||||
edge_u1->is_stitch_edge = true;
|
||||
@@ -555,10 +563,10 @@ void DiagSplit::split_ngon(const Mesh::SubdFace &face,
|
||||
|
||||
/* Perform split. */
|
||||
{
|
||||
subpatch.edge_u0.T = T(subpatch.patch, subpatch.c00, subpatch.c10);
|
||||
subpatch.edge_u1.T = T(subpatch.patch, subpatch.c01, subpatch.c11);
|
||||
subpatch.edge_v0.T = T(subpatch.patch, subpatch.c00, subpatch.c01);
|
||||
subpatch.edge_v1.T = T(subpatch.patch, subpatch.c10, subpatch.c11);
|
||||
subpatch.edge_u0.T = T(subpatch.patch, subpatch.uv00, subpatch.uv10);
|
||||
subpatch.edge_u1.T = T(subpatch.patch, subpatch.uv01, subpatch.uv11);
|
||||
subpatch.edge_v0.T = T(subpatch.patch, subpatch.uv00, subpatch.uv01);
|
||||
subpatch.edge_v1.T = T(subpatch.patch, subpatch.uv10, subpatch.uv11);
|
||||
|
||||
resolve_edge_factors(subpatch);
|
||||
|
||||
@@ -611,7 +619,7 @@ void DiagSplit::post_split()
|
||||
|
||||
/* All patches are now split, and all T values known. */
|
||||
|
||||
for (Edge &edge : edges) {
|
||||
for (SubEdge &edge : edges) {
|
||||
if (edge.second_vert_index < 0) {
|
||||
edge.second_vert_index = alloc_verts(edge.T - 1);
|
||||
}
|
||||
@@ -634,7 +642,7 @@ void DiagSplit::post_split()
|
||||
using edge_stitch_verts_map_t = unordered_map<pair<int, int>, int, pair_hasher>;
|
||||
edge_stitch_verts_map_t edge_stitch_verts_map;
|
||||
|
||||
for (Edge &edge : edges) {
|
||||
for (SubEdge &edge : edges) {
|
||||
if (edge.is_stitch_edge) {
|
||||
if (edge.stitch_edge_T == 0) {
|
||||
edge.stitch_edge_T = edge.T;
|
||||
@@ -648,7 +656,7 @@ void DiagSplit::post_split()
|
||||
}
|
||||
|
||||
/* Set start and end indices for edges generated from a split. */
|
||||
for (Edge &edge : edges) {
|
||||
for (SubEdge &edge : edges) {
|
||||
if (edge.start_vert_index < 0) {
|
||||
/* Fix up offsets. */
|
||||
if (edge.top_indices_decrease) {
|
||||
@@ -670,7 +678,7 @@ void DiagSplit::post_split()
|
||||
const int vert_offset = params.mesh->verts.size();
|
||||
|
||||
/* Add verts to stitching map. */
|
||||
for (const Edge &edge : edges) {
|
||||
for (const SubEdge &edge : edges) {
|
||||
if (edge.is_stitch_edge) {
|
||||
const int second_stitch_vert_index = edge_stitch_verts_map[edge.stitch_edge_key];
|
||||
|
||||
@@ -735,7 +743,7 @@ void DiagSplit::post_split()
|
||||
dice.reserve(num_verts, num_triangles);
|
||||
|
||||
for (size_t i = 0; i < subpatches.size(); i++) {
|
||||
Subpatch &sub = subpatches[i];
|
||||
SubPatch &sub = subpatches[i];
|
||||
|
||||
sub.edge_u0.T = max(sub.edge_u0.T, 1);
|
||||
sub.edge_u1.T = max(sub.edge_u1.T, 1);
|
||||
|
||||
@@ -26,17 +26,20 @@ class Patch;
|
||||
class DiagSplit {
|
||||
SubdParams params;
|
||||
|
||||
vector<Subpatch> subpatches;
|
||||
vector<SubPatch> subpatches;
|
||||
/* `deque` is used so that element pointers remain valid when size is changed. */
|
||||
deque<Edge> edges;
|
||||
deque<SubEdge> edges;
|
||||
|
||||
float3 to_world(Patch *patch, const float2 uv);
|
||||
int T(Patch *patch, const float2 Pstart, const float2 Pend, bool recursive_resolve = false);
|
||||
float3 to_world(const Patch *patch, const float2 uv);
|
||||
int T(const Patch *patch,
|
||||
const float2 Pstart,
|
||||
const float2 Pend,
|
||||
bool recursive_resolve = false);
|
||||
|
||||
void limit_edge_factor(int &T, Patch *patch, const float2 Pstart, const float2 Pend);
|
||||
void resolve_edge_factors(Subpatch &sub);
|
||||
void limit_edge_factor(int &T, const Patch *patch, const float2 Pstart, const float2 Pend);
|
||||
void resolve_edge_factors(SubPatch &sub);
|
||||
|
||||
void partition_edge(Patch *patch,
|
||||
void partition_edge(const Patch *patch,
|
||||
float2 *P,
|
||||
int *t0,
|
||||
int *t1,
|
||||
@@ -44,20 +47,22 @@ class DiagSplit {
|
||||
const float2 Pend,
|
||||
const int t);
|
||||
|
||||
void split(Subpatch &sub, const int depth = 0);
|
||||
void split(SubPatch &sub, const int depth = 0);
|
||||
|
||||
int num_alloced_verts = 0;
|
||||
int alloc_verts(const int n); /* Returns start index of new verts. */
|
||||
|
||||
public:
|
||||
Edge *alloc_edge();
|
||||
SubEdge *alloc_edge();
|
||||
|
||||
explicit DiagSplit(const SubdParams ¶ms);
|
||||
|
||||
void split_patches(Patch *patches, const size_t patches_byte_stride);
|
||||
void split_patches(const Patch *patches, const size_t patches_byte_stride);
|
||||
|
||||
void split_quad(const Mesh::SubdFace &face, Patch *patch);
|
||||
void split_ngon(const Mesh::SubdFace &face, Patch *patches, const size_t patches_byte_stride);
|
||||
void split_quad(const Mesh::SubdFace &face, const Patch *patch);
|
||||
void split_ngon(const Mesh::SubdFace &face,
|
||||
const Patch *patches,
|
||||
const size_t patches_byte_stride);
|
||||
|
||||
void post_split();
|
||||
};
|
||||
|
||||
@@ -9,63 +9,120 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Subpatch */
|
||||
class Patch;
|
||||
|
||||
class Subpatch {
|
||||
/* SubEdge */
|
||||
|
||||
struct SubEdge {
|
||||
/* Number of segments the edge will be diced into, see DiagSplit paper. */
|
||||
int T = 0;
|
||||
|
||||
/* top is edge adjacent to start, bottom is adjacent to end. */
|
||||
SubEdge *top = nullptr, *bottom = nullptr;
|
||||
|
||||
int top_offset = -1, bottom_offset = -1;
|
||||
bool top_indices_decrease = false, bottom_indices_decrease = false;
|
||||
|
||||
int start_vert_index = -1;
|
||||
int end_vert_index = -1;
|
||||
|
||||
/* Index of the second vert from this edges corner along the edge towards the next corner. */
|
||||
int second_vert_index = -1;
|
||||
|
||||
/* Vertices on edge are to be stitched. */
|
||||
bool is_stitch_edge = false;
|
||||
|
||||
/* Key to match this edge with others to be stitched with.
|
||||
* The ints in the pair are ordered stitching indices */
|
||||
pair<int, int> stitch_edge_key;
|
||||
|
||||
/* Full T along edge (may be larger than T for edges split from ngon edges) */
|
||||
int stitch_edge_T = 0;
|
||||
int stitch_offset = 0;
|
||||
int stitch_top_offset;
|
||||
int stitch_start_vert_index;
|
||||
int stitch_end_vert_index;
|
||||
|
||||
SubEdge() = default;
|
||||
|
||||
int get_vert_along_edge(const int n) const
|
||||
{
|
||||
assert(n >= 0 && n <= T);
|
||||
|
||||
if (n == 0) {
|
||||
return start_vert_index;
|
||||
}
|
||||
if (n == T) {
|
||||
return end_vert_index;
|
||||
}
|
||||
|
||||
return second_vert_index + n - 1;
|
||||
}
|
||||
};
|
||||
|
||||
/* SubPatch */
|
||||
|
||||
class SubPatch {
|
||||
public:
|
||||
class Patch *patch; /* Patch this is a subpatch of. */
|
||||
const Patch *patch; /* Patch this is a subpatch of. */
|
||||
int inner_grid_vert_offset;
|
||||
|
||||
struct edge_t {
|
||||
struct Edge {
|
||||
int T;
|
||||
int offset; /* Offset along main edge, interpretation depends on the two flags below. */
|
||||
|
||||
bool indices_decrease_along_edge;
|
||||
bool sub_edges_created_in_reverse_order;
|
||||
|
||||
struct Edge *edge;
|
||||
struct SubEdge *edge;
|
||||
|
||||
int get_vert_along_edge(const int n) const;
|
||||
int get_vert_along_edge(const int n_relative) const
|
||||
{
|
||||
assert(n_relative >= 0 && n_relative <= T);
|
||||
|
||||
int n = n_relative;
|
||||
|
||||
if (!indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
|
||||
n = offset + n;
|
||||
}
|
||||
else if (!indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
|
||||
n = edge->T - offset - T + n;
|
||||
}
|
||||
else if (indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
|
||||
n = offset + T - n;
|
||||
}
|
||||
else if (indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
|
||||
n = edge->T - offset - n;
|
||||
}
|
||||
|
||||
return edge->get_vert_along_edge(n);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* eu1
|
||||
* c01 --------- c11
|
||||
* | |
|
||||
* ev0 | | ev1
|
||||
* | |
|
||||
* c00 --------- c10
|
||||
* uv01 --------- uv11
|
||||
* | |
|
||||
* ev0 | | ev1
|
||||
* | |
|
||||
* uv00 --------- uv10
|
||||
* eu0
|
||||
*/
|
||||
|
||||
/* UV within patch, counter-clockwise starting from uv (0, 0) towards (1, 0) etc. */
|
||||
float2 uv00 = zero_float2();
|
||||
float2 uv10 = make_float2(1.0f, 0.0f);
|
||||
float2 uv11 = one_float2();
|
||||
float2 uv01 = make_float2(0.0f, 1.0f);
|
||||
|
||||
union {
|
||||
float2 corners[4]; /* UV within patch, clockwise starting from uv (0, 0) towards (0, 1) etc. */
|
||||
Edge edges[4]; /* Edges of this subpatch, each edge starts at the corner of the same index. */
|
||||
struct {
|
||||
float2 c00, c01, c11, c10;
|
||||
Edge edge_v0, edge_u1, edge_v1, edge_u0;
|
||||
};
|
||||
};
|
||||
|
||||
union {
|
||||
edge_t
|
||||
edges[4]; /* Edges of this subpatch, each edge starts at the corner of the same index. */
|
||||
struct {
|
||||
edge_t edge_v0, edge_u1, edge_v1, edge_u0;
|
||||
};
|
||||
};
|
||||
|
||||
explicit Subpatch(Patch *patch = nullptr)
|
||||
: patch(patch),
|
||||
c00(zero_float2()),
|
||||
c01(make_float2(0.0f, 1.0f)),
|
||||
c11(one_float2()),
|
||||
c10(make_float2(1.0f, 0.0f))
|
||||
{
|
||||
}
|
||||
|
||||
Subpatch(Patch *patch, const float2 c00, const float2 c01, const float2 c11, const float2 c10)
|
||||
: patch(patch), c00(c00), c01(c01), c11(c11), c10(c10)
|
||||
{
|
||||
}
|
||||
explicit SubPatch(const Patch *patch = nullptr) : patch(patch) {}
|
||||
|
||||
int calc_num_inner_verts() const
|
||||
{
|
||||
@@ -90,8 +147,6 @@ class Subpatch {
|
||||
return inner_triangles + edge_triangles;
|
||||
}
|
||||
|
||||
int get_vert_along_edge(const int e, const int n) const;
|
||||
|
||||
int get_vert_along_grid_edge(const int edge, const int n) const
|
||||
{
|
||||
int Mu = fmax(edge_u0.T, edge_u1.T);
|
||||
@@ -116,87 +171,18 @@ class Subpatch {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_vert_along_edge(const int edge, const int n) const
|
||||
{
|
||||
return edges[edge].get_vert_along_edge(n);
|
||||
}
|
||||
|
||||
float2 map_uv(float2 uv)
|
||||
{
|
||||
/* Map UV from subpatch to patch parametric coordinates. */
|
||||
const float2 d0 = interp(c00, c01, uv.y);
|
||||
const float2 d1 = interp(c10, c11, uv.y);
|
||||
const float2 d0 = interp(uv00, uv01, uv.y);
|
||||
const float2 d1 = interp(uv10, uv11, uv.y);
|
||||
return clamp(interp(d0, d1, uv.x), zero_float2(), one_float2());
|
||||
}
|
||||
};
|
||||
|
||||
struct Edge {
|
||||
/* Number of segments the edge will be diced into, see DiagSplit paper. */
|
||||
int T = 0;
|
||||
|
||||
/* top is edge adjacent to start, bottom is adjacent to end. */
|
||||
Edge *top = nullptr, *bottom = nullptr;
|
||||
|
||||
int top_offset = -1, bottom_offset = -1;
|
||||
bool top_indices_decrease = false, bottom_indices_decrease = false;
|
||||
|
||||
int start_vert_index = -1;
|
||||
int end_vert_index = -1;
|
||||
|
||||
/* Index of the second vert from this edges corner along the edge towards the next corner. */
|
||||
int second_vert_index = -1;
|
||||
|
||||
/* Vertices on edge are to be stitched. */
|
||||
bool is_stitch_edge = false;
|
||||
|
||||
/* Key to match this edge with others to be stitched with.
|
||||
* The ints in the pair are ordered stitching indices */
|
||||
pair<int, int> stitch_edge_key;
|
||||
|
||||
/* Full T along edge (may be larger than T for edges split from ngon edges) */
|
||||
int stitch_edge_T = 0;
|
||||
int stitch_offset = 0;
|
||||
int stitch_top_offset;
|
||||
int stitch_start_vert_index;
|
||||
int stitch_end_vert_index;
|
||||
|
||||
Edge() = default;
|
||||
|
||||
int get_vert_along_edge(const int n) const
|
||||
{
|
||||
assert(n >= 0 && n <= T);
|
||||
|
||||
if (n == 0) {
|
||||
return start_vert_index;
|
||||
}
|
||||
if (n == T) {
|
||||
return end_vert_index;
|
||||
}
|
||||
|
||||
return second_vert_index + n - 1;
|
||||
}
|
||||
};
|
||||
|
||||
inline int Subpatch::edge_t::get_vert_along_edge(const int n_relative) const
|
||||
{
|
||||
assert(n_relative >= 0 && n_relative <= T);
|
||||
|
||||
int n = n_relative;
|
||||
|
||||
if (!indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
|
||||
n = offset + n;
|
||||
}
|
||||
else if (!indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
|
||||
n = edge->T - offset - T + n;
|
||||
}
|
||||
else if (indices_decrease_along_edge && !sub_edges_created_in_reverse_order) {
|
||||
n = offset + T - n;
|
||||
}
|
||||
else if (indices_decrease_along_edge && sub_edges_created_in_reverse_order) {
|
||||
n = edge->T - offset - n;
|
||||
}
|
||||
|
||||
return edge->get_vert_along_edge(n);
|
||||
}
|
||||
|
||||
inline int Subpatch::get_vert_along_edge(const int edge, const int n) const
|
||||
{
|
||||
return edges[edge].get_vert_along_edge(n);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
Reference in New Issue
Block a user