// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== // // // Creation Date: 2007 // // Description: // Create Fluid Disk Cache // // proc int containsString( string $str, string $lst[] ) // // This procedure checks to see if the given $str is contained within the given // list of strings $lst. If found, returns 1. Otherwise, returns 0. // { string $s; for ($s in $lst) { if ($s == $str) return 1; } return 0; } proc string getFileDirFlag( string $cacheFile, string $cacheDirectory ) { string $fileDirFlag = ("-fileName \"" + $cacheFile+"\"" ); if ($cacheDirectory != "") { $fileDirFlag += (" -directory \""+$cacheDirectory+"\" "); } return $fileDirFlag; } proc attachOneCachePerGeometry( string $cacheFiles[], string $objsToCache[], string $channelsToCache[], string $cacheDirectory, string $replaceMode) // // This method is used when the user requests one file per fluid object. // In this case there is an xml file per shape and each fluid node // has its own separate cacheBlend and cacheFile node. // { int $ii; for ($ii = 0; $ii < size($cacheFiles); $ii++) { string $currObj = $objsToCache[$ii]; string $fileDirFlag = getFileDirFlag( $cacheFiles[$ii], $cacheDirectory ); $cacheFiles[$ii] = getCacheFilePath( $cacheDirectory, $cacheFiles[$ii] ); string $objs[] = { $currObj } ; string $cacheBlend[] = getCacheBlend( $objs, $replaceMode ); // Generate the channel and attribute names to be cached. string $attrs[] = {}; string $channelNames[] = {}; string $queryCmd = "cacheFile -q -cacheableAttrs -cacheableNode " + $currObj; string $channels[] = `eval $queryCmd`; int $ct = 0; string $ch, $attr; for ($ch in $channelsToCache) { if (!containsString($ch, $channels)) continue; $channelNames[$ct] = ($currObj + "_" + $ch); if ($ch == "density") $attrs[$ct++] = ($currObj+".inDensity"); else if ($ch == "velocity") $attrs[$ct++] = ($currObj+".inVelocity"); else if ($ch == "temperature") $attrs[$ct++] = ($currObj+".inTemperature"); else if ($ch == "fuel") $attrs[$ct++] = ($currObj+".inReaction"); else if ($ch == "color") $attrs[$ct++] = ($currObj+".inColor"); else if ($ch == "texture") $attrs[$ct++] = ($currObj+".inTextureCoordinates"); else if ($ch == "falloff") $attrs[$ct++] = ($currObj+".inFalloff"); else if ($ch == "resolution") $attrs[$ct++] = ($currObj+".inResolution"); else if ($ch == "offset") $attrs[$ct++] = ($currObj+".inOffset"); } if (size($cacheBlend) > 0) { string $createCmd = ("cacheFile -createCacheNode " + $fileDirFlag); for ($ch in $channelNames) { $createCmd += (" -cnm \"" + $ch + "\"" ); } string $cacheFile = `eval $createCmd`; doFluidCacheConnect( $cacheBlend[0], $cacheFile, $channelNames); } else { doCacheAttach( $objs, $fileDirFlag, $attrs, $channelNames); } // We cannot hide Fluid nodes after caching any more because // they are now displayed for width draw. // hide $objsToCache[$ii]; } } proc attachOneCache( string $cacheFile, string $objsToCache[], string $channelsToCache[], string $cacheDirectory, string $replaceMode) // // This method is used when the user did not request one file per geometry. // In this case, we use a single cacheFile node (and associated xml file) // to drive the array passed into this method. // { string $fileDirFlag = getFileDirFlag( $cacheFile, $cacheDirectory ); int $ii, $objCount = size($objsToCache); string $cacheBlend[] = getCacheBlend( $objsToCache, $replaceMode ); if (size($cacheBlend) > 0) { string $createCmd = ("cacheFile -createCacheNode " + $fileDirFlag ); for ($obj in $objsToCache) { $createCmd += (" -cnm \"" + $obj + "\"" ); } string $cacheFileNode = `eval $createCmd`; doFluidCacheConnect($cacheBlend[0],$cacheFileNode,$objsToCache); } else { string $attrs[]; string $channelNames[]; int $ct = 0; for( $ii = 0; $ii < $objCount; $ii++ ) { string $queryCmd = "cacheFile -q -cacheableAttrs -cacheableNode " + $objsToCache[$ii]; string $channels[] = `eval $queryCmd`; for ($ch in $channelsToCache) { if (!containsString($ch, $channels)) continue; $channelNames[$ct] = ($objsToCache[$ii] + "_" + $ch); if ($ch == "density") $attrs[$ct++] = ($objsToCache[$ii]+".inDensity"); else if ($ch == "velocity") $attrs[$ct++] = ($objsToCache[$ii]+".inVelocity"); else if ($ch == "temperature") $attrs[$ct++] = ($objsToCache[$ii]+".inTemperature"); else if ($ch == "fuel") $attrs[$ct++] = ($objsToCache[$ii]+".inReaction"); else if ($ch == "color") $attrs[$ct++] = ($objsToCache[$ii]+".inColor"); else if ($ch == "texture") $attrs[$ct++] = ($objsToCache[$ii]+".inTextureCoordinates"); else if ($ch == "falloff") $attrs[$ct++] = ($objsToCache[$ii]+".inFalloff"); else if ($ch == "resolution") $attrs[$ct++] = ($objsToCache[$ii]+".inResolution"); else if ($ch == "offset") $attrs[$ct++] = ($objsToCache[$ii]+".inOffset"); } } doCacheAttach($objsToCache,$fileDirFlag,$attrs,$channelNames); } } proc attachCacheGroups( string $cacheFiles[], string $objsToCache[], string $channelsToCache[], string $cacheDirectory, string $replaceMode) { global string $gCacheGroupSeparator; string $cacheGroups[] = `getObjectsByCacheGroup($objsToCache)`; if (size($cacheGroups) == size($objsToCache)) { attachOneCache( $cacheFiles[0], $objsToCache, $channelsToCache, $cacheDirectory, $replaceMode ); } else { int $currGroup = 0; int $nextGroup = getNextCacheGroup($cacheGroups,$currGroup); string $currObjs[]; while ($nextGroup > $currGroup) { clear($currObjs); for ($ii = $currGroup; $ii < $nextGroup; $ii++) { if ($cacheGroups[$ii] != $gCacheGroupSeparator) { $currObjs[size($currObjs)] = $cacheGroups[$ii]; } } if (size($currObjs) > 0) { attachOneCache( $cacheFiles[0], $currObjs, $channelsToCache, $cacheDirectory, $replaceMode ); } $currGroup = $nextGroup; $nextGroup = getNextCacheGroup($cacheGroups,$currGroup); } } } global proc string[] doCreateFluidCache( int $version, string $args[] ) // // Description: // Create cache files on disk for the select fluid object(s) according // to the specified flags described below. // // $version == 1: // $args[0] = time range mode: // time range mode = 0 : use $args[1] and $args[2] as start-end // time range mode = 1 : use render globals // time range mode = 2 : use timeline // $args[1] = start frame (if time range mode == 0) // $args[2] = end frame (if time range mode == 0) // // $version == 2: // $args[3] = cache file distribution, either "OneFile" or "OneFilePerFrame" // $args[4] = 0/1, whether to refresh during caching // $args[5] = directory for cache files, if "", then use project data dir // $args[6] = 0/1, whether to create a cache per geometry // $args[7] = name of cache file. An empty string can be used to specify that an auto-generated name is acceptable. // $args[8] = 0/1, whether the specified cache name is to be used as a prefix // $version == 3: // $args[9] = action to perform: "add", "replace", "merge" or "mergeDelete" // $args[10] = force save even if it overwrites existing files // $args[11] = simulation rate, the rate at which the fluid simulation is forced to run // $args[12] = sample mulitplier, the rate at which samples are written, as a multiple of simulation rate. // $version == 4: // $args[13] = 0/1, whether modifications should be inherited from the cache about to be replaced. // $args[14] = 0/1, whether to store doubles as floats // $args[15] = name of cache format // // $version == 5: // $args[16] = 0/1, whether density should be cached // $args[17] = 0/1, whether velocity should be cached // $args[18] = 0/1, whether temperature should be cached // $args[19] = 0/1, whether fuel should be cached // $args[20] = 0/1, whether color should be cached // $args[21] = 0/1, whether texture coordinates should be cached // $args[22] = 0/1, whether falloff should be cached // { string $cacheFiles[]; if(( $version > 5 ) || ( size($args) > 23 )) { error((uiRes("m_doCreateFluidCache.kFluidCacheBadArgsError"))); return $cacheFiles; } string $cacheDirectory = ""; string $fileName = ""; int $useAsPrefix = 0; int $perGeometry = 0; string $replaceMode = "replace"; int $force = 0; int $inherit = 0; string $distribution = "OneFilePerFrame"; int $rangeMode = $args[0]; float $diskCacheStartTime = $args[1]; float $diskCacheEndTime = $args[2]; float $simulationRate = 1.0; int $sampleMultiplier = 1; float $startTime = $diskCacheStartTime; float $endTime = $diskCacheEndTime; string $format = "mcx"; // Maya's default internal format if( $rangeMode == 1 ) { $startTime = `getAttr defaultRenderGlobals.startFrame`; $endTime = `getAttr defaultRenderGlobals.endFrame`; } else if( $rangeMode == 2 ) { $startTime = `playbackOptions -q -min`; $endTime = `playbackOptions -q -max`; } if ($version > 1) { $distribution = $args[3]; $cacheDirectory = $args[5]; $perGeometry = $args[6]; $fileName = $args[7]; $useAsPrefix = $args[8]; } if ($version > 2) { $replaceMode = $args[9]; $force = $args[10]; if (size($args) > 11 ) { $simulationRate = $args[11]; } if (size($args) > 12 ) { $sampleMultiplier = $args[12]; } } if( $version > 3 ) { $inherit = $args[13]; } if( $version > 4 ) { $format = $args[15]; } // Call doMergeCache instead since it handles gaps between // caches correctly. if( $replaceMode == "merge" || $replaceMode == "mergeDelete" ) { float $startTime = $args[1]; float $endTime = $args[2]; if( $args[0] == 1 ) { $startTime = `getAttr defaultRenderGlobals.startFrame`; $endTime = `getAttr defaultRenderGlobals.endFrame`; } else if( $args[0] == 2 ) { $startTime = `playbackOptions -q -min`; $endTime = `playbackOptions -q -max`; } string $mergeArgs[]; $mergeArgs[0] = 1; $mergeArgs[1] = $startTime; $mergeArgs[2] = $endTime; $mergeArgs[3] = $args[3]; $mergeArgs[4] = $cacheDirectory; $mergeArgs[5] = $fileName; $mergeArgs[6] = $useAsPrefix; $mergeArgs[7] = $force; $mergeArgs[8] = $simulationRate; $mergeArgs[9] = $sampleMultiplier; $mergeArgs[10] = $replaceMode; $mergeArgs[11] = "fluid"; $mergeArgs[12] = $format; return doMergeCache(2, $mergeArgs); } // If we're replacing a cache, and inheriting modifications, // the new cache should have the same translation, scaling // and clipping as the original. So store these values and // set after cache creation. // float $startFrame[] = {}; float $sourceStart[] = {}; float $sourceEnd[] = {}; float $scale[] = {}; select -d `ls -sl -type cacheFile`; string $objsToCache[] = getFluidObjectsToCache(1); if ($replaceMode == "add" ) { if (getCacheCanBeReplaced($objsToCache)) { if ( cacheReplaceNotAdd($objsToCache)) { $replaceMode = "replace"; } } } if ($replaceMode == "replace") { if (!getCacheCanBeReplaced($objsToCache)) { return $cacheFiles; } if( $inherit ) { string $obj, $cache; for( $obj in $objsToCache ) { string $existing[] = findExistingCaches($obj); int $index = size($startFrame); $startFrame[$index] = `getAttr ($existing[0]+".startFrame")`; $sourceStart[$index] = `getAttr ($existing[0]+".sourceStart")`; $sourceEnd[$index] = `getAttr ($existing[0]+".sourceEnd")`; $scale[$index] = `getAttr ($existing[0]+".scale")`; } } } // If the user has existing cache groups on some of the geometry, // then they cannot attach new caches per geometry. // string $cacheGroups[] = `getObjectsByCacheGroup($objsToCache)`; if (size($cacheGroups) != size($objsToCache)) { $perGeometry = 0; $args[6] = 0; // used below in generating cache file command warning( (uiRes("m_doCreateFluidCache.kIgnoringPerGeometry")) ); } // Check if directory has caches that might be overwritten // verifyWorkspaceFileRule( "fluidCache", "cache/nCache/fluid" ); $cacheDirectory = getCacheDirectory($cacheDirectory, "fluidCache", $objsToCache, $fileName, $useAsPrefix, $perGeometry, $replaceMode, $force, 0); if ($cacheDirectory == "") { return $cacheFiles; } else if ($cacheDirectory == "rename") { // must use eval deferred to ensure the hideOptionBox call from // doCreateFluidCache does not close our newly posted option box // string $cmdString = ("performCreateFluidCache 1 "+$replaceMode); evalDeferred($cmdString); error( (uiRes("m_doCreateFluidCache.kFluidFileAlreadyExists"))); return $cacheFiles; } // if we're replacing, delete active caches. // if( $replaceMode == "replace" ) { for( $obj in $objsToCache ) { string $all[] = findExistingCaches($obj); for( $cache in $all) { if( `getAttr ($cache+".enable")`) { deleteCacheFile(2, {"keep",$cache}); } } } } // create the cache(s) // if ($replaceMode == "add" || $replaceMode == "replace") { setCacheEnable(0, 1, $objsToCache); } // generate the cacheFile command to write the caches // string $cacheCmd = getCacheFileCmd($version, $cacheDirectory, $args); $cacheCmd += " -runupFrames 0"; int $ii = 0; // Create a list of the attributes to cache. string $channelsToCache[]; int $ctc = 0; if ($args[16] == "1") { $channelsToCache[$ctc++] = "density"; $cacheCmd += (" -cch density"); } if ($args[17] == "1") { $channelsToCache[$ctc++] = "velocity"; $cacheCmd += (" -cch velocity"); } if ($args[18] == "1") { $channelsToCache[$ctc++] = "temperature"; $cacheCmd += (" -cch temperature"); } if ($args[19] == "1") { $channelsToCache[$ctc++] = "fuel"; $cacheCmd += (" -cch fuel"); } if ($args[20] == "1") { $channelsToCache[$ctc++] = "color"; $cacheCmd += (" -cch color"); } if ($args[21] == "1") { $channelsToCache[$ctc++] = "texture"; $cacheCmd += (" -cch texture"); } if ($args[22] == "1") { $channelsToCache[$ctc++] = "falloff"; $cacheCmd += (" -cch falloff"); } $channelsToCache[$ctc++] = "resolution"; $cacheCmd += (" -cch resolution"); $channelsToCache[$ctc++] = "offset"; $cacheCmd += (" -cch offset"); for( $obj in $objsToCache ) { if ($args[16] == "1") setAttr ($obj + ".cacheDensity") 1; else setAttr ($obj + ".cacheDensity") 0 ; if ($args[17] == "1") setAttr ($obj + ".cacheVelocity") 1; else setAttr ($obj + ".cacheVelocity") 0 ; if ($args[18] == "1") setAttr ($obj + ".cacheTemperature") 1; else setAttr ($obj + ".cacheTemperature") 0 ; if ($args[19] == "1") setAttr ($obj + ".cacheReaction") 1; else setAttr ($obj + ".cacheReaction") 0 ; if ($args[20] == "1") setAttr ($obj + ".cacheColor") 1; else setAttr ($obj + ".cacheColor") 0 ; if ($args[21] == "1") setAttr ($obj + ".cacheTextureCoordinates") 1; else setAttr ($obj + ".cacheTextureCoordinates") 0 ; if ($args[22] == "1") setAttr ($obj + ".cacheFalloff") 1; else setAttr ($obj + ".cacheFalloff") 0 ; } // cache format argument $cacheCmd += " -cacheFormat " + $format; //segmented cache files are employed in the case of one large cache file that //exceeds 2GB in size. We only need to do that for the legacy mcc format as the new // mcx type can now handle files > 2GB. int $useSegmentedCacheFile = 0; int $numSegments = 0; if($distribution == "OneFile" && !$perGeometry && $format == "mcc" ) { string $queryCacheSizeCmd = "cacheFile"; for ($ii = 0; $ii < size($objsToCache); $ii++) { $queryCacheSizeCmd += (" -cnd "+$objsToCache[$ii]); } $queryCacheSizeCmd += " -q -dataSize"; float $dataSizePerFrame = `eval $queryCacheSizeCmd`; float $maxSize = 2147000000; //approximate size of max signed int. float $numSamples = ($endTime - $startTime + 1.0)/($simulationRate*$sampleMultiplier); float $dataSize = $dataSizePerFrame*$numSamples; if($dataSize > $maxSize) { $useSegmentedCacheFile = 1; $numSegments = floor($dataSize / $maxSize) + 1; } } if(!$useSegmentedCacheFile) { if( $fileName != "" ) { $cacheCmd += ("-fileName " + $fileName + " "); } $cacheCmd += ("-st "+$startTime+" -et "+$endTime); for ($ii = 0; $ii < size($objsToCache); $ii++) { $cacheCmd += (" -cnd "+$objsToCache[$ii]); if ($perGeometry) { string $descriptionCmd = ("getFluidDescriptionInfo "+$objsToCache[$ii]); $cacheCmd += (" -cacheInfo \""+$descriptionCmd+"\""); } } if (! $perGeometry) { string $descriptionCmd = ("getFluidDescriptionInfo selected"); $cacheCmd += (" -cacheInfo \""+$descriptionCmd+"\""); } $cacheFiles = `eval $cacheCmd`; } else { int $jj; float $segmentStartTime = $startTime; float $segmentEndTime; float $segmentLength = ($endTime - $startTime)/$numSegments; string $segmentCacheCmd ; string $segmentCacheName = ""; string $segmentCacheFiles[]; for($jj = 0; $jj< $numSegments; $jj++) { $segmentCacheCmd = $cacheCmd; if($fileName != "") $segmentCacheName = $fileName; else $segmentCacheName = getAutomaticFluidCacheName(); $segmentEndTime = $segmentStartTime + floor($segmentLength); $segmentCacheName += ("Segment" + ($jj+1)); $segmentCacheCmd += (" -fileName " + $segmentCacheName + " "); $segmentCacheCmd += ("-st "+$segmentStartTime+" -et "+$segmentEndTime); for ($ii = 0; $ii < size($objsToCache); $ii++) { $segmentCacheCmd += (" -cnd "+$objsToCache[$ii]); } string $descriptionCmd = ("getFluidDescriptionInfo selected"); $segmentCacheCmd += (" -cacheInfo \""+$descriptionCmd+"\""); $segmentCacheFiles = `eval $segmentCacheCmd`; $segmentStartTime = $segmentEndTime + 1; $cacheFiles[size($cacheFiles)] = $segmentCacheFiles[0]; } } // attach the caches to the fluid // // For now, just set the filename and directory name directly on the fluidShape node. if($useSegmentedCacheFile) { if(size($objsToCache) == 1) { for($ii=0;$ii= $sStart && $sourceStart[$i] <= $sEnd ) { cacheClipTrimBefore( $cache[0], $sourceStart[$i] ); } if( $sEnd != $sourceEnd[$i] && $sourceEnd[$i] >= $sStart && $sourceEnd[$i] <= $sEnd ) { cacheClipTrimAfter( $cache[0], $sourceEnd[$i] ); } setAttr ($cache[0] + ".startFrame") $startFrame[$i]; setAttr ($cache[0] + ".scale") $scale[$i]; } } select -r $objsToCache; return $cacheFiles; }