Physics RK4 001


Over here http://gafferongames.com/game-physics/integration-basics/

someone shows how to implement physics simulations using an RK4 integrator

and here’s my implementation of his c++ source as a Daz Script

1 - create a cylinder, 30cm tall 1 cm diameter
2 - select the cylinder
3 - run the script

the Z rotation angle of the selected cylinder will be driven by the simulated output ( x )

the line that reads “if( (cpt++) > 200 ) break;” is a safety device limiting the simulation to 200 frames

cpt also serves as the keyframe time

you may want to replace

zRot.setValue( cpt * tick, state[0] );

by

zRot.setValue( t * 4800, state[0] );




g_k is the Hooke’s law spring constant, g_b is the dampening factor


     
   //implementation of http://gafferongames.com/game-physics/integration-basics/

var g_k = 10; // spring constant

var g_b = .4; // damping

var onesixth = 1 / 6;




function acceleration( state, t )

{

return( - g_k * state[0] - g_b * state[1] );

}




function evaluateA( initial, t )

{

outputdx = initial[1];

outputdv = acceleration( initial, t );

return( [ outputdx, outputdv ] );

}




function evaluateB( initial, t, dt, d )

{

state = new Array( 2 );

state[0] = initial[0] + d[0] * dt;

state[1] = initial[1] + d[1] * dt;

output = new Array( 2 );

output[0] = state[1];

output[1] = acceleration( state, t + dt );

return( output );

}




function integrate( state, t, dt )

{

a = evaluateA( state, t );

b = evaluateB( state, t, dt * 0.5, a );

c = evaluateB( state, t, dt * 0.5, b );

d = evaluateB( state, t, dt, c );

dxdt = onesixth * ( a[0] + 2.0 * ( b[0] + c[0] ) + d[0] );

dvdt = onesixth * ( a[1] + 2.0 * ( b[1] + c[1] ) + d[1] );

state[0] = state[0] + dxdt * dt;

state[1] = state[1] + dvdt * dt;

}




function main() 

{

zRot = Scene.getPrimarySelection().getZRotControl();

tick = Scene.getTimeStep();

var state = [ 100, 0 ];

var t = 0;

var dt = 0.1;

cpt = 0;

while( Math.abs( state[0] ) > 0.001 || Math.abs( state[1] ) > 0.001 )

{

debug( state[0] + " " + state[1] );

zRot.setValue( cpt * tick, state[0] ); 

integrate( state, t, dt );

t += dt;

if( (cpt++) > 200 )

break;

}

}




main(); 
 
     


and here is HTML5 applet to display the curve and motion


     
 
<html> 
<head> 
<title>RK4 001</title> 
<script type="text/javascript">
var ttt = 0;
var keys = new Array();
var min;
var max;
var prev = 1000000;
function draw( keys, min, max ) 
{
// Get the canvas element.
var elem = document.getElementById( 'myCanvas' );
if( !elem || !elem.getContext ) 
{
return;
}
// Get the canvas 2d context.
var context = elem.getContext( '2d' );
if( !context ) 
{
return;
}
var Width = 1280; //must match dimensions of the canvas
var Height = 360;
var fX = keys.length;
if( fX == 0 ) 
return;
fX = ( Width - 1 ) / ( fX - 1 );
var fY = max - min;
if( fY == 0 ) 
fY = 1;
fY = ( Height - 1 ) / fY;
if( ( min <= 0 ) && ( max >= 0 ) ) // Y = 0 axis
{
context.strokeStyle = "#FF0000";
context.beginPath()
context.moveTo( 0,         ( 0 - min ) * fY );
context.lineTo( Width - 1, ( 0 - min ) * fY );
context.stroke();
context.closePath();
}
// plot
context.strokeStyle = "#0000FF";
context.beginPath()
context.moveTo( 0, ( keys[0] - min ) * fY );
for( var i = 1; i < 200; i++ )
{
context.lineTo( i * fX, ( keys[i] - min ) * fY );
}
context.stroke();
context.closePath();
}

//implementation of http://gafferongames.com/game-physics/integration-basics/
var g_k = 10; // spring constant
var g_b = .4;  // damping
var onesixth = 1 / 6;

function acceleration( state, t )
{
return( - g_k * state[0] - g_b * state[1] );
}

function evaluateA( initial, t )
{
outputdx = initial[1];
outputdv = acceleration( initial, t );
return( [ outputdx, outputdv ] );
}

function evaluateB( initial, t, dt, d )
{
state = new Array( 2 );
state[0] = initial[0] + d[0] * dt;
state[1] = initial[1] + d[1] * dt;
output = new Array( 2 );
output[0] = state[1];
output[1] = acceleration( state, t + dt );
return( output );
}

function integrate( state, t, dt )
{
a = evaluateA( state, t                       );
b = evaluateB( state, t, dt * 0.5, a );
c = evaluateB( state, t, dt * 0.5, b );
d = evaluateB( state, t, dt,       c );
dxdt = onesixth  * ( a[0] + 2.0 * ( b[0] + c[0] ) + d[0] );
dvdt = onesixth  * ( a[1] + 2.0 * ( b[1] + c[1] ) + d[1] );
state[0] = state[0] + dxdt * dt;
state[1] = state[1] + dvdt * dt;
}

function main() 
{
//zRot = Scene.getPrimarySelection().getZRotControl();
//tick = Scene.getTimeStep();
//debug( "tick " + tick )
var state = [ 100, 0 ];
var t = 0;
var dt = 0.1;
cpt = 0;
min = state[0];
max = state[0];
keys.push( state[0] );
while( (cpt++) < 200 )
{
integrate( state, t, dt );
keys.push( state[0] );
if( state[0] < min ) 
min = state[0];
else if( state[0] > max ) 
max = state[0];
t += dt;
}
draw( keys, min, max );
}

function update() 
{
// Get the canvas element.
var canvas = document.getElementById( 'myCanvas2' );
if( !canvas || !canvas.getContext ) 
{
return;
}
// Get the canvas 2d context.
var context = canvas.getContext( '2d' );
if( !context ) 
{
return;
}
var Width =  canvas.width; //must match dimensions of the canvas
var Height = canvas.height;
f = ( Width - 1 ) / ( max - min );
canvas.width = canvas.width; //clear
context.lineWidth = 20;
prev = keys[ttt];
context.strokeStyle = "#00FF00";
context.beginPath()
context.moveTo( f * ( 0    - min ), Height );
context.lineTo( f * ( prev - min ), 10 );
context.stroke();
context.closePath();
++ ttt;
if( ttt > 199 )
ttt = 0;
}

</script> 
</head> 
<body bgcolor=#E0E0FF> 
<p align=center style="width:1280px;border:1px solid #000">
<canvas id="myCanvas" width="1280" height="360">
</canvas>
<canvas id="myCanvas2" width="1280" height="360">
</canvas>
                <script type="text/javascript"> 
main();
var FPS = 30;
setInterval( update, 1000 / FPS );
</script>
</p> 
</body> 
</html> 
 
     





ċ
mcjRK4001.dsa
(1k)
mCasual Jacques,
Sep 29, 2013, 6:00 AM
ċ
mCasual Jacques,
Sep 29, 2013, 12:01 PM
Comments