diff options
Diffstat (limited to 'intern/cycles/subd/subd_dice.cpp')
-rw-r--r-- | intern/cycles/subd/subd_dice.cpp | 256 |
1 files changed, 90 insertions, 166 deletions
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index 914b408911e..714ff6ed629 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -38,107 +38,91 @@ EdgeDice::EdgeDice(const SubdParams ¶ms_) : params(params_) } } -void EdgeDice::reserve(int num_verts) +void EdgeDice::reserve(int num_verts, int num_triangles) { Mesh *mesh = params.mesh; vert_offset = mesh->verts.size(); tri_offset = mesh->num_triangles(); - /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ - if (vert_offset + num_verts > mesh->verts.capacity()) { - mesh->reserve_mesh(size_t((vert_offset + num_verts) * 1.2), mesh->num_triangles()); - } - - mesh->resize_mesh(vert_offset + num_verts, tri_offset); + mesh->resize_mesh(mesh->verts.size() + num_verts, mesh->num_triangles()); + mesh->reserve_mesh(mesh->verts.size() + num_verts, mesh->num_triangles() + num_triangles); Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); - mesh_P = mesh->verts.data(); - mesh_N = attr_vN->data_float3(); + mesh_P = mesh->verts.data() + vert_offset; + mesh_N = attr_vN->data_float3() + vert_offset; + + params.mesh->num_subd_verts += num_verts; } -int EdgeDice::add_vert(Patch *patch, float2 uv) +void EdgeDice::set_vert(Patch *patch, int index, float2 uv) { float3 P, N; patch->eval(&P, NULL, NULL, &N, uv.x, uv.y); - assert(vert_offset < params.mesh->verts.size()); - - mesh_P[vert_offset] = P; - mesh_N[vert_offset] = N; - params.mesh->vert_patch_uv[vert_offset] = make_float2(uv.x, uv.y); - - if (params.ptex) { - Attribute *attr_ptex_uv = params.mesh->attributes.add(ATTR_STD_PTEX_UV); - params.mesh->attributes.resize(); + assert(index < params.mesh->verts.size()); - float3 *ptex_uv = attr_ptex_uv->data_float3(); - ptex_uv[vert_offset] = make_float3(uv.x, uv.y, 0.0f); - } - - params.mesh->num_subd_verts++; - - return vert_offset++; + mesh_P[index] = P; + mesh_N[index] = N; + params.mesh->vert_patch_uv[index + vert_offset] = make_float2(uv.x, uv.y); } void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2) { Mesh *mesh = params.mesh; - /* todo: optimize so we can reserve in advance, this is like push_back_slow() */ - if (mesh->triangles.size() == mesh->triangles.capacity()) - mesh->reserve_mesh(mesh->verts.size(), size_t(max(mesh->num_triangles() + 1, 1) * 1.2)); - - mesh->add_triangle(v0, v1, v2, patch->shader, true); + mesh->add_triangle(v0 + vert_offset, v1 + vert_offset, v2 + vert_offset, patch->shader, true); params.mesh->triangle_patch[params.mesh->num_triangles() - 1] = patch->patch_index; - if (params.ptex) { - Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID); - params.mesh->attributes.resize(); - - float *ptex_face_id = attr_ptex_face_id->data_float(); - ptex_face_id[tri_offset] = (float)patch->ptex_face_id(); - } - tri_offset++; } -void EdgeDice::stitch_triangles(Patch *patch, vector<int> &outer, vector<int> &inner) +void EdgeDice::stitch_triangles(Subpatch &sub, int edge) { - if (inner.size() == 0 || outer.size() == 0) + int Mu = max(sub.edge_u0.T, sub.edge_u1.T); + int Mv = max(sub.edge_v0.T, sub.edge_v1.T); + Mu = max(Mu, 2); + Mv = max(Mv, 2); + + int outer_T = sub.edges[edge].T; + int inner_T = ((edge % 2) == 0) ? Mv - 2 : Mu - 2; + + if (inner_T < 0 || outer_T < 0) return; // XXX avoid crashes for Mu or Mv == 1, missing polygons /* stitch together two arrays of verts with triangles. at each step, * we compare using the next verts on both sides, to find the split * direction with the smallest diagonal, and use that in order to keep * the triangle shape reasonable. */ - for (size_t i = 0, j = 0; i + 1 < inner.size() || j + 1 < outer.size();) { + for (size_t i = 0, j = 0; i < inner_T || j < outer_T;) { int v0, v1, v2; - v0 = inner[i]; - v1 = outer[j]; + v0 = sub.get_vert_along_grid_edge(edge, i); + v1 = sub.get_vert_along_edge(edge, j); - if (j + 1 == outer.size()) { - v2 = inner[++i]; + if (j == outer_T) { + v2 = sub.get_vert_along_grid_edge(edge, ++i); } - else if (i + 1 == inner.size()) { - v2 = outer[++j]; + else if (i == inner_T) { + v2 = sub.get_vert_along_edge(edge, ++j); } else { /* length of diagonals */ - float len1 = len_squared(mesh_P[inner[i]] - mesh_P[outer[j + 1]]); - float len2 = len_squared(mesh_P[outer[j]] - mesh_P[inner[i + 1]]); + float len1 = len_squared(mesh_P[sub.get_vert_along_grid_edge(edge, i)] - + mesh_P[sub.get_vert_along_edge(edge, j + 1)]); + float len2 = len_squared(mesh_P[sub.get_vert_along_edge(edge, j)] - + mesh_P[sub.get_vert_along_grid_edge(edge, i + 1)]); /* use smallest diagonal */ if (len1 < len2) - v2 = outer[++j]; + v2 = sub.get_vert_along_edge(edge, ++j); else - v2 = inner[++i]; + v2 = sub.get_vert_along_grid_edge(edge, ++i); } - add_triangle(patch, v0, v1, v2); + add_triangle(sub.patch, v1, v0, v2); } } @@ -148,22 +132,15 @@ QuadDice::QuadDice(const SubdParams ¶ms_) : EdgeDice(params_) { } -void QuadDice::reserve(EdgeFactors &ef, int Mu, int Mv) -{ - /* XXX need to make this also work for edge factor 0 and 1 */ - int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1) * (Mv - 1); - EdgeDice::reserve(num_verts); -} - -float2 QuadDice::map_uv(SubPatch &sub, float u, float v) +float2 QuadDice::map_uv(Subpatch &sub, float u, float v) { /* map UV from subpatch to patch parametric coordinates */ - float2 d0 = interp(sub.P00, sub.P01, v); - float2 d1 = interp(sub.P10, sub.P11, v); + float2 d0 = interp(sub.c00, sub.c01, v); + float2 d1 = interp(sub.c10, sub.c11, v); return interp(d0, d1, u); } -float3 QuadDice::eval_projected(SubPatch &sub, float u, float v) +float3 QuadDice::eval_projected(Subpatch &sub, float u, float v) { float2 uv = map_uv(sub, u, v); float3 P; @@ -175,70 +152,40 @@ float3 QuadDice::eval_projected(SubPatch &sub, float u, float v) return P; } -int QuadDice::add_vert(SubPatch &sub, float u, float v) +void QuadDice::set_vert(Subpatch &sub, int index, float u, float v) { - return EdgeDice::add_vert(sub.patch, map_uv(sub, u, v)); + EdgeDice::set_vert(sub.patch, index, map_uv(sub, u, v)); } -void QuadDice::add_side_u(SubPatch &sub, - vector<int> &outer, - vector<int> &inner, - int Mu, - int Mv, - int tu, - int side, - int offset) +void QuadDice::set_side(Subpatch &sub, int edge) { - outer.clear(); - inner.clear(); + int t = sub.edges[edge].T; /* set verts on the edge of the patch */ - outer.push_back(offset + ((side) ? 2 : 0)); - - for (int i = 1; i < tu; i++) { - float u = i / (float)tu; - float v = (side) ? 1.0f : 0.0f; - - outer.push_back(add_vert(sub, u, v)); - } - - outer.push_back(offset + ((side) ? 3 : 1)); - - /* set verts on the edge of the inner grid */ - for (int i = 0; i < Mu - 1; i++) { - int j = (side) ? Mv - 1 - 1 : 0; - inner.push_back(offset + 4 + i + j * (Mu - 1)); - } -} - -void QuadDice::add_side_v(SubPatch &sub, - vector<int> &outer, - vector<int> &inner, - int Mu, - int Mv, - int tv, - int side, - int offset) -{ - outer.clear(); - inner.clear(); - - /* set verts on the edge of the patch */ - outer.push_back(offset + ((side) ? 1 : 0)); - - for (int j = 1; j < tv; j++) { - float u = (side) ? 1.0f : 0.0f; - float v = j / (float)tv; - - outer.push_back(add_vert(sub, u, v)); - } - - outer.push_back(offset + ((side) ? 3 : 2)); + for (int i = 0; i < t; i++) { + float f = i / (float)t; + + float u, v; + switch (edge) { + case 0: + u = 0; + v = f; + break; + case 1: + u = f; + v = 1; + break; + case 2: + u = 1; + v = 1.0f - f; + break; + case 3: + u = 1.0f - f; + v = 0; + break; + } - /* set verts on the edge of the inner grid */ - for (int j = 0; j < Mv - 1; j++) { - int i = (side) ? Mu - 1 - 1 : 0; - inner.push_back(offset + 4 + i + j * (Mu - 1)); + set_vert(sub, sub.get_vert_along_edge(edge, i), u, v); } } @@ -247,7 +194,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, EdgeFactors &ef, int Mu, int Mv) +float QuadDice::scale_factor(Subpatch &sub, int Mu, int Mv) { /* estimate area as 4x largest of 4 quads */ float3 P[3][3]; @@ -269,23 +216,14 @@ float QuadDice::scale_factor(SubPatch &sub, EdgeFactors &ef, int Mu, int Mv) // XXX does the -sqrt solution matter // XXX max(D, 0.0) is highly suspicious, need to test cases // where D goes negative - float N = 0.5f * (Ntris - (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1)); + float N = 0.5f * (Ntris - (sub.edge_u0.T + sub.edge_u1.T + sub.edge_v0.T + sub.edge_v1.T)); float D = 4.0f * N * Mu * Mv + (Mu + Mv) * (Mu + Mv); float S = (Mu + Mv + sqrtf(max(D, 0.0f))) / (2 * Mu * Mv); return S; } -void QuadDice::add_corners(SubPatch &sub) -{ - /* add verts for patch corners */ - add_vert(sub, 0.0f, 0.0f); - add_vert(sub, 1.0f, 0.0f); - add_vert(sub, 0.0f, 1.0f); - add_vert(sub, 1.0f, 1.0f); -} - -void QuadDice::add_grid(SubPatch &sub, int Mu, int Mv, int offset) +void QuadDice::add_grid(Subpatch &sub, int Mu, int Mv, int offset) { /* create inner grid */ float du = 1.0f / (float)Mu; @@ -296,13 +234,13 @@ void QuadDice::add_grid(SubPatch &sub, int Mu, int Mv, int offset) float u = i * du; float v = j * dv; - add_vert(sub, u, v); + set_vert(sub, offset + (i - 1) + (j - 1) * (Mu - 1), u, v); if (i < Mu - 1 && j < Mv - 1) { - int i1 = offset + 4 + (i - 1) + (j - 1) * (Mu - 1); - int i2 = offset + 4 + i + (j - 1) * (Mu - 1); - int i3 = offset + 4 + i + j * (Mu - 1); - int i4 = offset + 4 + (i - 1) + j * (Mu - 1); + int i1 = offset + (i - 1) + (j - 1) * (Mu - 1); + int i2 = offset + i + (j - 1) * (Mu - 1); + int i3 = offset + i + j * (Mu - 1); + int i4 = offset + (i - 1) + j * (Mu - 1); add_triangle(sub.patch, i1, i2, i3); add_triangle(sub.patch, i1, i3, i4); @@ -311,11 +249,11 @@ void QuadDice::add_grid(SubPatch &sub, int Mu, int Mv, int offset) } } -void QuadDice::dice(SubPatch &sub, EdgeFactors &ef) +void QuadDice::dice(Subpatch &sub) { /* compute inner grid size with scale factor */ - int Mu = max(ef.tu0, ef.tu1); - int Mv = max(ef.tv0, ef.tv1); + int Mu = max(sub.edge_u0.T, sub.edge_u1.T); + int Mv = max(sub.edge_v0.T, sub.edge_v1.T); #if 0 /* Doesn't work very well, especially at grazing angles. */ float S = scale_factor(sub, ef, Mu, Mv); @@ -326,33 +264,19 @@ void QuadDice::dice(SubPatch &sub, EdgeFactors &ef) Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1? Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1? - /* reserve space for new verts */ - int offset = params.mesh->verts.size(); - reserve(ef, Mu, Mv); - - /* corners and inner grid */ - add_corners(sub); - add_grid(sub, Mu, Mv, offset); - - /* bottom side */ - vector<int> outer, inner; - - add_side_u(sub, outer, inner, Mu, Mv, ef.tu0, 0, offset); - stitch_triangles(sub.patch, outer, inner); - - /* top side */ - add_side_u(sub, outer, inner, Mu, Mv, ef.tu1, 1, offset); - stitch_triangles(sub.patch, inner, outer); - - /* left side */ - add_side_v(sub, outer, inner, Mu, Mv, ef.tv0, 0, offset); - stitch_triangles(sub.patch, inner, outer); + /* inner grid */ + add_grid(sub, Mu, Mv, sub.inner_grid_vert_offset); - /* right side */ - add_side_v(sub, outer, inner, Mu, Mv, ef.tv1, 1, offset); - stitch_triangles(sub.patch, outer, inner); + /* sides */ + set_side(sub, 0); + set_side(sub, 1); + set_side(sub, 2); + set_side(sub, 3); - assert(vert_offset == params.mesh->verts.size()); + stitch_triangles(sub, 0); + stitch_triangles(sub, 1); + stitch_triangles(sub, 2); + stitch_triangles(sub, 3); } CCL_NAMESPACE_END |