static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job) { Scene *scene= CTX_data_scene(C); int i; FluidsimSettings *domainSettings; char debugStrBuffer[256]; int gridlevels = 0; const char *relbase= modifier_path_relbase(fsDomain); const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; const char *suffixSurface = FLUID_SUFFIX_SURFACE; char targetDir[FILE_MAX]; // store & modify output settings char targetFile[FILE_MAX]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking float domainMat[4][4]; float invDomMat[4][4]; int noFrames; int origFrame = scene->r.cfra; FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; FluidBakeJob *fb; elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); if (getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", strEnvName); elbeemDebugOut(debugStrBuffer); } /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */; noFrames = scene->r.efra - 0; if (noFrames<=0) { BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* check scene for sane object/modifier settings */ if (!fluid_validate_scene(reports, scene, fsDomain)) { fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* these both have to be valid, otherwise we wouldn't be here */ fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; mesh = fsDomain->data; domainSettings->bakeStart = 1; domainSettings->bakeEnd = scene->r.efra; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); // reset last valid frame domainSettings->lastgoodframe = -1; /* delete old baked files */ fluidsim_delete_until_lastframe(domainSettings, relbase); /* rough check of settings... */ if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz, domainSettings->resolutionxyz); elbeemDebugOut(debugStrBuffer); domainSettings->previewresxyz = domainSettings->resolutionxyz; } // set adaptive coarsening according to resolutionxyz // this should do as an approximation, with in/outflow // doing this more accurate would be overkill // perhaps add manual setting? if (domainSettings->maxRefine <0) { if (domainSettings->resolutionxyz>128) { gridlevels = 2; } else if (domainSettings->resolutionxyz > 64) { gridlevels = 1; } else { gridlevels = 0; } } else { gridlevels = domainSettings->maxRefine; } BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name, gridlevels); elbeemDebugOut(debugStrBuffer); /* ******** prepare output file paths ******** */ outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames; /* ******** initialize and allocate animation channels ******** */ fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); /* reset to original current frame */ scene->r.cfra = origFrame; ED_update_for_newframe(CTX_data_main(C), scene, 1); /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if (!invert_m4_m4(invDomMat, domainMat)) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* ******** start writing / exporting ******** */ // use .tmp, don't overwrite/delete original file BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); // make sure these directories exist as well if (outStringsChanged) { BLI_make_existing_file(targetFile); } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); fsset->version = 1; fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : domainSettings->threads; // setup global settings copy_v3_v3(fsset->geoStart, domainSettings->bbStart); copy_v3_v3(fsset->geoSize, domainSettings->bbSize); // simulate with 50^3 fsset->resolutionxyz = (int)domainSettings->resolutionxyz; fsset->previewresxyz = (int)domainSettings->previewresxyz; fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); fsset->viscosity = get_fluid_viscosity(domainSettings); get_fluid_gravity(fsset->gravity, scene, domainSettings); // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset->animStart = domainSettings->animStart; fsset->aniFrameTime = channels->aniFrameTime; fsset->noOfFrames = noFrames; // is otherwise subtracted in parser BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface); // defaults for compressibility and adaptive grids fsset->gstar = domainSettings->gstar; fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels fsset->generateParticles = domainSettings->generateParticles; fsset->numTracerParticles = domainSettings->generateTracers; fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; fsset->farFieldSize = domainSettings->farFieldSize; BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); // domain channels fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = channels->length; fsset->channelFrameTime = channels->DomainTime; fsset->channelViscosity = channels->DomainViscosity; fsset->channelGravity = channels->DomainGravity; fsset->runsimCallback = &runSimulationCallback; fsset->runsimUserData = fb; if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; fsset->domainobsPartslip = domainSettings->partSlipValue; /* use domainobsType also for surface generation flag (bit: >=64) */ if (domainSettings->typeFlags & OB_FSSG_NOOBS) fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; else fsset->mFsSurfGenSetting = 0; // "normal" mode fsset->generateVertexVectors = (domainSettings->domainNovecgen==0); // init blender domain transform matrix { int j; for (i=0; i<4; i++) { for (j=0; j<4; j++) { fsset->surfaceTrafo[i*4+j] = invDomMat[j][i]; } } } /* ******** init solver with settings ******** */ elbeemInit(); elbeemAddDomain(fsset); /* ******** export all fluid objects to elbeem ******** */ export_fluid_objects(fobjects, scene, channels->length); /* custom data for fluid bake job */ fb->settings = fsset; if (do_job) { wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_FLUID); /* setup job */ WM_jobs_customdata_set(wm_job, fb, fluidbake_free); WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } else { short dummy_stop = 0, dummy_do_update = 0; float dummy_progress = 0.0f; /* blocking, use with exec() */ fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); fluidbake_endjob((void *)fb); fluidbake_free((void *)fb); } /* ******** free stored animation data ******** */ fluidbake_free_data(channels, fobjects, NULL, NULL); // elbeemFree(); return 1; }
int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain) { Scene *scene= CTX_data_scene(C); int i; FluidsimSettings *domainSettings; char debugStrBuffer[256]; int gridlevels = 0; const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp const char *suffixConfig = FLUID_SUFFIX_CONFIG; const char *suffixSurface = FLUID_SUFFIX_SURFACE; char targetDir[FILE_MAXDIR+FILE_MAXFILE]; // store & modify output settings char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking float domainMat[4][4]; float invDomMat[4][4]; int noFrames; int origFrame = scene->r.cfra; FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; wmJob *steve; FluidBakeJob *fb; elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS); fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); if(getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); elbeemDebugOut(debugStrBuffer); } /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */; noFrames = scene->r.efra - 0; if(noFrames<=0) { BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings."); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* check scene for sane object/modifier settings */ if (!fluid_validate_scene(reports, scene, fsDomain)) { fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* these both have to be valid, otherwise we wouldnt be here */ fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; mesh = fsDomain->data; domainSettings->bakeStart = 1; domainSettings->bakeEnd = scene->r.efra; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); // reset last valid frame domainSettings->lastgoodframe = -1; /* rough check of settings... */ if(domainSettings->previewresxyz > domainSettings->resolutionxyz) { snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz , domainSettings->resolutionxyz); elbeemDebugOut(debugStrBuffer); domainSettings->previewresxyz = domainSettings->resolutionxyz; } // set adaptive coarsening according to resolutionxyz // this should do as an approximation, with in/outflow // doing this more accurate would be overkill // perhaps add manual setting? if(domainSettings->maxRefine <0) { if(domainSettings->resolutionxyz>128) { gridlevels = 2; } else if(domainSettings->resolutionxyz>64) { gridlevels = 1; } else { gridlevels = 0; } } else { gridlevels = domainSettings->maxRefine; } snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); elbeemDebugOut(debugStrBuffer); /* ******** prepare output file paths ******** */ outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); channels->length = scene->r.efra; channels->aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames; /* ******** initialise and allocate animation channels ******** */ fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); /* reset to original current frame */ scene->r.cfra = origFrame; ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1); /* ---- XXX: No Time animation curve for now, leaving this code here for reference { int timeIcu[1] = { FLUIDSIM_TIME }; float timeDef[1] = { 1. }; // time channel is a bit special, init by hand... timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex"); for(i=0; i<=scene->r.efra; i++) { timeAtIndex[i] = (float)(i-startFrame); } fluidsimInitChannel(scene, &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB // time channel is a multiplicator for if(channelDomainTime) { for(i=0; i<allchannelSize; i++) { channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.; } } timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe"); timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1 if(channelDomainTime) { for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0]; } fsset->} else { for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; } } } // domain channel init */ /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if(!invert_m4_m4(invDomMat, domainMat)) { snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix."); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* ******** start writing / exporting ******** */ // use .tmp, dont overwrite/delete original file BLI_snprintf(targetFile, sizeof(targetFile), "%s%s.tmp", targetDir, suffixConfig); // make sure these directories exist as well if(outStringsChanged) { BLI_make_existing_file(targetFile); } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); fsset->version = 1; // setup global settings copy_v3_v3(fsset->geoStart, domainSettings->bbStart); copy_v3_v3(fsset->geoSize, domainSettings->bbSize); // simulate with 50^3 fsset->resolutionxyz = (int)domainSettings->resolutionxyz; fsset->previewresxyz = (int)domainSettings->previewresxyz; fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); fsset->viscosity = get_fluid_viscosity(domainSettings); get_fluid_gravity(fsset->gravity, scene, domainSettings); // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset->animStart = domainSettings->animStart; fsset->aniFrameTime = channels->aniFrameTime; fsset->noOfFrames = noFrames; // is otherwise subtracted in parser BLI_snprintf(targetFile, sizeof(targetFile), "%s%s", targetDir, suffixSurface); // defaults for compressibility and adaptive grids fsset->gstar = domainSettings->gstar; fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels fsset->generateParticles = domainSettings->generateParticles; fsset->numTracerParticles = domainSettings->generateTracers; fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; fsset->farFieldSize = domainSettings->farFieldSize; BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); // domain channels fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = channels->length; fsset->channelFrameTime = channels->DomainTime; fsset->channelViscosity = channels->DomainViscosity; fsset->channelGravity = channels->DomainGravity; fsset->runsimCallback = &runSimulationCallback; fsset->runsimUserData = fb; if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; fsset->domainobsPartslip = domainSettings->partSlipValue; fsset->generateVertexVectors = (domainSettings->domainNovecgen==0); // init blender domain transform matrix { int j; for(i=0; i<4; i++) { for(j=0; j<4; j++) { fsset->surfaceTrafo[i*4+j] = invDomMat[j][i]; } } } /* ******** init solver with settings ******** */ elbeemInit(); elbeemAddDomain(fsset); /* ******** export all fluid objects to elbeem ******** */ export_fluid_objects(fobjects, scene, channels->length); /* custom data for fluid bake job */ fb->settings = fsset; /* setup job */ WM_jobs_customdata(steve, fb, fluidbake_free); WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob); WM_jobs_start(CTX_wm_manager(C), steve); /* ******** free stored animation data ******** */ fluidbake_free_data(channels, fobjects, NULL, NULL); // elbeemFree(); return 1; }
static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects) { Scene *scene = CTX_data_scene(C); Base *base; int i; int length = channels->length; float eval_time; /* init time values (assuming that time moves at a constant speed; may be overridden later) */ init_time(domainSettings, channels); /* allocate domain animation channels */ channels->DomainGravity = MEM_callocN(length * (CHANNEL_VEC+1) * sizeof(float), "channel DomainGravity"); channels->DomainViscosity = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainViscosity"); channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainTime"); /* allocate fluid objects */ for (base=scene->base.first; base; base= base->next) { Object *ob = base->object; FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); if (fluidmd) { FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object"); fobj->object = ob; if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { BLI_addtail(fobjects, fobj); continue; } fobj->Translation = MEM_callocN(length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Translation"); fobj->Rotation = MEM_callocN(length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Rotation"); fobj->Scale = MEM_callocN(length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Scale"); fobj->Active = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject Active"); fobj->InitialVelocity = MEM_callocN(length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject InitialVelocity"); if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { fobj->AttractforceStrength = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceStrength"); fobj->AttractforceRadius = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceRadius"); fobj->VelocityforceStrength = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceStrength"); fobj->VelocityforceRadius = MEM_callocN(length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceRadius"); } if (fluid_is_animated_mesh(fluidmd->fss)) { float *verts=NULL; int *tris=NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd); initElbeemMesh(scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex); fobj->VertexCache = MEM_callocN(length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache"); MEM_freeN(verts); MEM_freeN(tris); } BLI_addtail(fobjects, fobj); } } /* now we loop over the frames and fill the allocated channels with data */ for (i=0; i < channels->length; i++) { FluidObject *fobj; float viscosity, gravity[3]; float timeAtFrame, time; eval_time = domainSettings->bakeStart + i; /* XXX: This can't be used due to an anim sys optimization that ignores recalc object animation, * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); * This doesn't work with drivers: * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); */ /* Modifying the global scene isn't nice, but we can do it in * this part of the process before a threaded job is created */ scene->r.cfra = (int)eval_time; ED_update_for_newframe(CTX_data_main(C), scene, 1); /* now scene data should be current according to animation system, so we fill the channels */ /* Domain time */ // TODO: have option for not running sim, time mangling, in which case second case comes in handy if (channels->DomainTime) { time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime; timeAtFrame = channels->timeAtFrame[i] + time; channels->timeAtFrame[i+1] = timeAtFrame; set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT); } else { timeAtFrame = channels->timeAtFrame[i+1]; } /* Domain properties - gravity/viscosity */ get_fluid_gravity(gravity, scene, domainSettings); set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC); viscosity = get_fluid_viscosity(domainSettings); set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT); /* object movement */ for (fobj=fobjects->first; fobj; fobj=fobj->next) { Object *ob = fobj->object; FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); float active= (float) ((fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE) > 0 ? 1 : 0); float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f}; if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) continue; /* init euler rotation values and convert to elbeem format */ /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */ if (i) { copy_v3_v3(old_rot, fobj->Rotation + 4*(i-1)); mul_v3_fl(old_rot, (float)-M_PI / 180.f); } mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat); mul_v3_fl(rot_d, -180.0f / (float)M_PI); set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC); set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC); set_channel(fobj->Scale, timeAtFrame, ob->size, i, CHANNEL_VEC); set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); // printf("Active: %f, Frame: %f\n", active, timeAtFrame); if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { set_channel(fobj->AttractforceStrength, timeAtFrame, &fluidmd->fss->attractforceStrength, i, CHANNEL_FLOAT); set_channel(fobj->AttractforceRadius, timeAtFrame, &fluidmd->fss->attractforceRadius, i, CHANNEL_FLOAT); set_channel(fobj->VelocityforceStrength, timeAtFrame, &fluidmd->fss->velocityforceStrength, i, CHANNEL_FLOAT); set_channel(fobj->VelocityforceRadius, timeAtFrame, &fluidmd->fss->velocityforceRadius, i, CHANNEL_FLOAT); } if (fluid_is_animated_mesh(fluidmd->fss)) { set_vertex_channel(fobj->VertexCache, timeAtFrame, scene, fobj, i); } } } }
static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), FluidsimSettings *domainSettings, FluidAnimChannels *channels, ListBase *fobjects) { Scene *scene = CTX_data_scene(C); Base *base; int i; int length = channels->length; float eval_time; /* XXX: first init time channel - temporary for now */ /* init time values (should be done after evaluating animated time curve) */ init_time(domainSettings, channels); /* allocate domain animation channels */ channels->DomainGravity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "channel DomainGravity"); channels->DomainViscosity = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainViscosity"); //channels->DomainTime = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "channel DomainTime"); /* allocate fluid objects */ for (base=scene->base.first; base; base= base->next) { Object *ob = base->object; FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); if (fluidmd) { FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object"); fobj->object = ob; if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { BLI_addtail(fobjects, fobj); continue; } fobj->Translation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Translation"); fobj->Rotation = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Rotation"); fobj->Scale = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject Scale"); fobj->Active = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject Active"); fobj->InitialVelocity = MEM_callocN( length * (CHANNEL_VEC+1) * sizeof(float), "fluidobject InitialVelocity"); if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { fobj->AttractforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceStrength"); fobj->AttractforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject AttractforceRadius"); fobj->VelocityforceStrength = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceStrength"); fobj->VelocityforceRadius = MEM_callocN( length * (CHANNEL_FLOAT+1) * sizeof(float), "fluidobject VelocityforceRadius"); } if (fluid_is_animated_mesh(fluidmd->fss)) { float *verts=NULL; int *tris=NULL, modifierIndex = modifiers_indexInObject(ob, (ModifierData *)fluidmd); initElbeemMesh(scene, ob, &fobj->numVerts, &verts, &fobj->numTris, &tris, 0, modifierIndex); fobj->VertexCache = MEM_callocN( length *((fobj->numVerts*CHANNEL_VEC)+1) * sizeof(float), "fluidobject VertexCache"); MEM_freeN(verts); MEM_freeN(tris); } BLI_addtail(fobjects, fobj); } } /* now we loop over the frames and fill the allocated channels with data */ for (i=0; i<channels->length; i++) { FluidObject *fobj; float viscosity, gravity[3]; float timeAtFrame; eval_time = domainSettings->bakeStart + i; timeAtFrame = channels->timeAtFrame[i+1]; /* XXX: This can't be used due to an anim sys optimisation that ignores recalc object animation, * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) * --> BKE_animsys_evaluate_all_animation(G.main, eval_time); * This doesn't work with drivers: * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); */ /* Modifying the global scene isn't nice, but we can do it in * this part of the process before a threaded job is created */ scene->r.cfra = (int)eval_time; ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1); /* now scene data should be current according to animation system, so we fill the channels */ /* Domain properties - gravity/viscosity/time */ get_fluid_gravity(gravity, scene, domainSettings); set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC); viscosity = get_fluid_viscosity(domainSettings); set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT); // XXX : set_channel(channels->DomainTime, timeAtFrame, &time, i, CHANNEL_VEC); /* object movement */ for (fobj=fobjects->first; fobj; fobj=fobj->next) { Object *ob = fobj->object; FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); float active= (float)(fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE); float rot_d[3], rot_360[3] = {360.f, 360.f, 360.f}; if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) continue; /* init euler rotation values and convert to elbeem format */ BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotAxis, &ob->rotAngle, ob->rotmode, ROT_MODE_EUL); mul_v3_v3fl(rot_d, ob->rot, 180.f/M_PI); sub_v3_v3v3(rot_d, rot_360, rot_d); set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC); set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC); set_channel(fobj->Scale, timeAtFrame, ob->size, i, CHANNEL_VEC); set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { set_channel(fobj->AttractforceStrength, timeAtFrame, &fluidmd->fss->attractforceStrength, i, CHANNEL_FLOAT); set_channel(fobj->AttractforceRadius, timeAtFrame, &fluidmd->fss->attractforceRadius, i, CHANNEL_FLOAT); set_channel(fobj->VelocityforceStrength, timeAtFrame, &fluidmd->fss->velocityforceStrength, i, CHANNEL_FLOAT); set_channel(fobj->VelocityforceRadius, timeAtFrame, &fluidmd->fss->velocityforceRadius, i, CHANNEL_FLOAT); } if (fluid_is_animated_mesh(fluidmd->fss)) { set_vertex_channel(fobj->VertexCache, timeAtFrame, scene, fobj, i); } } } }