Blender V2.61 - r43446

MOD_ocean.c

Go to the documentation of this file.
00001 
00028 #include "MEM_guardedalloc.h"
00029 
00030 #include "DNA_customdata_types.h"
00031 #include "DNA_object_types.h"
00032 #include "DNA_meshdata_types.h"
00033 #include "DNA_modifier_types.h"
00034 #include "DNA_scene_types.h"
00035 
00036 #include "BKE_cdderivedmesh.h"
00037 #include "BKE_global.h"
00038 #include "BKE_modifier.h"
00039 #include "BKE_ocean.h"
00040 #include "BKE_utildefines.h"
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_math.h"
00044 #include "BLI_math_inline.h"
00045 #include "BLI_utildefines.h"
00046 #include "BLI_string.h"
00047 
00048 #include "MOD_util.h"
00049 
00050 #ifdef WITH_OCEANSIM
00051 static void init_cache_data(Object *ob, struct OceanModifierData *omd)
00052 {
00053     const char *relbase= modifier_path_relbase(ob);
00054 
00055     omd->oceancache = BKE_init_ocean_cache(omd->cachepath, relbase,
00056                                            omd->bakestart, omd->bakeend, omd->wave_scale,
00057                                            omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
00058 }
00059 
00060 static void clear_cache_data(struct OceanModifierData *omd)
00061 {
00062     BKE_free_ocean_cache(omd->oceancache);
00063     omd->oceancache = NULL;
00064     omd->cached = FALSE;
00065 }
00066 
00067 /* keep in sync with init_ocean_modifier_bake(), object_modifier.c */
00068 static void init_ocean_modifier(struct OceanModifierData *omd)
00069 {
00070     int do_heightfield, do_chop, do_normals, do_jacobian;
00071 
00072     if (!omd || !omd->ocean) return;
00073 
00074     do_heightfield = TRUE;
00075     do_chop = (omd->chop_amount > 0);
00076     do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
00077     do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
00078 
00079     BKE_free_ocean_data(omd->ocean);
00080     BKE_init_ocean(omd->ocean, omd->resolution*omd->resolution, omd->resolution*omd->resolution, omd->spatial_size, omd->spatial_size,
00081                    omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
00082                    omd->depth, omd->time,
00083                    do_heightfield, do_chop, do_normals, do_jacobian,
00084                    omd->seed);
00085 }
00086 
00087 static void simulate_ocean_modifier(struct OceanModifierData *omd)
00088 {
00089     if (!omd || !omd->ocean) return;
00090 
00091     BKE_simulate_ocean(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
00092 }
00093 #endif /* WITH_OCEANSIM */
00094 
00095 
00096 
00097 /* Modifier Code */
00098 
00099 static void initData(ModifierData *md)
00100 {
00101 #ifdef WITH_OCEANSIM
00102     OceanModifierData *omd = (OceanModifierData*) md;
00103 
00104     omd->resolution = 7;
00105     omd->spatial_size = 50;
00106 
00107     omd->wave_alignment = 0.0;
00108     omd->wind_velocity = 30.0;
00109 
00110     omd->damp = 0.5;
00111     omd->smallest_wave = 0.01;
00112     omd->wave_direction= 0.0;
00113     omd->depth = 200.0;
00114 
00115     omd->wave_scale = 1.0;
00116 
00117     omd->chop_amount = 1.0;
00118 
00119     omd->foam_coverage = 0.0;
00120 
00121     omd->seed = 0;
00122     omd->time = 1.0;
00123 
00124     omd->refresh = 0;
00125 
00126     omd->size = 1.0;
00127     omd->repeat_x = 1;
00128     omd->repeat_y = 1;
00129 
00130     modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
00131 
00132     omd->cached = 0;
00133     omd->bakestart = 1;
00134     omd->bakeend = 250;
00135     omd->oceancache = NULL;
00136     omd->foam_fade = 0.98;
00137     omd->foamlayername[0] = '\0';   /* layer name empty by default */
00138 
00139     omd->ocean = BKE_add_ocean();
00140     init_ocean_modifier(omd);
00141     simulate_ocean_modifier(omd);
00142 #else  // WITH_OCEANSIM
00143     /* unused */
00144     (void)md;
00145 #endif // WITH_OCEANSIM
00146 }
00147 
00148 static void freeData(ModifierData *md)
00149 {
00150 #ifdef WITH_OCEANSIM
00151     OceanModifierData *omd = (OceanModifierData*) md;
00152 
00153     BKE_free_ocean(omd->ocean);
00154     if (omd->oceancache)
00155         BKE_free_ocean_cache(omd->oceancache);
00156 #else // WITH_OCEANSIM
00157     /* unused */
00158     (void)md;
00159 #endif // WITH_OCEANSIM
00160 }
00161 
00162 static void copyData(ModifierData *md, ModifierData *target)
00163 {
00164 #ifdef WITH_OCEANSIM
00165     OceanModifierData *omd = (OceanModifierData*) md;
00166     OceanModifierData *tomd = (OceanModifierData*) target;
00167 
00168     tomd->resolution = omd->resolution;
00169     tomd->spatial_size = omd->spatial_size;
00170 
00171     tomd->wind_velocity = omd->wind_velocity;
00172 
00173     tomd->damp = omd->damp;
00174     tomd->smallest_wave = omd->smallest_wave;
00175     tomd->depth = omd->depth;
00176 
00177     tomd->wave_alignment = omd->wave_alignment;
00178     tomd->wave_direction = omd->wave_direction;
00179     tomd->wave_scale = omd->wave_scale;
00180 
00181     tomd->chop_amount = omd->chop_amount;
00182     tomd->foam_coverage = omd->foam_coverage;
00183     tomd->time = omd->time;
00184 
00185     tomd->seed = omd->seed;
00186     tomd->flag = omd->flag;
00187 
00188     tomd->refresh = 0;
00189 
00190 
00191     tomd->size = omd->size;
00192     tomd->repeat_x = omd->repeat_x;
00193     tomd->repeat_y = omd->repeat_y;
00194 
00195     /* XXX todo: copy cache runtime too */
00196     tomd->cached = 0;
00197     tomd->bakestart = omd->bakestart;
00198     tomd->bakeend = omd->bakeend;
00199     tomd->oceancache = NULL;
00200 
00201     tomd->ocean = BKE_add_ocean();
00202     init_ocean_modifier(tomd);
00203     simulate_ocean_modifier(tomd);
00204 #else // WITH_OCEANSIM
00205     /* unused */
00206     (void)md;
00207     (void)target;
00208 #endif // WITH_OCEANSIM
00209 }
00210 
00211 #ifdef WITH_OCEANSIM
00212 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
00213 {
00214     OceanModifierData *omd = (OceanModifierData *)md;
00215     CustomDataMask dataMask = 0;
00216 
00217     if (omd->flag & MOD_OCEAN_GENERATE_FOAM)
00218         dataMask |= CD_MASK_MCOL;
00219 
00220     return dataMask;
00221 }
00222 #else // WITH_OCEANSIM
00223 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
00224 {
00225     /* unused */
00226     (void)md;
00227     return 0;
00228 }
00229 #endif // WITH_OCEANSIM
00230 
00231 #if 0
00232 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
00233 {
00234     /* get bounding box of underlying dm */
00235     int v, totvert=dm->getNumVerts(dm);
00236     float min[3], max[3], delta[3];
00237 
00238     MVert *mvert = dm->getVertDataArray(dm,0);
00239 
00240     copy_v3_v3(min, mvert->co);
00241     copy_v3_v3(max, mvert->co);
00242 
00243     for(v=1; v<totvert; v++, mvert++) {
00244         min[0]=MIN2(min[0],mvert->co[0]);
00245         min[1]=MIN2(min[1],mvert->co[1]);
00246         min[2]=MIN2(min[2],mvert->co[2]);
00247 
00248         max[0]=MAX2(max[0],mvert->co[0]);
00249         max[1]=MAX2(max[1],mvert->co[1]);
00250         max[2]=MAX2(max[2],mvert->co[2]);
00251     }
00252 
00253     sub_v3_v3v3(delta, max, min);
00254 
00255     *sx = delta[0];
00256     *sy = delta[1];
00257 
00258     *ox = min[0];
00259     *oy = min[1];
00260 }
00261 #endif
00262 
00263 #ifdef WITH_OCEANSIM
00264 
00265 
00266 #define OMP_MIN_RES 18
00267 static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
00268 {
00269     DerivedMesh *result;
00270 
00271     MVert *mverts;
00272     MFace *mfaces;
00273     int *origindex;
00274 
00275     int cdlayer;
00276 
00277     const int rx = omd->resolution*omd->resolution;
00278     const int ry = omd->resolution*omd->resolution;
00279     const int res_x = rx * omd->repeat_x;
00280     const int res_y = ry * omd->repeat_y;
00281 
00282     const int num_verts = (res_x + 1) * (res_y + 1);
00283     const int num_edges = (res_x * res_y * 2) + res_x + res_y;
00284     const int num_faces = res_x * res_y;
00285 
00286     float sx = omd->size * omd->spatial_size;
00287     float sy = omd->size * omd->spatial_size;
00288     const float ox = -sx / 2.0f;
00289     const float oy = -sy / 2.0f;
00290 
00291     float ix, iy;
00292 
00293     int x, y;
00294 
00295     sx /= rx;
00296     sy /= ry;
00297 
00298     result = CDDM_new(num_verts, num_edges, num_faces);
00299 
00300     mverts = CDDM_get_verts(result);
00301     mfaces = CDDM_get_faces(result);
00302     origindex= result->getFaceDataArray(result, CD_ORIGINDEX);
00303 
00304     /* create vertices */
00305     #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
00306     for (y=0; y < res_y+1; y++) {
00307         for (x=0; x < res_x+1; x++) {
00308             const int i = y*(res_x+1) + x;
00309             float *co= mverts[i].co;
00310             co[0] = ox + (x * sx);
00311             co[1] = oy + (y * sy);
00312             co[2] = 0;
00313         }
00314     }
00315 
00316     /* create faces */
00317     #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
00318     for (y=0; y < res_y; y++) {
00319         for (x=0; x < res_x; x++) {
00320             const int fi = y*res_x + x;
00321             const int vi = y*(res_x+1) + x;
00322             MFace *mf= &mfaces[fi];
00323             mf->v1 = vi;
00324             mf->v2 = vi + 1;
00325             mf->v3 = vi + 1 + res_x+1;
00326             mf->v4 = vi + res_x+1;
00327 
00328             mf->flag |= ME_SMOOTH;
00329 
00330             /* generated geometry does not map to original faces */
00331             origindex[fi] = ORIGINDEX_NONE;
00332         }
00333     }
00334 
00335     CDDM_calc_edges(result);
00336 
00337     /* add uvs */
00338     cdlayer= CustomData_number_of_layers(&result->faceData, CD_MTFACE);
00339     if(cdlayer < MAX_MTFACE) {
00340         MTFace *tfaces= CustomData_add_layer(&result->faceData, CD_MTFACE, CD_CALLOC, NULL, num_faces);
00341 
00342         if (tfaces) { /* unlikely to fail */
00343             ix = 1.0 / rx;
00344             iy = 1.0 / ry;
00345             #pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
00346             for (y=0; y < res_y; y++) {
00347                 for (x=0; x < res_x; x++) {
00348                     const int i = y*res_x + x;
00349                     tfaces[i].uv[0][0] = x * ix;
00350                     tfaces[i].uv[0][1] = y * iy;
00351 
00352                     tfaces[i].uv[1][0] = (x+1) * ix;
00353                     tfaces[i].uv[1][1] = y * iy;
00354 
00355                     tfaces[i].uv[2][0] = (x+1) * ix;
00356                     tfaces[i].uv[2][1] = (y+1) * iy;
00357 
00358                     tfaces[i].uv[3][0] = x * ix;
00359                     tfaces[i].uv[3][1] = (y+1) * iy;
00360                 }
00361             }
00362         }
00363     }
00364 
00365     return result;
00366 }
00367 
00368 static DerivedMesh *doOcean(ModifierData *md, Object *ob,
00369                             DerivedMesh *derivedData,
00370                             int UNUSED(useRenderParams))
00371 {
00372     OceanModifierData *omd = (OceanModifierData*) md;
00373 
00374     DerivedMesh *dm=NULL;
00375     OceanResult ocr;
00376 
00377     MVert *mverts, *mv;
00378 
00379     int i, j;
00380 
00381     int num_verts;
00382     int num_faces;
00383 
00384     int cfra;
00385 
00386     /* use cached & inverted value for speed
00387      * expanded this would read...
00388      *
00389      * (axis / (omd->size * omd->spatial_size)) + 0.5f) */
00390 #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f)
00391 
00392     const float size_co_inv= 1.0f / (omd->size * omd->spatial_size);
00393 
00394     /* update modifier */
00395     if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
00396         omd->ocean = BKE_add_ocean();
00397     if (omd->refresh & MOD_OCEAN_REFRESH_RESET)
00398         init_ocean_modifier(omd);
00399     if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE)
00400         clear_cache_data(omd);
00401 
00402     omd->refresh = 0;
00403 
00404     /* do ocean simulation */
00405     if (omd->cached == TRUE) {
00406         if (!omd->oceancache) init_cache_data(ob, omd);
00407         BKE_simulate_ocean_cache(omd->oceancache, md->scene->r.cfra);
00408     }
00409     else {
00410         simulate_ocean_modifier(omd);
00411     }
00412 
00413     if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE)
00414         dm = generate_ocean_geometry(omd);
00415     else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
00416         dm = CDDM_copy(derivedData);
00417     }
00418 
00419     cfra = md->scene->r.cfra;
00420     CLAMP(cfra, omd->bakestart, omd->bakeend);
00421     cfra -= omd->bakestart; // shift to 0 based
00422 
00423     num_verts = dm->getNumVerts(dm);
00424     num_faces = dm->getNumFaces(dm);
00425 
00426     mverts = dm->getVertArray(dm);
00427 
00428     /* add vcols before displacement - allows lookup based on position */
00429 
00430     if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
00431         int cdlayer= CustomData_number_of_layers(&dm->faceData, CD_MCOL);
00432 
00433         if(cdlayer < MAX_MCOL) {
00434             MCol *mcols= CustomData_add_layer_named(&dm->faceData, CD_MCOL, CD_CALLOC, NULL, num_faces, omd->foamlayername);
00435 
00436             if (mcols) { /* unlikely to fail */
00437                 MCol *mc;
00438                 MFace *mfaces= dm->getFaceArray(dm);
00439                 MFace *mf;
00440 
00441                 float foam;
00442 
00443                 for (i = 0, mf= mfaces; i < num_faces; i++, mf++) {
00444                     j= mf->v4 ? 3 : 2;
00445                     do {
00446                         const float *co= mverts[*(&mf->v1 + j)].co;
00447                         const float u = OCEAN_CO(size_co_inv, co[0]);
00448                         const float v = OCEAN_CO(size_co_inv, co[1]);
00449 
00450                         if (omd->oceancache && omd->cached==TRUE) {
00451                             BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
00452                             foam = ocr.foam;
00453                             CLAMP(foam, 0.0f, 1.0f);
00454                         }
00455                         else {
00456                             BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
00457                             foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
00458                         }
00459 
00460                         mc= &mcols[i*4 + j];
00461                         mc->r = mc->g = mc->b = (char)(foam * 255);
00462                         /* mc->a = 255; */ /* no need to set */
00463                     } while (j--);
00464                 }
00465             }
00466         }
00467     }
00468 
00469 
00470     /* displace the geometry */
00471 
00472     //#pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES)
00473     for (i=0, mv= mverts; i< num_verts; i++, mv++) {
00474         const float u = OCEAN_CO(size_co_inv, mv->co[0]);
00475         const float v = OCEAN_CO(size_co_inv, mv->co[1]);
00476 
00477         if (omd->oceancache && omd->cached==TRUE)
00478             BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
00479         else
00480             BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
00481 
00482         mv->co[2] += ocr.disp[1];
00483 
00484         if (omd->chop_amount > 0.0f) {
00485             mv->co[0] += ocr.disp[0];
00486             mv->co[1] += ocr.disp[2];
00487         }
00488     }
00489 
00490     #undef OCEAN_CO
00491 
00492     return dm;
00493 }
00494 #else  // WITH_OCEANSIM
00495 static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
00496                               DerivedMesh *derivedData,
00497                               int UNUSED(useRenderParams))
00498 {
00499     /* unused */
00500     (void)md;
00501     return derivedData;
00502 }
00503 #endif // WITH_OCEANSIM
00504 
00505 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
00506                                   DerivedMesh *derivedData,
00507                                   int UNUSED(useRenderParams),
00508                                   int UNUSED(isFinalCalc))
00509 {
00510     DerivedMesh *result;
00511 
00512     result = doOcean(md, ob, derivedData, 0);
00513 
00514     if(result != derivedData)
00515         CDDM_calc_normals(result);
00516 
00517     return result;
00518 }
00519 
00520 static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
00521                                     struct EditMesh *UNUSED(editData),
00522                                     DerivedMesh *derivedData)
00523 {
00524     return applyModifier(md, ob, derivedData, 0, 1);
00525 }
00526 
00527 
00528 
00529 ModifierTypeInfo modifierType_Ocean = {
00530     /* name */              "Ocean",
00531     /* structName */        "OceanModifierData",
00532     /* structSize */        sizeof(OceanModifierData),
00533     /* type */              eModifierTypeType_Constructive,
00534     /* flags */             eModifierTypeFlag_AcceptsMesh
00535                             | eModifierTypeFlag_SupportsEditmode
00536                             | eModifierTypeFlag_EnableInEditmode,
00537 
00538     /* copyData */          copyData,
00539     /* deformMatrices */    NULL,
00540     /* deformVerts */       NULL,
00541     /* deformVertsEM */     NULL,
00542     /* deformMatricesEM */  NULL,
00543     /* applyModifier */     applyModifier,
00544     /* applyModifierEM */   applyModifierEM,
00545     /* initData */          initData,
00546     /* requiredDataMask */  requiredDataMask,
00547     /* freeData */          freeData,
00548     /* isDisabled */        NULL,
00549     /* updateDepgraph */    NULL,
00550     /* dependsOnTime */     NULL,
00551     /* dependsOnNormals */  NULL,
00552     /* foreachObjectLink */ NULL,
00553     /* foreachIDLink */     NULL,
00554 };