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:
Brecht Van Lommel
2025-03-09 04:10:17 +01:00
parent 42846caca1
commit e84b377eae
10 changed files with 240 additions and 278 deletions

View File

@@ -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++;
}
}

View File

@@ -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 &params_) : 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);

View File

@@ -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 &params);
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

View File

@@ -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));
}
}

View File

@@ -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

View File

@@ -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_;

View File

@@ -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();
};

View File

@@ -27,7 +27,7 @@ enum {
DiagSplit::DiagSplit(const SubdParams &params_) : 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);

View File

@@ -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 &params);
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();
};

View File

@@ -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