2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) Blender Foundation
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Matt Ebb
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/modifiers/intern/MOD_ocean.c
32 #include "DNA_customdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_modifier_types.h"
36 #include "DNA_scene_types.h"
39 #include "BLI_math_inline.h"
41 #include "BLI_utildefines.h"
43 #include "BKE_cdderivedmesh.h"
44 #include "BKE_modifier.h"
45 #include "BKE_ocean.h"
48 static void init_cache_data(Object *ob, struct OceanModifierData *omd)
50 const char *relbase = modifier_path_relbase(ob);
52 omd->oceancache = BKE_ocean_init_cache(omd->cachepath, relbase,
53 omd->bakestart, omd->bakeend, omd->wave_scale,
54 omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution);
57 static void clear_cache_data(struct OceanModifierData *omd)
59 BKE_ocean_free_cache(omd->oceancache);
60 omd->oceancache = NULL;
64 /* keep in sync with init_ocean_modifier_bake(), object_modifier.c */
65 static void init_ocean_modifier(struct OceanModifierData *omd)
67 int do_heightfield, do_chop, do_normals, do_jacobian;
69 if (!omd || !omd->ocean) return;
71 do_heightfield = true;
72 do_chop = (omd->chop_amount > 0);
73 do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
74 do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
76 BKE_ocean_free_data(omd->ocean);
77 BKE_ocean_init(omd->ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
78 omd->spatial_size, omd->spatial_size,
79 omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
80 omd->depth, omd->time,
81 do_heightfield, do_chop, do_normals, do_jacobian,
85 static void simulate_ocean_modifier(struct OceanModifierData *omd)
87 if (!omd || !omd->ocean) return;
89 BKE_ocean_simulate(omd->ocean, omd->time, omd->wave_scale, omd->chop_amount);
91 #endif /* WITH_OCEANSIM */
97 static void initData(ModifierData *md)
100 OceanModifierData *omd = (OceanModifierData *) md;
103 omd->spatial_size = 50;
105 omd->wave_alignment = 0.0;
106 omd->wind_velocity = 30.0;
109 omd->smallest_wave = 0.01;
110 omd->wave_direction = 0.0;
113 omd->wave_scale = 1.0;
115 omd->chop_amount = 1.0;
117 omd->foam_coverage = 0.0;
128 modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
133 omd->oceancache = NULL;
134 omd->foam_fade = 0.98;
135 omd->foamlayername[0] = '\0'; /* layer name empty by default */
137 omd->ocean = BKE_ocean_add();
138 init_ocean_modifier(omd);
139 simulate_ocean_modifier(omd);
140 #else /* WITH_OCEANSIM */
143 #endif /* WITH_OCEANSIM */
146 static void freeData(ModifierData *md)
149 OceanModifierData *omd = (OceanModifierData *) md;
151 BKE_ocean_free(omd->ocean);
153 BKE_ocean_free_cache(omd->oceancache);
154 #else /* WITH_OCEANSIM */
157 #endif /* WITH_OCEANSIM */
160 static void copyData(ModifierData *md, ModifierData *target)
163 OceanModifierData *omd = (OceanModifierData *) md;
164 OceanModifierData *tomd = (OceanModifierData *) target;
166 tomd->geometry_mode = omd->geometry_mode;
167 tomd->resolution = omd->resolution;
168 tomd->spatial_size = omd->spatial_size;
170 tomd->wind_velocity = omd->wind_velocity;
172 tomd->damp = omd->damp;
173 tomd->smallest_wave = omd->smallest_wave;
174 tomd->depth = omd->depth;
176 tomd->wave_alignment = omd->wave_alignment;
177 tomd->wave_direction = omd->wave_direction;
178 tomd->wave_scale = omd->wave_scale;
180 tomd->chop_amount = omd->chop_amount;
181 tomd->foam_coverage = omd->foam_coverage;
182 tomd->time = omd->time;
184 tomd->seed = omd->seed;
185 tomd->flag = omd->flag;
189 tomd->size = omd->size;
190 tomd->repeat_x = omd->repeat_x;
191 tomd->repeat_y = omd->repeat_y;
193 /* XXX todo: copy cache runtime too */
195 tomd->bakestart = omd->bakestart;
196 tomd->bakeend = omd->bakeend;
197 tomd->oceancache = NULL;
199 tomd->ocean = BKE_ocean_add();
200 init_ocean_modifier(tomd);
201 simulate_ocean_modifier(tomd);
202 #else /* WITH_OCEANSIM */
206 #endif /* WITH_OCEANSIM */
210 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
212 OceanModifierData *omd = (OceanModifierData *)md;
213 CustomDataMask dataMask = 0;
215 if (omd->flag & MOD_OCEAN_GENERATE_FOAM)
216 dataMask |= CD_MASK_MCOL;
220 #else /* WITH_OCEANSIM */
221 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
227 #endif /* WITH_OCEANSIM */
229 static bool dependsOnNormals(ModifierData *md)
231 OceanModifierData *omd = (OceanModifierData *)md;
232 return (omd->geometry_mode != MOD_OCEAN_GEOM_GENERATE);
236 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
238 /* get bounding box of underlying dm */
239 int v, totvert = dm->getNumVerts(dm);
240 float min[3], max[3], delta[3];
242 MVert *mvert = dm->getVertDataArray(dm, 0);
244 copy_v3_v3(min, mvert->co);
245 copy_v3_v3(max, mvert->co);
247 for (v = 1; v < totvert; v++, mvert++) {
248 min[0] = min_ff(min[0], mvert->co[0]);
249 min[1] = min_ff(min[1], mvert->co[1]);
250 min[2] = min_ff(min[2], mvert->co[2]);
252 max[0] = max_ff(max[0], mvert->co[0]);
253 max[1] = max_ff(max[1], mvert->co[1]);
254 max[2] = max_ff(max[2], mvert->co[2]);
257 sub_v3_v3v3(delta, max, min);
269 typedef struct GenerateOceanGeometryData {
281 } GenerateOceanGeometryData;
283 static void generate_ocean_geometry_vertices(void *userdata, const int y)
285 GenerateOceanGeometryData *gogd = userdata;
288 for (x = 0; x <= gogd->res_x; x++) {
289 const int i = y * (gogd->res_x + 1) + x;
290 float *co = gogd->mverts[i].co;
291 co[0] = gogd->ox + (x * gogd->sx);
292 co[1] = gogd->oy + (y * gogd->sy);
297 static void generate_ocean_geometry_polygons(void *userdata, const int y)
299 GenerateOceanGeometryData *gogd = userdata;
302 for (x = 0; x < gogd->res_x; x++) {
303 const int fi = y * gogd->res_x + x;
304 const int vi = y * (gogd->res_x + 1) + x;
305 MPoly *mp = &gogd->mpolys[fi];
306 MLoop *ml = &gogd->mloops[fi * 4];
312 ml->v = vi + 1 + gogd->res_x + 1;
314 ml->v = vi + gogd->res_x + 1;
317 mp->loopstart = fi * 4;
320 mp->flag |= ME_SMOOTH;
322 /* generated geometry does not map to original faces */
323 gogd->origindex[fi] = ORIGINDEX_NONE;
327 static void generate_ocean_geometry_uvs(void *userdata, const int y)
329 GenerateOceanGeometryData *gogd = userdata;
332 for (x = 0; x < gogd->res_x; x++) {
333 const int i = y * gogd->res_x + x;
334 MLoopUV *luv = &gogd->mloopuvs[i * 4];
336 luv->uv[0] = x * gogd->ix;
337 luv->uv[1] = y * gogd->iy;
340 luv->uv[0] = (x + 1) * gogd->ix;
341 luv->uv[1] = y * gogd->iy;
344 luv->uv[0] = (x + 1) * gogd->ix;
345 luv->uv[1] = (y + 1) * gogd->iy;
348 luv->uv[0] = x * gogd->ix;
349 luv->uv[1] = (y + 1) * gogd->iy;
354 static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
358 GenerateOceanGeometryData gogd;
363 const bool use_threading = omd->resolution > 4;
365 gogd.rx = omd->resolution * omd->resolution;
366 gogd.ry = omd->resolution * omd->resolution;
367 gogd.res_x = gogd.rx * omd->repeat_x;
368 gogd.res_y = gogd.ry * omd->repeat_y;
370 num_verts = (gogd.res_x + 1) * (gogd.res_y + 1);
371 num_polys = gogd.res_x * gogd.res_y;
373 gogd.sx = omd->size * omd->spatial_size;
374 gogd.sy = omd->size * omd->spatial_size;
375 gogd.ox = -gogd.sx / 2.0f;
376 gogd.oy = -gogd.sy / 2.0f;
381 result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);
383 gogd.mverts = CDDM_get_verts(result);
384 gogd.mpolys = CDDM_get_polys(result);
385 gogd.mloops = CDDM_get_loops(result);
387 gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
389 /* create vertices */
390 BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);
393 BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);
395 CDDM_calc_edges(result);
398 if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
399 gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
400 CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);
402 if (gogd.mloopuvs) { /* unlikely to fail */
403 gogd.ix = 1.0 / gogd.rx;
404 gogd.iy = 1.0 / gogd.ry;
406 BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
410 result->dirty |= DM_DIRTY_NORMALS;
415 static DerivedMesh *doOcean(ModifierData *md, Object *ob,
416 DerivedMesh *derivedData,
417 int UNUSED(useRenderParams))
419 OceanModifierData *omd = (OceanModifierData *) md;
421 DerivedMesh *dm = NULL;
429 /* use cached & inverted value for speed
430 * expanded this would read...
432 * (axis / (omd->size * omd->spatial_size)) + 0.5f) */
433 #define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f)
435 const float size_co_inv = 1.0f / (omd->size * omd->spatial_size);
437 /* can happen in when size is small, avoid bad array lookups later and quit now */
438 if (!isfinite(size_co_inv)) {
442 /* update modifier */
443 if (omd->refresh & MOD_OCEAN_REFRESH_ADD) {
444 omd->ocean = BKE_ocean_add();
446 if (omd->refresh & MOD_OCEAN_REFRESH_RESET) {
447 init_ocean_modifier(omd);
449 if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) {
450 clear_cache_data(omd);
454 /* do ocean simulation */
455 if (omd->cached == true) {
456 if (!omd->oceancache) {
457 init_cache_data(ob, omd);
459 BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
462 simulate_ocean_modifier(omd);
465 if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
466 dm = generate_ocean_geometry(omd);
467 DM_ensure_normals(dm);
469 else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
470 dm = CDDM_copy(derivedData);
473 cfra = md->scene->r.cfra;
474 CLAMP(cfra, omd->bakestart, omd->bakeend);
475 cfra -= omd->bakestart; /* shift to 0 based */
477 mverts = dm->getVertArray(dm);
479 /* add vcols before displacement - allows lookup based on position */
481 if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
482 if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) {
483 const int num_polys = dm->getNumPolys(dm);
484 const int num_loops = dm->getNumLoops(dm);
485 MLoop *mloops = dm->getLoopArray(dm);
486 MLoopCol *mloopcols = CustomData_add_layer_named(
487 &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
489 if (mloopcols) { /* unlikely to fail */
490 MPoly *mpolys = dm->getPolyArray(dm);
493 for (i = 0, mp = mpolys; i < num_polys; i++, mp++) {
494 MLoop *ml = &mloops[mp->loopstart];
495 MLoopCol *mlcol = &mloopcols[mp->loopstart];
497 for (j = mp->totloop; j--; ml++, mlcol++) {
498 const float *vco = mverts[ml->v].co;
499 const float u = OCEAN_CO(size_co_inv, vco[0]);
500 const float v = OCEAN_CO(size_co_inv, vco[1]);
503 if (omd->oceancache && omd->cached == true) {
504 BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
506 CLAMP(foam, 0.0f, 1.0f);
509 BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
510 foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
513 mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255);
514 /* This needs to be set (render engine uses) */
523 /* displace the geometry */
525 /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */
527 const int num_verts = dm->getNumVerts(dm);
529 for (i = 0; i < num_verts; i++) {
530 float *vco = mverts[i].co;
531 const float u = OCEAN_CO(size_co_inv, vco[0]);
532 const float v = OCEAN_CO(size_co_inv, vco[1]);
534 if (omd->oceancache && omd->cached == true) {
535 BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
538 BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
541 vco[2] += ocr.disp[1];
543 if (omd->chop_amount > 0.0f) {
544 vco[0] += ocr.disp[0];
545 vco[1] += ocr.disp[2];
554 #else /* WITH_OCEANSIM */
555 static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
556 DerivedMesh *derivedData,
557 int UNUSED(useRenderParams))
563 #endif /* WITH_OCEANSIM */
565 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
566 DerivedMesh *derivedData,
567 ModifierApplyFlag UNUSED(flag))
571 result = doOcean(md, ob, derivedData, 0);
573 if (result != derivedData)
574 result->dirty |= DM_DIRTY_NORMALS;
580 ModifierTypeInfo modifierType_Ocean = {
582 /* structName */ "OceanModifierData",
583 /* structSize */ sizeof(OceanModifierData),
584 /* type */ eModifierTypeType_Constructive,
585 /* flags */ eModifierTypeFlag_AcceptsMesh |
586 eModifierTypeFlag_SupportsEditmode |
587 eModifierTypeFlag_EnableInEditmode,
589 /* copyData */ copyData,
590 /* deformMatrices */ NULL,
591 /* deformVerts */ NULL,
592 /* deformVertsEM */ NULL,
593 /* deformMatricesEM */ NULL,
594 /* applyModifier */ applyModifier,
595 /* applyModifierEM */ NULL,
596 /* initData */ initData,
597 /* requiredDataMask */ requiredDataMask,
598 /* freeData */ freeData,
599 /* isDisabled */ NULL,
600 /* updateDepgraph */ NULL,
601 /* updateDepsgraph */ NULL,
602 /* dependsOnTime */ NULL,
603 /* dependsOnNormals */ dependsOnNormals,
604 /* foreachObjectLink */ NULL,
605 /* foreachIDLink */ NULL,
606 /* foreachTexLink */ NULL,