cloth physics exp. kit
══════════════════
Introduction
══════════════════
this is part 2 of a series
although you may be able to use this, it is meant as a study and demonstration for
daz-script coders
in part 1 we saw particle physics : http://sites.google.com/site/mcasualsdazscripts/particle-physics
this script too is based on the article "Advanced Character Physics" by Thomas Jakobsen
http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml
══════════════════
History
══════════════════
02/07/2010 Release
══════════════════
Installation
══════════════════
download the dip at the bottom of this page
unzip it in your daz content folder
typically c:\program files\daz\studio\content
this will install the cloth.cr2 figure in the
content / Figure / mcasual folder
and the scripts mcjPhysicsExp2.dsa and mcjPhysicsExp2DS1and2.ds
scripts in the studio/scripts/mcasual folder
also mcjPhysicsExp2_readme.txt will be placed in content/readme's
your scene must contain a "cloth.cr2" figure
this figure is part of the distribution Zip file
see the attachments at the bottom of this page
when you load it, the cloth is invisible because
all the vertices are located at ( 0, 0, 0 )
this figure has 243 morph channels that allow
this script to totally control its shape
you should never move the cloth figure
your scene must also contain a cylinder (re)named "pole"
this cylinder should be 1 meter long
the piece of cloth will attach itself to this pole
during the simulation
══════════════════
Use
══════════════════
- parent the 'pole' to a character's hand
- animate the character. the animation goes from frames 0 to 100
run the script, processing on a recently started Daz Studio can take 46 seconds
this delay may then double! each time the script is run
so we suggest you save your scene, close daz studio,
then reload your scene before running the script
source code:
// DAZ Studio version 3.0 filetype DAZ Script
// written by mCasual/Jacques
// based on: "Advanced Character Physics" by Thomas Jakobsen
// http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml
// your scene must contain a "cloth.cr2" figure
// this figure is part of the distribution Zip file
// when you load it, the cloth is invisible because
// all the vertices are located at ( 0, 0, 0 )
// this figure has 243 morph channels that allow
// this script to totally control its shape
// you should never move the cloth figure
// your scene must contain a cylinder (re)named "pole"
// this cylinder should be 1 meter long
// the piece of cloth will attach itself to this pole
// during the simulation
// typical use:
// - parent the 'pole' to a character's hand
// - animate the character. the animation goes from frames 0 to 100
// run the script, processing on a recently started Daz Studio can take 46 seconds
// this delay may then double! each time the script is run
// so we suggest you save your scene, close daz studio,
// then reload your scene before running the script
//================================================================================================
//
//================================================================================================
var clothNode;
var clothObj;
var poleNode;
var NUM_PARTICLES = 81;
m_x = new Array(); // Current positions
m_oldx = new Array(); // Previous positions
m_a = new Array(); // Force accumulators
m_fTimeStep = 1.0 / 30.0;
m_fTimeStepSquared = m_fTimeStep * m_fTimeStep;
//note: gravity was reduced from the real value of 980
//to get a more "floaty" cloth
//things to try : no gravity, strong wind from the side : DzVec3( -400, 0, 0 )
m_vGravity = new DzVec3( 0, -400, 0 ); // Gravity in cm / sec^2
var NumDiv = 8; //the cloth figure is based on a simple 8x8 plane
var numRows = NumDiv +1
var numCols = NumDiv + 1
var linklen = 100 / NumDiv; //setting the distance between the vertices
//================================================================================================
//
//================================================================================================
function Verlet()
{
var a;
getPole(); //the first row of the cloth vertices follows the pole
//the other vertices are subject to the forces( gravity in this case )
//and velocity
for( var i = numCols; i < NUM_PARTICLES; i++ )
{
x = m_x[i];
tempx = x;
x = x.add( tempx );
x = x.subtract( m_oldx[i] );
a = DzVec3( m_a[i] );
a.x = a.x * m_fTimeStepSquared;
a.y = a.y * m_fTimeStepSquared;
a.z = a.z * m_fTimeStepSquared;
m_x[i] = x.add( a );
m_oldx[i] = tempx;
}
}
//================================================================================================
//
//================================================================================================
function TimeStep()
{
AccumulateForces();
Verlet();
SatisfyConstraints();
}
//================================================================================================
//
//================================================================================================
function SatisfyConstraints()
{
//there's 9 columns of vertices
//the top of each column if firmly attached to the 'pole'
//the other vertices down that column are allowed to
//swing around, the only constrain being that they keep
//the original separation / distance
//todo : constrain the separation between columns from top to bottom
var col, row, idx, prevPos, thisPos;
for( col = 0; col < numCols; col++ )
{
idx = col;
prevPos = m_x[col];
for( row = 1; row < numRows; row++ )
{
idx += numCols;
thisPos = m_x[idx];
delta = thisPos.subtract( prevPos );
delta.setLength( linklen );
m_x[idx] = prevPos.add( delta );
prevPos = m_x[idx];
}
}
}
//================================================================================================
// in this simulation the only force is gravity
// this is where we could add wind, turbulence, vacuums etc
//================================================================================================
function AccumulateForces()
{
for( var i = 0; i < NUM_PARTICLES; i++ )
{
m_a[i] = m_vGravity;
}
}
//================================================================================================
// position the 81 vertices of the cloth figure
//================================================================================================
function Draw()
{
for( var i = 0; i < NUM_PARTICLES; i++ )
{
poke( i, m_x[i] );
}
}
//================================================================================================
// top row of vertices glued to the 'pole'
// other vertices dangling below
// vertical and horizontal spacing = linklen
//================================================================================================
function initParticles()
{
getPole();
for( var col = 0; col < numCols; col++ )
{
var topPos = m_x[col]
for( var row = 1; row < numRows; row++ )
{
var idx = row * numCols + col;
m_oldx[idx] = m_x[idx] = DzVec3(
topPos.x,
topPos.y - row * linklen,
topPos.z
);
debug( m_x[idx].x + " " + m_x[idx].y + " " + m_x[idx].z );
}
}
}
//================================================================================================
// the position of each vertex of the cloth figure is controlled by 3 morphs ( x, y, z )
// setting a morph to 100% = 1 meter displacement along the corresponding axis
//================================================================================================
function poke( idx, pos )
{
idx *= 3;
clothObj.getModifier( idx++ ).getValueChannel().setValue( pos.x/100 );
clothObj.getModifier( idx++ ).getValueChannel().setValue( pos.y/100 );
clothObj.getModifier( idx++ ).getValueChannel().setValue( pos.z/100 );
}
//================================================================================================
// the first row of vertices of the cloth is glued along the 'pole' spacing is linklen
//================================================================================================
function getPole()
{
var rot = poleNode.getWSRot();
var pos = poleNode.getWSPos();
var vec = rot.getYAxis();
vec.normalize();
for( var i = 0; i < 9; i++ )
{
var len = i * linklen;
m_x[i] = new DzVec3(
pos.x + vec.x * len,
pos.y + vec.y * len,
pos.z + vec.z * len
);
}
}
//================================================================================================
//
//================================================================================================
function main()
{
clothNode = Scene.findNode( "cloth1" );
if( !clothNode )
{
MessageBox.information( "Could not find required cloth figure in the scene", "error", "&OK" );
return;
}
clothObj = clothNode.getObject();
poleNode = Scene.findNodeByLabel( "pole" );
if( !poleNode )
{
MessageBox.information( "Your scene should contain a 1 meter long cylinder named 'pole'", "error", "&OK" );
return;
}
Scene.setFrame( 0 );
initParticles()
Draw();
setBusyCursor();
startProgress( "Processing " + 100 + " frames" , 100, true , true );
for( var i = 1; i <= 100; i++ )
{
processEvents();
updateProgress( i );
if( progressIsCancelled() )
{
clearBusyCursor();
finishProgress();
break;
}
Scene.setFrame( i );
TimeStep();
Draw();
}
clearBusyCursor();
finishProgress();
}
//launch
main();