From e84b377eae8b821f87d7ff234590adc0dcf1e946 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 9 Mar 2025 04:10:17 +0100 Subject: [PATCH] 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 --- intern/cycles/scene/mesh_subdivision.cpp | 42 +---- intern/cycles/subd/dice.cpp | 16 +- intern/cycles/subd/dice.h | 16 +- intern/cycles/subd/osd.cpp | 14 +- intern/cycles/subd/osd.h | 3 +- intern/cycles/subd/patch.cpp | 23 ++- intern/cycles/subd/patch.h | 15 +- intern/cycles/subd/split.cpp | 150 ++++++++-------- intern/cycles/subd/split.h | 29 ++-- intern/cycles/subd/subpatch.h | 210 +++++++++++------------ 10 files changed, 240 insertions(+), 278 deletions(-) diff --git a/intern/cycles/scene/mesh_subdivision.cpp b/intern/cycles/scene/mesh_subdivision.cpp index 0065b290893..f36a561edd8 100644 --- a/intern/cycles/scene/mesh_subdivision.cpp +++ b/intern/cycles/scene/mesh_subdivision.cpp @@ -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++; } } diff --git a/intern/cycles/subd/dice.cpp b/intern/cycles/subd/dice.cpp index 0b21fd2c2d6..e8a76fb6f8e 100644 --- a/intern/cycles/subd/dice.cpp +++ b/intern/cycles/subd/dice.cpp @@ -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); diff --git a/intern/cycles/subd/dice.h b/intern/cycles/subd/dice.h index ed68ad7407c..4ceac649136 100644 --- a/intern/cycles/subd/dice.h +++ b/intern/cycles/subd/dice.h @@ -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 diff --git a/intern/cycles/subd/osd.cpp b/intern/cycles/subd/osd.cpp index aba9ab8e8e0..412e10f0adb 100644 --- a/intern/cycles/subd/osd.cpp +++ b/intern/cycles/subd/osd.cpp @@ -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)); } } diff --git a/intern/cycles/subd/osd.h b/intern/cycles/subd/osd.h index 120b6f6f065..5250f761f36 100644 --- a/intern/cycles/subd/osd.h +++ b/intern/cycles/subd/osd.h @@ -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 diff --git a/intern/cycles/subd/patch.cpp b/intern/cycles/subd/patch.cpp index f22fbdba360..8acbcb4a241 100644 --- a/intern/cycles/subd/patch.cpp +++ b/intern/cycles/subd/patch.cpp @@ -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_; diff --git a/intern/cycles/subd/patch.h b/intern/cycles/subd/patch.h index 2d32a086d14..cc01a59902b 100644 --- a/intern/cycles/subd/patch.h +++ b/intern/cycles/subd/patch.h @@ -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(); }; diff --git a/intern/cycles/subd/split.cpp b/intern/cycles/subd/split.cpp index 9227de34708..4ed75575474 100644 --- a/intern/cycles/subd/split.cpp +++ b/intern/cycles/subd/split.cpp @@ -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, 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); diff --git a/intern/cycles/subd/split.h b/intern/cycles/subd/split.h index 54aacc76227..61e987c76ff 100644 --- a/intern/cycles/subd/split.h +++ b/intern/cycles/subd/split.h @@ -26,17 +26,20 @@ class Patch; class DiagSplit { SubdParams params; - vector subpatches; + vector subpatches; /* `deque` is used so that element pointers remain valid when size is changed. */ - deque edges; + deque 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(); }; diff --git a/intern/cycles/subd/subpatch.h b/intern/cycles/subd/subpatch.h index 74ff73ec167..3a5627094b1 100644 --- a/intern/cycles/subd/subpatch.h +++ b/intern/cycles/subd/subpatch.h @@ -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 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 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