//////////////////////Simulation Script/////////////////////////////// //================================================================== //Copyright (C) 2007 Celambarasan Ramsamy // //This program is free software; you can redistribute it and/or //modify it under the terms of the GNU General Public License //as published by the Free Software Foundation. // // //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. //=================================================================== // List Of Globals global float $ctPreviousFrameVertexTranslationArrayWind[]; global float $ctTempPreviousFrameVertexTranslationArrayWind[]; // Temporarly stores up the previous frame displacement values to ensure that subsequent layersafter the first layer has access to it global string $ctSelectedVertexNamesWind[]; global int $ctSelectedVertexCountWind; global int $ctLayerCountWind; global int $ctWidthCount; global int $ctHeightCount; global int $ctUIState=0; global string $ctLayerScalingSliders[]; global float $ctPreviousFrameLayerScalingFactor[]; global int $ctSelectionMask=46; // Initialize selection mask to select lattice points proc float ctWindAmplitudeGenerator(float $ctU,float $ctV,float $ctUOffset,float $ctVOffset) { $ctU=$ctU+($ctUOffset); $ctV=$ctV+($ctVOffset); // Values read in from the UI float $ctA=`floatSliderGrp -q -value ctWaveIrregularitiesA`; float $ctB=`floatSliderGrp -q -value ctWaveIrregularitiesB`; float $ctC=`floatSliderGrp -q -value ctWaveIrregularitiesC`; float $ctD=`floatSliderGrp -q -value ctWaveIrregularitiesD`; // Get the vertical offset to make the wavelet interval irregular float $ctWaveIrregularityFactor=((noise($ctV * $ctA /*Speed at which the irregularity changes*/,($ctU+($ctV * $ctB)/* $ctV helps make the waves seem to move vertically...high value makes the wave to flutter*/) * $ctC/*Controls the curves in the wind(Lower the value the straighter the wind)*/)+1.0)*0.5) * $ctD; /*This value gives the max tightness factor(How close can adjucant waves get)*/ // Translate the noise interval to 0 - 1 interval $ctV=$ctV+$ctWaveIrregularityFactor; /* The furthest the adjucant wavelets can get is defined by the normal value of $ctv without the above noise function(the normal speed).*/ float $ctUScalingFactorArray[]=`floatFieldGrp -q -value ctURangeScalingFactor`; float $ctVScalingFactorArray[]=`floatFieldGrp -q -value ctURangeScalingFactor`; // Scale the noise domain as needed $ctU=$ctU * $ctUScalingFactorArray[0]; $ctV=$ctV * $ctVScalingFactorArray[0]; float $tWindMagnitude=((sin(3.14*$ctV) * `floatSliderGrp -q -value ctBaseWaveMotionComponent`) + (sin(3.14*$ctV) * `floatSliderGrp -q -value ctMagnitudeDifferenceScaling` * $ctWaveIrregularityFactor)); // here the wind amplitude without $ctWaveIrregularityFactor is the maximum possible amplitude possible...$ctWaveIrregularityFactor value helps to reduce the displacement at places where adjacent waves are not close together return $tWindMagnitude; } //////////////// Adds points Lattice layer points before the wind function is initialized ////////// global proc ctAddLayerPoints(int $ctLayerId[]) { global int $ctSelectedVertexCountWind; global int $ctWidthCount; global int $ctHeightCount; global int $ctLayerCountWind; global int $ctSelectionMask; string $ctSelectedVertices1[]; global string $ctSelectedVertexNamesWind[]; string $ctTempSelectionString="filterExpand -sm " + $ctSelectionMask; // Get the list of selected vertices $ctSelectedVertices1 =eval($ctTempSelectionString); // Get the vertex count $ctSelectedVertexCountWind = size($ctSelectedVertices1); int $ctExpectedVertexCount=($ctWidthCount * $ctHeightCount); // Error Checks if($ctLayerId[0] < 0) { print ("Error: Current Layer Count cannot be negative\n"); return; } if($ctSelectedVertexCountWind != $ctExpectedVertexCount) { print ("Error: The number of selected Points does not match the expected vertex count of " + $ctExpectedVertexCount + "\n"); return; } if($ctLayerCountWind <= $ctLayerId[0]) { print ("Error: Current Layer Count cannot exceed total number of layers\n"); return; } int $cti=0; // Process and store each of the selected vertices for($cti=0;$cti<$ctSelectedVertexCountWind;$cti++) { $ctSelectedVertexNamesWind[($ctLayerId[0]*$ctSelectedVertexCountWind) + $cti]=$ctSelectedVertices1[$cti]; } print ("Selected Points added sucessfully to Layer " + $ctLayerId[0] + "\n"); } // Layer count starts from 0 to n-1 for a lattice with n points // The magnitudes are layered from top to bottom 0th layer has the most displacement and the nth layer has least displacement //////////////// Main Function ///////////////// global proc ctWindMain() { // Globals global float $ctPreviousFrameVertexTranslationArrayWind[]; global float $ctTempPreviousFrameVertexTranslationArrayWind[]; global string $ctSelectedVertexNamesWind[]; global int $ctSelectedVertexCountWind; global int $ctWidthCount; global int $ctHeightCount; global int $ctLayerCountWind; global string $ctLayerScalingSliders[]; global float $ctPreviousFrameLayerScalingFactor[]; global int $ctCurrentFrameCountWind; global float $ctCurrentFrameXDisplacementWind; global float $ctCurrentFrameYDisplacementWind; global float $ctCurrentFrameZDisplacementWind; global float $ctUWind; global float $ctVWind; float $ctCurrentLayerScalingFactor; // Stores the scaling factor value for the current layer // Read the current frame count $ctCurrentFrameCountWind=`currentTime -q`; // Update the vertex positions for this frame int $cti=0; int $ctj=0; int $ctCurrentVertexCount; int $ctCurrentLayerCount; // Retreive and store the remapped UV range float $ctRemappedURange[]=eval("floatFieldGrp -q -value ctURange"); float $ctRemappedVRange[]=eval("floatFieldGrp -q -value ctVRange"); // Retrive and set the wind direction from UI float $ctWindDirectionArray[]=eval("floatFieldGrp -q -value ctWindDirection"); // Normalize the direction vector normalize($ctWindDirectionArray); vector $ctWindDirection=<<$ctWindDirectionArray[0],$ctWindDirectionArray[1],$ctWindDirectionArray[2]>>; // Update all the vertices in each layer going from top to bottom (0 to (n-1)) for($ctCurrentLayerCount=0;$ctCurrentLayerCount < $ctLayerCountWind;$ctCurrentLayerCount++) { // Retreive the layer scaling factor from the last frame float $ctTempPreviousFrameScalingFactorForThisFrame; // The top most layer does not have a scaling factor if($ctCurrentLayerCount >0) $ctTempPreviousFrameScalingFactorForThisFrame=$ctPreviousFrameLayerScalingFactor[$ctCurrentLayerCount-1]; for($ctj=0;$ctj<$ctHeightCount;$ctj++) { for($cti=0;$cti<$ctWidthCount;$cti++) { $ctUWind = (float)$cti / (float)($ctWidthCount-1); $ctVWind = (float)$ctj / (float)($ctHeightCount-1); // Remap the actual UV values of the points into the UV range Specified in the UI float $ctRemappedU=($ctRemappedURange[0] * (1.0 - $ctUWind))+($ctRemappedURange[1] * $ctUWind); float $ctRemappedV=($ctRemappedVRange[0] * (1.0 - $ctVWind))+($ctRemappedVRange[1] * $ctVWind); // Calculate the index of the current vertex $ctCurrentVertexCount=($ctj * $ctWidthCount)+$cti; // Only for the first layer look up the noise function and generate the displacement.. for the rest of the layers just sacle the generated displacement and reuse it if($ctCurrentLayerCount==0) { // Move the vertex back to it’s original position, by reverse translating based on the previous frame translation values stored in the $ctPreviousFrameVertexTranslationArray[] // Reset the vertex to the original position move -r (-$ctPreviousFrameVertexTranslationArrayWind[3*$ctCurrentVertexCount]) (-$ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+1]) (-$ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+2]) $ctSelectedVertexNamesWind[($ctCurrentLayerCount*$ctSelectedVertexCountWind) + $ctCurrentVertexCount]; // Assume that the last $ctSelectedVertexCountWind value is equal to the total vertex count in each layer float $ctOffset; float $ctScaledOffset; // Read into the three dimensional noise field for a offset magnitude $ctOffset=ctWindAmplitudeGenerator($ctRemappedU,$ctRemappedV,0.0,(float)$ctCurrentFrameCountWind * `floatSliderGrp -q -value ctTimeScaling` /*Controls the speed of wind*/); //`noise <<$cti,$cti,($ctCurrentFrameCount1 * 0.04 /* Controls the speed of the oscillation*/)>>`; $ctScaledOffset=$ctOffset * `floatSliderGrp -q -value ctOverallMagnitudeScaling`; /* Controls the magnitude of the displacement */ $ctCurrentFrameXDisplacementWind=$ctWindDirection.x * $ctScaledOffset; $ctCurrentFrameYDisplacementWind=$ctWindDirection.y * $ctScaledOffset; $ctCurrentFrameZDisplacementWind=$ctWindDirection.z * $ctScaledOffset; // Offset the vertex in the current frame and in the current layer move -r $ctCurrentFrameXDisplacementWind $ctCurrentFrameYDisplacementWind $ctCurrentFrameZDisplacementWind $ctSelectedVertexNamesWind[($ctCurrentLayerCount*$ctSelectedVertexCountWind) + $ctCurrentVertexCount]; //print $ctSelectedVertexNamesWind[($ctCurrentLayerCount*$ctSelectedVertexCountWind) + $ctCurrentVertexCount]; // Back up the previous frame displacement values for the other layers $ctTempPreviousFrameVertexTranslationArrayWind[3*$ctCurrentVertexCount]=$ctPreviousFrameVertexTranslationArrayWind[3*$ctCurrentVertexCount]; $ctTempPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+1]=$ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+1]; $ctTempPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+2]=$ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+2]; // Store the current frame displacement in the array $ctPreviousFrameVertexTranslationArrayWind[3*$ctCurrentVertexCount]=$ctCurrentFrameXDisplacementWind; $ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+1]=$ctCurrentFrameYDisplacementWind; $ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+2]=$ctCurrentFrameZDisplacementWind; } else { // Reset the vertex to the original position move -r (-$ctTempPreviousFrameVertexTranslationArrayWind[3*$ctCurrentVertexCount] * $ctTempPreviousFrameScalingFactorForThisFrame) (-$ctTempPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+1] * $ctTempPreviousFrameScalingFactorForThisFrame) (-$ctTempPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+2] * $ctTempPreviousFrameScalingFactorForThisFrame) $ctSelectedVertexNamesWind[($ctCurrentLayerCount*$ctSelectedVertexCountWind) + $ctCurrentVertexCount]; // Assume that the last $ctSelectedVertexCountWind value is equal to the total vertex count in each layer string $ctTempCommandString="floatSliderGrp -q -value " + $ctLayerScalingSliders[$ctCurrentLayerCount-1]; // Get the scaling factor for the current layer from the UI $ctCurrentLayerScalingFactor=eval($ctTempCommandString); //print $ctCurrentLayerScalingFactor; float $ctCurrentFrameXDisplacementWind1=$ctCurrentLayerScalingFactor * $ctPreviousFrameVertexTranslationArrayWind[3*$ctCurrentVertexCount]; float $ctCurrentFrameYDisplacementWind1=$ctCurrentLayerScalingFactor * $ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+1]; float $ctCurrentFrameZDisplacementWind1=$ctCurrentLayerScalingFactor * $ctPreviousFrameVertexTranslationArrayWind[(3*$ctCurrentVertexCount)+2]; // Offset the vertex in the current frame and in the current layer move -r $ctCurrentFrameXDisplacementWind1 $ctCurrentFrameYDisplacementWind1 $ctCurrentFrameZDisplacementWind1 $ctSelectedVertexNamesWind[($ctCurrentLayerCount*$ctSelectedVertexCountWind) + $ctCurrentVertexCount]; } } } // Store the current frame scaling factor for the next frame // Top layer does not have a scaling factor if($ctCurrentLayerCount >0) $ctPreviousFrameLayerScalingFactor[$ctCurrentLayerCount-1]=$ctCurrentLayerScalingFactor; } } //// The Script for the UI /////// // Validates the parameters returned from the UI before storing them to the Variables global proc ctValidateLayerCount(int $ctLayerCount[],int $ctTempWidthCount[],int $ctTempHeightCount[],int $ctTempSelectionMask[]) { global int $ctLayerCountWind; global int $ctWidthCount; global int $ctHeightCount; global int $ctUIState; global int $ctSelectionMask; // Make sure that the layer count is greater than zero if(($ctLayerCount[0] < 0)||($ctTempWidthCount[0] < 0)||($ctTempHeightCount[0] < 0)) { print("Error: Entered Value cannot be negative enter a valid positive value\n"); return; } // make sure the layer count is not equal to zero if(($ctLayerCount[0] == 0)||($ctTempWidthCount[0] == 0)||($ctTempHeightCount[0] == 0)) { print("Error: Entered Value cannot be zero.Enter a valid positive value\n"); return; } if($ctTempSelectionMask[0]<0) { print("Selection Mask value cannot be negative, Enter a valid 'FilterExpand' command selection mask value\n"); return; } // If the value returned from the UI is valid then store the value and move the UI to the next state $ctLayerCountWind=$ctLayerCount[0]; $ctWidthCount=$ctTempWidthCount[0]; $ctHeightCount=$ctTempHeightCount[0]; $ctSelectionMask=$ctTempSelectionMask[0]; // Reset the global arrays before the simulation global float $ctPreviousFrameVertexTranslationArrayWind[]; global float $ctTempPreviousFrameVertexTranslationArrayWind[]; global float $ctPreviousFrameLayerScalingFactor[]; int $cti=0; for($cti=0;$cti<($ctWidthCount*$ctHeightCount);$cti++) { $ctPreviousFrameVertexTranslationArrayWind[3*$cti]=0.0; $ctPreviousFrameVertexTranslationArrayWind[(3*$cti)+1]=0.0; $ctPreviousFrameVertexTranslationArrayWind[(3*$cti)+2]=0.0; $ctTempPreviousFrameVertexTranslationArrayWind[3*$cti]=0.0; $ctTempPreviousFrameVertexTranslationArrayWind[(3*$cti)+1]=0.0; $ctTempPreviousFrameVertexTranslationArrayWind[(3*$cti)+2]=0.0; } for($cti=1;$cti<($ctLayerCountWind);$cti++) { $ctPreviousFrameLayerScalingFactor[$cti-1]=0.0; } // Move the uI configuration to the next state $ctUIState++; print ("Values Set Sucessfully\n"); } global proc ctWindUI() { int $ctIsDeveloping=true; global int $ctLayerCountWind; global int $ctWidthCount; global int $ctHeightCount; global int $ctUIState; // If the window already exists then delete and create a new one if($ctIsDeveloping && `window -exists ctWindUIWindow`) { deleteUI ctWindUIWindow; } // Create a new UI if the window already doesn`t exist if(!`window -exists ctWindUIWindow`) { window -title "Simulation" ctWindUIWindow; scrollLayout; columnLayout -columnOffset "both" 3; // Select the Current UI Configuration to display switch($ctUIState) { case 0: // Initial state that sets up the initial values needed for simulation text -label "Enter a valid 'FilterExpand' command selection mask for the type of component to be selected (Look up the MEL command reference for 'FilterExpand' command Mask Values). "; separator; intFieldGrp -value 46 0 0 0 -label "Selection Mask" ctSelectionMask; separator; separator; separator; intFieldGrp -value 1 1 1 1 -label "Total Number of Layers" ctTotalLayerCount; // Explain in documentation about how which direction represents the horizontal and which direction represents vertical intFieldGrp -value 2 1 1 1 -label "Horizontal Points Count" ctHorizontalPointsCount; intFieldGrp -value 2 1 1 1 -label "Vertical Points Count" ctVerticalPointsCount; button -label "Initialize Simulation Values" -command "ctValidateLayerCount(eval(\"intFieldGrp -q -value ctTotalLayerCount\"),eval(\"intFieldGrp -q -value ctHorizontalPointsCount\"),eval(\"intFieldGrp -q -value ctVerticalPointsCount\"),eval(\"intFieldGrp -q -value ctSelectionMask\")); ctWindUI();" ctAddValuesButton; button -label "Reset All" -command "$ctUIState=0;" ctResetButton; break; case 1: // Second UI state where Lattice points for each group is added text -label "Select and add the points belonging to each layer, Layer count ranges from 0(Top Most Layer) to (Total Number of Layers - 1)(Bottom Most Layer)."; text -label "When you finish adding the points belonging to all the layers, hit the 'Begin Simulation' Button."; separator; separator; separator; intFieldGrp -value 0 1 1 1 -label "Current Layer Count" ctCurrentLayerCount; button -label "Add Points to Layer" -command "ctAddLayerPoints(eval(\"intFieldGrp -q -value ctCurrentLayerCount\"))" ctAddPointsToLayerButton; button -label "Reset All" -command "$ctUIState=0; ctWindUI();" ctResetButton; button -label "Begin Simulation" -command "$ctUIState++; ctWindUI(); ctWindMain();" ctBeginSimulation; // Begins the simulation break; case 2: { // The final UI state that has controls for all the parameters of the wind simulation int $ctTempi; float $ctCurrentLayerScalingFactor; // Stores the scaling factor value for the current layer // Controls for the wind simulation on layer 0 text -label "Simulation Control For Layer-0 (TopMost Layer)"; separator; floatFieldGrp -value 0.0 1.0 -1.0 0.0 -numberOfFields 3 -label "Wave Direction" ctWindDirection; floatFieldGrp -value 0.0 1.0 0.0 0.0 -numberOfFields 2 -label "U range" ctURange; floatFieldGrp -value 0.0 1.0 0.0 0.0 -numberOfFields 2 -label "V range" ctVRange; floatFieldGrp -value 4.0 1.0 0.0 0.0 -numberOfFields 1 -label "U range Scaling Factor" ctURangeScalingFactor; floatFieldGrp -value 4.0 1.0 0.0 0.0 -numberOfFields 1 -label "V range Scaling Factor" ctVRangeScalingFactor; separator; separator; text -label "Controls for controlling the Nature of Wave Irregularities"; separator; text -label "V = V + (noise(V*A,(U+(V*B))*C)) * D"; separator; text -label "U : Current U value(Horizontal Position)"; text -label "V : Current V value(Vertical Position)"; text -label "A : How quickly does it change from being turbulent to being calm? Lesser Value generates more consistent waves"; text -label "B : How fast does the wave patterns move along the side as they travel through the field? Higher Values, faster sideways movement"; text -label "C : How Curved are the generated waves? Lesser Value, Lesser Curve"; text -label "D : This sets the highest possible tightness between two adjacent wavelets.Higher the value,tighter they get.Setting this value to zero shows the farthest distance possible between two waves"; separator; separator; separator; floatSliderGrp -label "Wave Persitance Rate(A)" -field true -value 2.6 -step 0.001 -precision 4 ctWaveIrregularitiesA; floatSliderGrp -label "Side Movement Rate(B)" -field true -value 2.0 -step 0.001 -precision 4 ctWaveIrregularitiesB; floatSliderGrp -label "Wave Curve Factor(C)" -field true -value 1.5 -step 0.001 -precision 4 ctWaveIrregularitiesC; floatSliderGrp -label "Tightness Factor(D)" -field true -value 0.5 -step 0.001 -precision 4 ctWaveIrregularitiesD; separator; separator; separator; text -label "Final Wave Magnitude=(sin(3.14*V)*(F)) + (sin(3.14*V))*(E)*(Value From the Above Noise Function))"; separator; text -label "U : Current U value(Horizontal Position)"; text -label "V : Current V value(Vertical Position)"; separator; separator; text -label "Sections of the wave closer together have higher displacement than the sections that are further apart.This value scales the difference beteen the least and the highest magnitude (This value varies based on the value of noise function above)"; separator; floatSliderGrp -label "Mag. Diff. Scaling Factor(E)" -field true -value 0.3 -minValue -1000 -maxValue 1000 -step 0.001 -precision 4 ctMagnitudeDifferenceScaling; separator; separator; text -label "This component increases the influence of the direct sine wave component without any irregularities"; separator; floatSliderGrp -label "Sine Component(F)" -field true -value 0.0 -minValue -1000 -maxValue 1000 -step 0.001 -precision 4 ctBaseWaveMotionComponent; separator; separator; separator; floatSliderGrp -label "Magnitude Scaling Factor" -field true -value 2.0 -minValue -1000 -maxValue 1000 -step 0.001 -precision 4 ctOverallMagnitudeScaling; floatSliderGrp -label "Wave Speed Factor" -field true -value 0.005 -step 0.001 -minValue -1 -maxValue 1 -precision 4 ctTimeScaling; separator; separator; separator; text -label "Subsequent Layers Scaling Factor"; separator; global string $ctLayerScalingSliders[]; // Draw the one float slider group for each layer starting from the second layer to the last layer for($ctTempi=1;$ctTempi<$ctLayerCountWind;$ctTempi++) { // Calculate the scaling factor for the current layer with respect to the top most layer $ctCurrentLayerScalingFactor=(float)(($ctLayerCountWind-1) - $ctTempi)/(float)($ctLayerCountWind-1); $ctLayerScalingSliders[($ctTempi-1)] = "ctSlider" + ($ctTempi); string $ctTempCommandString="floatSliderGrp -field true -step 0.001 -minValue -10 -maxValue 10 -value "+ $ctCurrentLayerScalingFactor +" -label \"Layer "+($ctTempi)+ "\" " +$ctLayerScalingSliders[($ctTempi-1)]; eval($ctTempCommandString); } separator; separator; separator; separator; button -label "Reset All" -command "$ctUIState=0; ctWindUI();" ctResetButton; } break; default: // If the switch happens to gointo a invalid state then reset the UI back to the initial state $ctUIState=0; // Initial state that gets the total number of layers to be used intFieldGrp -value 1 1 1 1 -label "Total Number of Layers" ctTotalLayerCount; // Explain in documentation about how which direction represents the horizontal and which direction represents vertical intFieldGrp -value 2 1 1 1 -label "Horizontal Points Count" ctHorizontalPointsCount; intFieldGrp -value 2 1 1 1 -label "Vertical Points Count" ctVerticalPointsCount; button -label "Set Values" -command "ctValidateLayerCount(eval(\"intFieldGrp -q -value ctTotalLayerCount\"),eval(\"intFieldGrp -q -value ctHorizontalPointsCount\"),eval(\"intFieldGrp -q -value ctVerticalPointsCount\")); ctWindUI();" ctAddValuesButton; button -label "Reset All" -command "$ctUIState=0; ctWindUI();" ctResetButton; break; } showWindow ctWindUIWindow; } }