Blender V2.61 - r43446

subd_dice.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "camera.h"
00020 #include "mesh.h"
00021 
00022 #include "subd_dice.h"
00023 #include "subd_patch.h"
00024 
00025 #include "util_debug.h"
00026 
00027 CCL_NAMESPACE_BEGIN
00028 
00029 /* EdgeDice Base */
00030 
00031 EdgeDice::EdgeDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_)
00032 {
00033     mesh = mesh_;
00034     mesh_P = NULL;
00035     mesh_N = NULL;
00036     vert_offset = 0;
00037     dicing_rate = dicing_rate_;
00038     shader = shader_;
00039     smooth = smooth_;
00040     camera = NULL;
00041 
00042     mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
00043 }
00044 
00045 void EdgeDice::reserve(int num_verts, int num_tris)
00046 {
00047     vert_offset = mesh->verts.size();
00048     tri_offset = mesh->triangles.size();
00049 
00050     mesh->reserve(vert_offset + num_verts, tri_offset + num_tris);
00051 
00052     Attribute *attr_vN = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
00053 
00054     mesh_P = &mesh->verts[0];
00055     mesh_N = attr_vN->data_float3();
00056 }
00057 
00058 int EdgeDice::add_vert(Patch *patch, float2 uv)
00059 {
00060     float3 P, N, dPdu, dPdv;
00061 
00062     patch->eval(&P, &dPdu, &dPdv, uv.x, uv.y);
00063     N = normalize(cross(dPdu, dPdv));
00064 
00065     assert(vert_offset < mesh->verts.size());
00066 
00067     mesh_P[vert_offset] = P;
00068     mesh_N[vert_offset] = N;
00069 
00070     return vert_offset++;
00071 }
00072 
00073 void EdgeDice::add_triangle(int v0, int v1, int v2)
00074 {
00075     mesh->add_triangle(v0, v1, v2, shader, smooth);
00076 }
00077 
00078 void EdgeDice::stitch_triangles(vector<int>& outer, vector<int>& inner)
00079 {
00080     if(inner.size() == 0 || outer.size() == 0)
00081         return; // XXX avoid crashes for Mu or Mv == 1, missing polygons
00082 
00083     /* stitch together two arrays of verts with triangles. at each step,
00084        we compare using the next verts on both sides, to find the split
00085        direction with the smallest diagonal, and use that in order to keep
00086        the triangle shape reasonable. */
00087     for(size_t i = 0, j = 0; i+1 < inner.size() || j+1 < outer.size();) {
00088         int v0, v1, v2;
00089 
00090         v0 = inner[i];
00091         v1 = outer[j];
00092 
00093         if(j+1 == outer.size()) {
00094             v2 = inner[++i];
00095         }
00096         else if(i+1 == inner.size()) {
00097             v2 = outer[++j];
00098         }
00099         else {
00100             /* length of diagonals */
00101             float len1 = len(mesh_P[inner[i]] - mesh_P[outer[j+1]]);
00102             float len2 = len(mesh_P[outer[j]] - mesh_P[inner[i+1]]);
00103 
00104             /* use smallest diagonal */
00105             if(len1 < len2)
00106                 v2 = outer[++j];
00107             else
00108                 v2 = inner[++i];
00109         }
00110 
00111         add_triangle(v0, v1, v2);
00112     }
00113 }
00114 
00115 /* QuadDice */
00116 
00117 QuadDice::QuadDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_)
00118 : EdgeDice(mesh_, shader_, smooth_, dicing_rate_)
00119 {
00120 }
00121 
00122 void QuadDice::reserve(EdgeFactors& ef, int Mu, int Mv)
00123 {
00124     /* XXX need to make this also work for edge factor 0 and 1 */
00125     int num_verts = (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1) + (Mu - 1)*(Mv - 1);
00126     EdgeDice::reserve(num_verts, 0);
00127 }
00128 
00129 float2 QuadDice::map_uv(SubPatch& sub, float u, float v)
00130 {
00131     /* map UV from subpatch to patch parametric coordinates */
00132     float2 d0 = interp(sub.P00, sub.P01, v);
00133     float2 d1 = interp(sub.P10, sub.P11, v);
00134     return interp(d0, d1, u);
00135 }
00136 
00137 float3 QuadDice::eval_projected(SubPatch& sub, float u, float v)
00138 {
00139     float2 uv = map_uv(sub, u, v);
00140     float3 P;
00141 
00142     sub.patch->eval(&P, NULL, NULL, uv.x, uv.y);
00143     if(camera)
00144         P = transform(&camera->worldtoraster, P);
00145 
00146     return P;
00147 }
00148 
00149 int QuadDice::add_vert(SubPatch& sub, float u, float v)
00150 {
00151     return EdgeDice::add_vert(sub.patch, map_uv(sub, u, v));
00152 }
00153 
00154 void QuadDice::add_side_u(SubPatch& sub,
00155     vector<int>& outer, vector<int>& inner,
00156     int Mu, int Mv, int tu, int side, int offset)
00157 {
00158     outer.clear();
00159     inner.clear();
00160 
00161     /* set verts on the edge of the patch */
00162     outer.push_back(offset + ((side)? 2: 0));
00163 
00164     for(int i = 1; i < tu; i++) {
00165         float u = i/(float)tu;
00166         float v = (side)? 1.0f: 0.0f;
00167 
00168         outer.push_back(add_vert(sub, u, v));
00169     }
00170 
00171     outer.push_back(offset + ((side)? 3: 1));
00172 
00173     /* set verts on the edge of the inner grid */
00174     for(int i = 0; i < Mu-1; i++) {
00175         int j = (side)? Mv-1-1: 0;
00176         inner.push_back(offset + 4 + i + j*(Mu-1));
00177     }
00178 }
00179 
00180 void QuadDice::add_side_v(SubPatch& sub,
00181     vector<int>& outer, vector<int>& inner,
00182     int Mu, int Mv, int tv, int side, int offset)
00183 {
00184     outer.clear();
00185     inner.clear();
00186 
00187     /* set verts on the edge of the patch */
00188     outer.push_back(offset + ((side)? 1: 0));
00189 
00190     for(int j = 1; j < tv; j++) {
00191         float u = (side)? 1.0f: 0.0f;
00192         float v = j/(float)tv;
00193 
00194         outer.push_back(add_vert(sub, u, v));
00195     }
00196 
00197     outer.push_back(offset + ((side)? 3: 2));
00198 
00199     /* set verts on the edge of the inner grid */
00200     for(int j = 0; j < Mv-1; j++) {
00201         int i = (side)? Mu-1-1: 0;
00202         inner.push_back(offset + 4 + i + j*(Mu-1));
00203     }
00204 }
00205 
00206 float QuadDice::quad_area(const float3& a, const float3& b, const float3& c, const float3& d)
00207 {
00208     return triangle_area(a, b, d) + triangle_area(a, d, c);
00209 }
00210 
00211 float QuadDice::scale_factor(SubPatch& sub, EdgeFactors& ef, int Mu, int Mv)
00212 {
00213     /* estimate area as 4x largest of 4 quads */
00214     float3 P[3][3];
00215 
00216     for(int i = 0; i < 3; i++)
00217         for(int j = 0; j < 3; j++)
00218             P[i][j] = eval_projected(sub, i*0.5f, j*0.5f);
00219 
00220     float A1 = quad_area(P[0][0], P[1][0], P[0][1], P[1][1]);
00221     float A2 = quad_area(P[1][0], P[2][0], P[1][1], P[2][1]);
00222     float A3 = quad_area(P[0][1], P[1][1], P[0][2], P[1][2]);
00223     float A4 = quad_area(P[1][1], P[2][1], P[1][2], P[2][2]);
00224     float Apatch = max(A1, max(A2, max(A3, A4)))*4.0f;
00225 
00226     /* solve for scaling factor */
00227     float Atri = dicing_rate*dicing_rate*0.5f;
00228     float Ntris = Apatch/Atri;
00229 
00230     // XXX does the -sqrt solution matter
00231     // XXX max(D, 0.0) is highly suspicious, need to test cases
00232     // where D goes negative
00233     float N = 0.5f*(Ntris - (ef.tu0 + ef.tu1 + ef.tv0 + ef.tv1));
00234     float D = 4.0f*N*Mu*Mv + (Mu + Mv)*(Mu + Mv);
00235     float S = (Mu + Mv + sqrtf(max(D, 0.0f)))/(2*Mu*Mv);
00236 
00237     return S;
00238 }
00239 
00240 void QuadDice::add_corners(SubPatch& sub)
00241 {
00242     /* add verts for patch corners */
00243     if(sub.patch->is_triangle()) {
00244         add_vert(sub, 0.0f, 0.0f);
00245         add_vert(sub, 1.0f, 0.0f);
00246         add_vert(sub, 0.0f, 1.0f);
00247     }
00248     else {
00249         add_vert(sub, 0.0f, 0.0f);
00250         add_vert(sub, 1.0f, 0.0f);
00251         add_vert(sub, 0.0f, 1.0f);
00252         add_vert(sub, 1.0f, 1.0f);
00253     }
00254 }
00255 
00256 void QuadDice::add_grid(SubPatch& sub, int Mu, int Mv, int offset)
00257 {
00258     /* create inner grid */
00259     float du = 1.0f/(float)Mu;
00260     float dv = 1.0f/(float)Mv;
00261 
00262     for(int j = 1; j < Mv; j++) {
00263         for(int i = 1; i < Mu; i++) {
00264             float u = i*du;
00265             float v = j*dv;
00266 
00267             add_vert(sub, u, v);
00268 
00269             if(i < Mu-1 && j < Mv-1) {
00270                 int i1 = offset + 4 + (i-1) + (j-1)*(Mu-1);
00271                 int i2 = offset + 4 + i + (j-1)*(Mu-1);
00272                 int i3 = offset + 4 + i + j*(Mu-1);
00273                 int i4 = offset + 4 + (i-1) + j*(Mu-1);
00274 
00275                 add_triangle(i1, i2, i3);
00276                 add_triangle(i1, i3, i4);
00277             }
00278         }
00279     }
00280 }
00281 
00282 void QuadDice::dice(SubPatch& sub, EdgeFactors& ef)
00283 {
00284     /* compute inner grid size with scale factor */
00285     int Mu = max(ef.tu0, ef.tu1);
00286     int Mv = max(ef.tv0, ef.tv1);
00287 
00288     float S = scale_factor(sub, ef, Mu, Mv);
00289     Mu = max((int)ceil(S*Mu), 2); // XXX handle 0 & 1?
00290     Mv = max((int)ceil(S*Mv), 2); // XXX handle 0 & 1?
00291 
00292     /* reserve space for new verts */
00293     int offset = mesh->verts.size();
00294     reserve(ef, Mu, Mv);
00295 
00296     /* corners and inner grid */
00297     add_corners(sub);
00298     add_grid(sub, Mu, Mv, offset);
00299 
00300     /* bottom side */
00301     vector<int> outer, inner;
00302 
00303     add_side_u(sub, outer, inner, Mu, Mv, ef.tu0, 0, offset);
00304     stitch_triangles(outer, inner);
00305 
00306     /* top side */
00307     add_side_u(sub, outer, inner, Mu, Mv, ef.tu1, 1, offset);
00308     stitch_triangles(inner, outer);
00309 
00310     /* left side */
00311     add_side_v(sub, outer, inner, Mu, Mv, ef.tv0, 0, offset);
00312     stitch_triangles(inner, outer);
00313 
00314     /* right side */
00315     add_side_v(sub, outer, inner, Mu, Mv, ef.tv1, 1, offset);
00316     stitch_triangles(outer, inner);
00317 
00318     assert(vert_offset == mesh->verts.size());
00319 }
00320 
00321 /* TriangleDice */
00322 
00323 TriangleDice::TriangleDice(Mesh *mesh_, int shader_, bool smooth_, float dicing_rate_)
00324 : EdgeDice(mesh_, shader_, smooth_, dicing_rate_)
00325 {
00326 }
00327 
00328 void TriangleDice::reserve(EdgeFactors& ef, int M)
00329 {
00330     int num_verts = ef.tu + ef.tv + ef.tw;
00331 
00332     for(int m = M-2; m > 0; m -= 2)
00333         num_verts += 3 + (m-1)*3;
00334     
00335     if(!(M & 1))
00336         num_verts++;
00337     
00338     EdgeDice::reserve(num_verts, 0);
00339 }
00340 
00341 float2 TriangleDice::map_uv(SubPatch& sub, float2 uv)
00342 {
00343     /* map UV from subpatch to patch parametric coordinates */
00344     return uv.x*sub.Pu + uv.y*sub.Pv + (1.0f - uv.x - uv.y)*sub.Pw;
00345 }
00346 
00347 int TriangleDice::add_vert(SubPatch& sub, float2 uv)
00348 {
00349     return EdgeDice::add_vert(sub.patch, map_uv(sub, uv));
00350 }
00351 
00352 void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M)
00353 {
00354     // XXX normals are flipped, why?
00355 
00356     /* grid is constructed starting from the outside edges, and adding
00357        progressively smaller inner triangles that connected to the outer
00358        one, until M = 1 or 2, the we fill up the last part. */
00359     vector<int> outer_u, outer_v, outer_w;
00360     int m;
00361 
00362     /* add outer corners vertices */
00363     {
00364         float2 p_u = make_float2(1.0f, 0.0f);
00365         float2 p_v = make_float2(0.0f, 1.0f);
00366         float2 p_w = make_float2(0.0f, 0.0f);
00367 
00368         int corner_u = add_vert(sub, p_u);
00369         int corner_v = add_vert(sub, p_v);
00370         int corner_w = add_vert(sub, p_w);
00371 
00372         outer_u.push_back(corner_v);
00373         outer_v.push_back(corner_w);
00374         outer_w.push_back(corner_u);
00375 
00376         for(int i = 1; i < ef.tu; i++)
00377             outer_u.push_back(add_vert(sub, interp(p_v, p_w, i/(float)ef.tu)));
00378         for(int i = 1; i < ef.tv; i++)
00379             outer_v.push_back(add_vert(sub, interp(p_w, p_u, i/(float)ef.tv)));
00380         for(int i = 1; i < ef.tw; i++)
00381             outer_w.push_back(add_vert(sub, interp(p_u, p_v, i/(float)ef.tw)));
00382 
00383         outer_u.push_back(corner_w);
00384         outer_v.push_back(corner_u);
00385         outer_w.push_back(corner_v);
00386     }
00387 
00388     for(m = M-2; m > 0; m -= 2) {
00389         vector<int> inner_u, inner_v, inner_w;
00390 
00391         float t = m/(float)M;
00392         float2 center = make_float2(1.0f/3.0f, 1.0f/3.0f);
00393 
00394         /* 3 corner vertices */
00395         float2 p_u = interp(center, make_float2(1.0f, 0.0f), t);
00396         float2 p_v = interp(center, make_float2(0.0f, 1.0f), t);
00397         float2 p_w = interp(center, make_float2(0.0f, 0.0f), t);
00398 
00399         int corner_u = add_vert(sub, p_u);
00400         int corner_v = add_vert(sub, p_v);
00401         int corner_w = add_vert(sub, p_w);
00402 
00403         /* construct array of vertex indices for each side */
00404         inner_u.push_back(corner_v);
00405         inner_v.push_back(corner_w);
00406         inner_w.push_back(corner_u);
00407 
00408         for(int i = 1; i < m; i++) {
00409             /* add vertices between corners */
00410             float t = i/(float)m;
00411 
00412             inner_u.push_back(add_vert(sub, interp(p_v, p_w, t)));
00413             inner_v.push_back(add_vert(sub, interp(p_w, p_u, t)));
00414             inner_w.push_back(add_vert(sub, interp(p_u, p_v, t)));
00415         }
00416 
00417         inner_u.push_back(corner_w);
00418         inner_v.push_back(corner_u);
00419         inner_w.push_back(corner_v);
00420 
00421         /* stitch together inner/outer with triangles */
00422         stitch_triangles(outer_u, inner_u);
00423         stitch_triangles(outer_v, inner_v);
00424         stitch_triangles(outer_w, inner_w);
00425 
00426         outer_u = inner_u;
00427         outer_v = inner_v;
00428         outer_w = inner_w;
00429     }
00430 
00431     /* fill up last part */
00432     if(m == -1) {
00433         /* single triangle */
00434         add_triangle(outer_w[0], outer_u[0], outer_v[0]);
00435     }
00436     else {
00437         /* center vertex + 6 triangles */
00438         int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f));
00439 
00440         add_triangle(outer_w[0], outer_w[1], center);
00441         add_triangle(outer_w[1], outer_w[2], center);
00442         add_triangle(outer_u[0], outer_u[1], center);
00443         add_triangle(outer_u[1], outer_u[2], center);
00444         add_triangle(outer_v[0], outer_v[1], center);
00445         add_triangle(outer_v[1], outer_v[2], center);
00446     }
00447 }
00448 
00449 void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef)
00450 {
00451     /* todo: handle 2 1 1 resolution */
00452     int M = max(ef.tu, max(ef.tv, ef.tw));
00453 
00454     reserve(ef, M);
00455     add_grid(sub, ef, M);
00456 
00457     assert(vert_offset == mesh->verts.size());
00458 }
00459 
00460 CCL_NAMESPACE_END
00461