Search ProofOfProgress Blog

Wednesday, April 27, 2011

Capsule Line Collision Source Code

Download Source: ****HERE****
Here is a demo of some capsule-line collision I whipped up.
One thing I am proud of is I made a formula that finds the intersection of
a circle using the function graph of a circle.

Basically, if you take a ray and want to know where that ray intersects the circle:

The ray pointing towards the circle:
rP = ray point.
rV = ray vector.

The circle:
CP = center point of circle.
cr = radius of circle.

[1]: Take negative receprocal of rV to get perpendicular vector pV.
[2]: combine pV with CP to get a perpendicular at center of circle.
[3]: set rays [rP rV] and [CP pV] equal to each other and find
intersection using point-normal form.
Call this intersection RC
[4]: Find distance: intersection to circle center. Call this distance DS.
[5]: Divide DS by the cr to get a value from 0 to 1.
[6]: Input this 0to1 value into the function graph of a circle:
[7]: Take the y-height output and scale it up by the radius (cr) of the circle.
Call this value SKA.
[8]: Flip the sign of normalized rV. Translate it to the intersection point RC.
[9]: Intersection on circle = RC+(SKA*normalized_rV);

Tuesday, April 26, 2011

Graph of a circle as a function of X.

--Graph of a circle as a function of X.
for xIN = -100 to 100 do(
x = (xIN as float)/100.0; --x = 0 to 1.
r = 1; --radius of 1.
y = (1-(x*x))^(.5)

p = point();
p.centerMarker = true; = false;
p.cross = false;
p.pos.x = x;
p.pos.y = y;

Monday, April 25, 2011

line circle collision 2D source code

Download Source: ****HERE****

When your ball has NO VELOCITY, or you are doing a simple bouncing ball script without capsule collision, then this is the script for you. It will take the intersecting ball and line and PUSH, the ball away from the line until there is one point between the ball and line touching. This is the collision point.

Written In Maxscript. Will be re-writing a version for actionscript.

Capsule Point Intersection

Download Source: ****HERE****

Saturday, April 23, 2011

2D rectangular capsule collision function

Download Source: ****HERE****

Intersection of two vectors using point normal form

I am pretty proud of this. Here is the intersection point of 2 vectors (2D).
It would be pretty easy to convert this to 3D, which I am going to do next.
But I originally needed it for 2D intersections in actionscript.

[EDIT: Lines rarely intersect in 3D. Formula does not translate.]
[I feel kinda stupid now.]

Yes... MaxScripting code to prototype actionScript code.
This being because it is very easy to visually debug geometric formulas
in 3dsmax. So its actually quicker for me to write maxscript and actionscript
than just actionscript.

Here is the formula, as a maxscript function:

function pointNormalIntersect2D
oA --Origin A
oB --Origin B
vA --Vector #1.
vB --Vector #2.
&P --position output

nA = normalize(vA);
nB = normalize(vB);

--oA --origin A
--nA --normal A
--sA --scalar A
--oB --origin B
--nB --normal B
--sB --scalar B
--oA.x+(nA.x*sA)==oB.x+(nB.x*sB); //MULTIPLY BY nB.y
--oA.y+(nA.y*sA)==oB.y+(nB.y*sB); //MULTIPLY BY nB.x
--[ c1 ] [ c2 ] [ c3 ] [ c4 ]
--MINUS THEM: c4 cancels out.
c1 = (nB.y*oA.x)- (nB.x*oA.y);
--c2 = (nB.y*nA.x*sA)-(nB.x*nA.y*sA);
c3 = (nB.y*oB.x)- (nB.x*oB.y);

--New Equation is:
--c2 = c3 - c1;
c3c1 = c3 - c1; --c3 minus c1;

--Figure out how many sA's you have by combining like terms;
sAcount = (nB.y*nA.x)-(nB.x*nA.y);

--New Equation is:
--sAcount*sA = c3c1;

--calculate sA:
sA = c3c1/sAcount;

--once scalar sA is found, plug it into point normal form to find intersection.
P.x = oA.x+(nA.x*sA);
P.y = oA.y+(nA.y*sA);


oA = $v1A.pos;
oB = $v2A.pos;
vA = $v1A.pos - $v1B.pos;
vB = $v2A.pos - $v2B.pos;
P = [0,0,0];
pointNormalIntersect2D oA oB vA vB &P;
$intPos.pos = P;

Thursday, April 21, 2011

Piston Platform TurnAround

Wednesday, April 20, 2011

Tuesday, April 19, 2011

Get Verts Used By Face: Max Script

--*** NOTE: $Box37 is reference to object named "Box37" in scene. ***

--Using Bit Array:
verts1 = polyop.getVertsUsingFace $Box37 #{1,2}
print("verts1 == " + verts1 as string);

--Using array converted to BitArray:
oneTwo = #(1,2);
Bwaaar = oneTwo as BitArray;
verts2 = polyop.getVertsUsingFace $Box37 Bwaaar;
print("verts2 == " + verts2 as string);

Sunday, April 17, 2011

List of UVW unwrap programs:


Interesting Observation:
All programs have... 8 characters.

Saturday, April 16, 2011

ClickDraggable Class ActionScript

Download Source: ****HERE****
My current maxscript project is taking a while to develop.
And I want to have something tangible to show for my efforts every day.
Thus, here is a clickDraggable class I made in flash today:

Thursday, April 14, 2011

Wednesday, April 13, 2011

Find index of modifier in stack via classID in Maxscript

Suppose you are looking for a skin modifier
in the selected object (myObject).
BUT... The skin modifier has been renamed to "JMIMS_SKIN".
Here is how you would find the skin modifier, even though it is
no longer named "Skin" in the stack.

myObject = $;
srchID=Skin.ClassID; --Search for skin modifier in MyObject.

For m = 1 to myObject.modifiers.count do(
cmID = myObject.modifiers[m].ClassID;

Print("Your Modifier is index#" + m as string);
print(cmID as string + "!=" + Skin.ClassID as string);
)--[Next m]

Tuesday, April 12, 2011


Iterate through objects in scene with these object sets:
[1] objects -- all the objects
[2] geometry -- the standard 3ds Max categories...
[3] lights
[4] cameras
[5] helpers
[6] shapes
[7] systems
[8] spacewarps
[9] selection -- the current selection

Use these to iterate through all of one type of object in maxscript:
For geo in geometry do(
geo.pos = [0,0,0];

M15: Rig Update Via Forcing Script Controllers To Re-Evaluate

A proof of concept for storing arrays in script controllers via string manipulation.

[Source Code Below] Download Source: ****HERE****

L01:Global Pitfalls In MaxScript

Download Source Files to Follow along with lecture:

Summary of video coverage:
[1]: Globals in MacroScripts are not quite what they seem.

[2]: GlobalVars.Remove is potentially hazardous.

[3]: Checking to see if an object exists by using:

[Source Files Below] Download Source: ****HERE****

Saturday, April 9, 2011

PG14 SpeedBoxy For The Weekend

A proof of concept for storing arrays in script controllers via string manipulation.

[Source Code Below] Download Source: ****HERE****

Perpendicular Surface Constraint in Max Script

[Source Code Below] Download Source: ****HERE****

Thursday, April 7, 2011

Stacking Piston Maker Tool for Max Script

[Source Code Below] Download Source: ****HERE****

Determine if two vectors are parallel in Max Script

I am posting this here so I never have to look up how to do this.
The simple compact answer to determining if two vectors are parallel.
In Max Script.

First Example: Using Dot Product.

V1 = [1,1,1]; ----------Vector #1
V2 = [-1,-1,-1]; -------Vector #2
nV1 = normalize(V1); ----Normalized Vector #1.
nV2 = normalize(V2); ----Normalized Vector #2.
dir = dot nV1 nV2; ------Dot product of normalized vectors.
print("dot ==" + dir as string);

--Negative 1 = Anti-Parallel.
--ZERO = Perpendicular/Orthagonal
--Positive 1 = Parallel.

--Does anyone know if there is a word for "Non-Integer" besides "Float"?

Another way:
This uses Cross Product to determine if two vectors are parallel.

V1 = [1,2,3]; ----------Vector #1
V2 = [-1,-2,-3]; -------Vector #2
dir = cross V1 V2 -------Cross of both.
print("cross==" + dir as string);

--If cross==[0,0,0] then you have
--parallel or anti-parallel vectors
--or one or more vectors has a length of zero
--Only vector with length of zero: [0,0,0];

Retractable Piston Maker

[Source Code Below] Download Source: ****HERE****

Wednesday, April 6, 2011

Align Object Axis to line and control twist with upnode

Say we want to align the Z-axis of an object GEOM
to a line between objects cp1 and cp2.

Step1: Create a normalized vector:
P01 = cp1.pos; --Original Start Point.
P02 = cp2.pos; --Original End Point.
PVEC = P02-P01; --Point from start point to end point.
PLEN = length(PVEC); --Length of vector.
NPV = PVEC / PLEN; --Normalized PVEC

Step2: Lets say that the orientation of cp1 is also going to be used for
twist control. Specifically that, the twist of the objects aligned to the
line will be controlled by the X-Axis of cp1.

--The initial X-Axis may not be perpendicular to the line cp1-cp2.
--Take the cross between the bent X and the Z-Axis (NPV) to get Yaxis.
bentX = (Normalize cp1.transform.row1);
Yaxis = Normalize(cross NPV bentX);

--Use the good Y-axis and Z-Axis (NPV) to get a perpendicular Xaxis.
Xaxis = Normalize(cross NPV Yaxis);
GEOM.Transform = Matrix3 Xaxis Yaxis NPV P01 --Objects new transform.
-- x y z position

Take it Further:
To take this further, you could slide the object up and down the line
by using point-normal form.

Example: Put aligned object in MIDDLE of the line:
midPosition = cp1 + NPV*(PLEN/2)

Example: slide aligned object from start of line to end of line:
for i = 0 to 1 do( --0 to 1 as in Zero to 100%.
istr = i as string;
midPosition = cp1 + NPV*(PLEN*istr)

Tuesday, April 5, 2011

Push Constraint Demo

[Source Code Below] Download Source: ****HERE****

Sunday, April 3, 2011

AutoLoad CallBacks On File Open in MaxScript

[Source Code Below] Download Source: ****HERE****

-- 1 2 3 4 5 6 7 8 9 10
--What it does:
--[1]: Registers callback when you open the file and move the time slider.
--[2]: UnRegisters when you open a different max file.
--How to use:
--[1]: Put code into a script controller of a dummy object.
--[2]: Make sure last line of script controller is:
-- : [0,0,0], or other valid point3 if position script.
-- : quat 0 0 0 1, or other quaternion if rotation script.
-- : ect...
--[3]: If you want, you can also edit this code to handle
-- "when constructs" and "change handlers".
--My personal application:
--[1]: Use to force update script controllers that are not
-- Executing in the correct order.
Global MFP_586_214_3958; --MFP = "Max File Path";
Global BFN_586_214_3958; --BFN = "Bound Function";
if (MFP_586_214_3958 != maxFilePath)then(
MFP_586_214_3958 = maxFilePath;
Function BindThisFunction
--Need code to un-register itself when the maxFilePath changes.
if(MFP_586_214_3958 != maxFilePath)then(
--Must remove globals so that will re-register
--If you re-open this file or another file with this
--script in it.
unRegisterRedrawViewsCallback BFN_586_214_3958;
MFP_586_214_3958 = undefined;
globalVars.remove "MFP_586_214_3958";
globalVars.remove "BFN_586_214_3958";
print("Unregistering Callback");
print("Callback executed on frame" + currentTime as string);
--**********YOUR CALLBACK CODE HERE***********
--**********YOUR CALLBACK CODE HERE***********
--**********YOUR CALLBACK CODE HERE***********

--Bind function to global variable, else the function will
--Not be capable of unRegistering itself.
BFN_586_214_3958 = BindThisFunction;

--Register the function as a callback.
registerRedrawViewsCallback BFN_586_214_3958;
print("CallBack has been registered");

-- 1 2 3 4 5 6 7 8 9 10

Saturday, April 2, 2011

Multi-PickButton MaxScript Code

[Source Code Below] Download Source: ****HERE****

-- 1 2 3 4 5 6 7 8 9 10
--This code will demo how to use my multi-pick-button.
--Works like normal pick button, but allows you to select multiple objects.
-- ***************************************************************************
-- ***************************************************************************
-- Want more free scripts?: ******
-- ***************************************************************************
-- ***************************************************************************

rollout MainRollout "Multi-PickButton Demo"(
local RV_ArrayNodes = #(); --Array of nodes selected by button ArrayPick

button ArrayPick "Select Objects, THEN click me.";

--The list box displays what you currently have selected by the ArrayPick button.
listbox LB01 "Influencing Objs"
height:5; --5 lines tall.
ReadOnly:True; --Read Only List.

on ArrayPick Pressed do(
if selection.count == 0 then(
ArrayPick.Caption = "LIST EMPTY";
ArrayPick.Caption = "List Unchanged";
MSTAT = #no; --Do not append;
if (LB01.items.count > 0)then(
mstatText = "";
mstatText = mstatText + "[YES]: Append to previous selection." + "\n";
mstatText = mstatText + "[NO]: Replace old selection." + "\n";
mstatText = mstatText + "[CANCEL]: Don't do anything." + "\n";
MSTAT = yesNoCancelBox mstatText \
title:"Append or Replace?" beep:False;

if (MSTAT!=#cancel)then(
nodeNameArray = #();

--If #no: Create New Selection.
RV_ArrayNodes = #();
for i = 1 to selection.count do(
nodeNameArray[i] = selection[i].name;
RV_ArrayNodes[i] = selection[i];
ArrayPick.Caption = "List Populated";
LB01.items = nodeNameArray;
print("Rv array nodes===" + RV_ArrayNodes as string);

--If #yes: Append to Original selection.
nodeNameArray = LB01.items;
for i = 1 to selection.count do(
APN = appendIfUnique RV_ArrayNodes selection[i];
if(APN)then(append nodeNameArray selection[i].name);
ArrayPick.Caption = "List Appended To";
LB01.items = nodeNameArray;
print("Rv array nodes===" + RV_ArrayNodes as string);

)--[ArrayPick Pressed]
)--[End Rollout]
CreateDialog MainRollout;
-- 1 2 3 4 5 6 7 8 9 10