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;
p.box = false;
p.cross = false;
p.pos.x = x;
p.pos.y = y;
)--[x]

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+(nA*sA)==oB+(nB*sB);
--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
--
--(nB.y*oA.x)+(nB.y*nA.x*sA)==(nB.y*oB.x)+(nB.y*nB.x*sB);
--(nB.x*oA.y)+(nB.x*nA.y*sA)==(nB.x*oB.y)+(nB.x*nB.y*sB);
--[ 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=[0,0,0];
P.x = oA.x+(nA.x*sA);
P.y = oA.y+(nA.y*sA);

)--[FN:pointNormalIntersect]

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

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:


UVWrella
UNFoLD3D
RoadKill
UVlayout


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;
modFound=False;
if(cmID[1]==srchID[1])then(
if(cmID[2]==srchID[2])then(
modFound=True;
)--[x]
)--[x]

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

Tuesday, April 12, 2011

objects,geometry,lights,cameras,helpers,shapes,systems,spacewarps,selection


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:
Example:
For geo in geometry do(
geo.pos = [0,0,0];
)--[x]

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:
if(theObj==Undefined)then(.....)
IS NOT THE COMPLETE SOLUTION.



[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)
)--[x]

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
--34567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
--
--********************************************************************
--********************************************************************
--MORE FREE SCRIPTS AT: http://www.youtube.com/user/PolygonRunner ****
--********************************************************************
--********************************************************************
--
--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");
)else(
print("Callback executed on frame" + currentTime as string);
--**********YOUR CALLBACK CODE HERE***********
--**********YOUR CALLBACK CODE HERE***********
--**********YOUR CALLBACK CODE HERE***********
)--[x]
)--[FN:BindThisFunction]

--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");
)--[END]

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

Saturday, April 2, 2011

Multi-PickButton MaxScript Code



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



-- 1 2 3 4 5 6 7 8 9 10
--34567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
--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?: http://www.youtube.com/user/PolygonRunner ******
-- ***************************************************************************
-- ***************************************************************************

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.

--Control for MULTI-OBJECT PICK BUTTON
on ArrayPick Pressed do(
if selection.count == 0 then(
if(LB01.items.count==0)then(
ArrayPick.Caption = "LIST EMPTY";
)else(
ArrayPick.Caption = "List Unchanged";
)--[x]
)else(
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;
print(MSTAT);
)--[x]

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

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

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

)--[#yes]
)--[MSTAT!=#cancel]
)--[Selection.count]
)--[ArrayPick Pressed]
)--[End Rollout]
CreateDialog MainRollout;
-- 1 2 3 4 5 6 7 8 9 10
--34567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890

Monday, March 28, 2011

MaxScript Rig Exporter for GoTeamGo

The rig exporter I made in maxscript finally got my rig into the game correctly.
What it does:
1. Converts all links to skinning.
2. Puts all geometry pivots at the origin.

...Step2 took me at least 7 hours of work today.
The entire exporter is 387 lines of code long.

The exported rig looks pretty trippy. As because of the math involved, all bones start at [0,0,0] at the beginning of the animation cycle.

Solution: Symmetry Modifier Gizmo Pivot not aligned to Object Pivot

Solution in max when you think you think you fixed the pivot of an object, yet the modifier's gizmo still won't line up correctly:

1. Select Object.
2. Run This Line: ResetXform($)
3. Select Object > Convert To Editable Poly.
4. Now try modifier.

Solution: Align Pivot To Another Object Without Affecting Geometry in MaxScript

This code can be used to Align a pivot of an object to another object or
some other arbitrary matrix without affecting the position of the original geometry.

Potential Usage: programmatically moving pivots before export so your model
will look right in your game engine.


Function ReAssignPivot
inputTransform --New Transform Matrix To Be Pivot
&theObject --The Object to Act on.
--Function Description:
--Gives the object a new pivot, defined by a transform matrix.
--Does so WITHOUT affecting the world position of the original geometry.
--
--**************************************************************
-- More Free Scripts: www.ProofOfProgress.BlogSpot.com ***
--**************************************************************
--
=(
--VLM = Visible Local Matrix.
--The matrix/pivot you see when selecting object and "Local" axis is selected as viewable.
VLM = theObject.Transform;
IP_LocalRot = theObject.objectOffsetRot; --Rotation to be used later.
IP_LOCAL = theObject.objectOffsetPos; --Invisible Pivot Local coordinates
--In relation to VLM matrix.
IP_WORLD = IP_LOCAL * VLM; --World Coordinates of Invisible Pivot. [Local To World Transform]
VLM_0 = inputTransform; --Reset Visible Local matrix coordinates.

NEW_IP_LOCAL = IP_WORLD * inverse(VLM_0); --[World To local Transform]

theObject.Transform = VLM_0;
theObject.objectOffsetPos = NEW_IP_LOCAL;

--Now Handle Rotation:
--Since rotation of visible local matrix has been zeroed out,
--You must add that loss to the invisible pivot rotation.

RotationLoss = VLM.RotationPart - VLM_0.RotationPart;
GeomWorldRot = RotationLoss + IP_LocalRot;
theObject.objectOffsetRot = GeomWorldRot;

)--[FN:ReAssignPivot]

--Test Code;
--This test code will align SomeCircle's pivot to PivotObject's Pivot.
inputTransform = $PivotObject.Transform;
affectedObject = $SomeCircle;
ReAssignPivot inputTransform &OBJ;

Solution: Align Pivot To World Without Affecting Geometry in Maxscript


This script moves the pivot of an object to the world and aligns it without
affecting the original location of the object geometry.

Some things I learned about max's internals from doing this:
1. theObject.objectOffsetPos is the LOCAL coordinates of the objects
"Invisible" axis. Plug those Local coordinates into the objects
transform matrix to get the WORLD coordinates of the objects
"Invisible" axis.

Example:
LocalCoords = theObject.objectOffsetPos;
TheMatrix = theObject.Transform;
WorldSpaceCoords = LocalCoords * TheMatrix;

2. The Objects VISIBLE pivot is a Matrix.
The Objects INVISIBLE pivot is a quaternion and point3 position.

This is self-Evident when you mess around.


Function alignPivotToWorld
&theObject
--Aligns the pivot to the world WITHOUT affecting the geometry.
--
--*****************************************************
--More Scripts at: www.ProofOfProgress.BlogSpot.com **
--*****************************************************
--
=(
--VLM = Visible Local Matrix.
--The matrix/pivot you see when selecting object and "Local" axis is selected as viewable.
VLM = theObject.Transform;
IP_LocalRot = theObject.objectOffsetRot; --Rotation to be used later.
IP_LOCAL = theObject.objectOffsetPos; --Invisible Pivot Local coordinates
--In relation to VLM matrix.
IP_WORLD = IP_LOCAL * VLM; --World Coordinates of Invisible Pivot. [Local To World Transform]
VLM_0 = matrix3 1; --Reset Visible Local matrix coordinates.

NEW_IP_LOCAL = IP_WORLD * inverse(VLM_0); --[World To local Transform]

theObject.Transform = VLM_0;
theObject.objectOffsetPos = NEW_IP_LOCAL;

--Now Handle Rotation:
--Since rotation of visible local matrix has been zeroed out,
--You must add that loss to the invisible pivot rotation.
GeomWorldRot = VLM.RotationPart + IP_LocalRot;
theObject.objectOffsetRot = GeomWorldRot;

)--[FN:alignPivotToWorld]

--Test Code;
OBJ = $;
thePos = [0,0,0];
alignPivotToWorld &OBJ;


I don't have the time, but if anyone would like to edit this
So that the pivot can be adjusted to be put ANYWHERE rather than aligned to the
World, let me know. I will re-post it and credit will be given.

Sunday, March 27, 2011

Solution To: Bone Animation Fails to Export in 3DSmax

Scenario:
1. You have a bone linked to a dummy.
2. You animate the dummy.
3. You export the bone animation.

Problem:
The bone animation does not seem to be in your FBX file when you test it
in your engine.

Why:
Linking moves the bone, but does not change the position controller value.

Solution:
This script to switch out your regular linking with this controller.



Function ConvertLinkedChildrenToPuppets
LOBA --Linked [Child] Objects array.
--Array of objects to have their link
--Constraint converted to script controller.
SGEO --Script Controller geometry object.
--The geometry object that will house the
--SINGLE script controller responsible for
--Controlling the position of all LOBA objects.
--
--*****************************************************
--More Scripts at: www.ProofOfProgress.BlogSpot.com **
--*****************************************************
--
=(

SCON = Scale_Script(); --Create Empty Scale Script.

--Go through geometry objects and add them to lists of exposed nodes.
--Also, add constants to the script controller that are matrices
--Of the original offset position between parent and child.
for g = 1 to LOBA.count do(
gstring = g as string;

--Add Constant
matrixName = "offsetMatrix" + gstring;
parentMatrix = LOBA[g].Parent.Transform;
childMatrix = LOBA[g].Transform;
offsetMatrix = childMatrix*Inverse(parentMatrix);
matrixValue = offsetMatrix;
SCON.AddConstant matrixName matrixValue

--Add Parent
NodeName = "ParentNo" + gstring;
theNodeObj = LOBA[g].Parent;
SCON.AddNode NodeName theNodeObj;

--Add Child
NodeName = "ChildNo" + gstring;
theNodeObj = LOBA[g];
SCON.AddNode NodeName theNodeObj;

--Un-Parent the arrangement:
LOBA[g].Parent = Undefined;
)--[Next g]


--Must add controller LAST or script code will be erased.
SGEO.Scale.Controller = SCON; --Add script controller to object.

--Create The Script:
script_code = "";
for g = 1 to LOBA.count do(
gg = g as string;
--cs = "childNo" + gg + ".Transform = offsetMatrix" + gg + "*ParentNo" + gg +".Transform;" + "\n";
cs = "childNo" + gg + ".Transform = offsetMatrix" + gg + "*ParentNo" + gg +".Transform;" + "\n";
script_code = script_code +cs;
)--[x]
script_code = script_code + "[1,1,1]" + "\n";
SCON.Script = script_code;

)--[FN:ConvertLinkedChildrenToPuppets]

LOBA = #();
LOBA[1] = $Circle01;
LOBA[2] = $Circle02;
LOBA[3] = $Circle03;
LOBA[4] = $Circle04;

SGEO = $SGEO;

ConvertLinkedChildrenToPuppets LOBA SGEO;

Link By Hand / Code in MaxScript

--The math behind linking AAA to BBB.
--If AAA and BBB are objects in 3DSmax.
offsetMatrix = $AAA.Transform*Inverse($BBB.Transform);
$AAA.Transform = offsetMatrix*$BBB.Transform;


--To Unlink The Original Parenting:
$.Parent = Undefined;

Dynamically Created Rollout For Storing Matrices in Maxscript

I just found out I don't need to do this because I can place
matrices as constants within script controllers.
Doing that dynamically would be better than doing this.
But here it is anyways.


Function StoreMatrices
MatrixArray --An array of matrices to go into the "MatrixHolder" custom attribute.
HoldingObject --The object the custom attribute will be attached to.
--
--*****************************************************
--More Scripts at: www.ProofOfProgress.BlogSpot.com **
--*****************************************************
--
--Function Summary:
--Dynamically creates a custom attribute with MatrixArray.Count number of Matrices.
--Can then be accessed by: TheObject.BaseObject.MatrixHolder.Matrix5
=(
--MUST use global or execute function will not create attribute correctly.
global MatrixHolderDEF_586_214_3958;

DQ = "\""; --Double quote character.

--Header Assemble:
H01 = "MatrixHolderDEF_586_214_3958 = attributes MatrixHolder(" + "\n";
H02 = "parameters main rollout:ro_howMany(" + "\n";
H_X = H01 + H02;

--Body Code Assemble:
matrixMAXstring = MatrixArray.Count as string;
varList = "";
For i = 1 to MatrixArray.count do(
mn = i as string; --Matrix Number.
coreCode = "Matrix" + mn + " type:#matrix3;" + "\n";
varList = varList + coreCode;
)--Next i

--Footer Assemble:
F01 = ")--[params]" + "\n";
F02 = "rollout ro_howMany "+DQ+"MatrixHolder"+DQ+" (" + "\n";
F03 = "label lab1 "+DQ+"MatrixCount=="+matrixMaxString+DQ+ "\n";
F04 =")--[x]" + "\n";
F05 =")--[End Custom Attribute Def]" + "\n";
F_X = F01+F02+F03+F04+F05;

--Assemble and Execute Definition:
exe_def = H_X+varList+F_X;
Execute(exe_def);

--Add the Compiled Definition to the Object:
custAttributes.add HoldingObject MatrixHolderDEF_586_214_3958 Unique:True BaseObject:True; --*******************<<<<

--Now that your custom attribute is created with the correct number of matrix slots,
--Fill the values in.
--global global_m;

global global_HoldingObj;
global global_MatrixArray;
For m = 1 to MatrixArray.count do(
gm = m as string;
global_HoldingObj = HoldingObject.BaseObject.MatrixHolder;
global_MatrixArray = MatrixArray;
--eCode = "HoldingObject.BaseObject.MatrixHolder.Matrix" + gm +"= MatrixArray["+gm+"];"
eCode = "global_HoldingObj.Matrix" + gm + "=global_MatrixArray["+gm+"];";
Execute(eCode);
)--[next m]


--Edit: Put the adding custom attribute code into the actual EXE-string.
--The EXE-string is executing on a different thread than the rest of the code.
--So if you tried "custAttributes.add HoldingObject MatrixHolderDEF Unique:True BaseObject:True"
--After using the EXE string, it would not work. Even SLEEP would not fix the problem.

--UPDATE: It appears to be executing on a different thread..
--But it is actually a scope issue that can be fixed by using a GLOBAL.
--Look at: "Why does Execute return 'undefined' when accessing a loop variable?"
--In maxscript help for more information.

)--[FN:StoreMatrices]


--Example Code:
MatrixArray = #();
TheObject = $;
MatrixArray[1] = Matrix3 [1,1,1] [1,1,1] [1,1,1] [1,1,1];
MatrixArray[2] = Matrix3 [2,2,2] [2,2,2] [2,2,2] [2,2,2];
MatrixArray[3] = Matrix3 [3,3,3] [3,3,3] [3,3,3] [3,3,3];
MatrixArray[4] = Matrix3 [4,4,4] [4,4,4] [4,4,4] [4,4,4];
MatrixArray[5] = Matrix3 [5,5,5] [5,5,5] [5,5,5] [5,5,5];

--Test Code:
theOBJ = $;
StoreMatrices MatrixArray theOBJ;

--Test to see if one of the matrices exist.
theOBJ.BaseObject.MatrixHolder.Matrix5

Saturday, March 26, 2011

Align Tool Does not Work in 3dsMax

Step1: Aligned one object's pivot to another object.
Step2: Orientation constrain them together.
Step3: Wonder why they popped out of place anyways.

Honestly, I am not sure why the align tool does not always properly align objects.
But a quick solution:

--Align Object 1 to object 2, Rotation ONLY.
Pos01 = $Object01.pos;
$Object01.Transform = $Object02.Transform;
$Object01.pos = Pos01;

Friday, March 25, 2011

Animation Export Solution Found

BACK STORY: -------------------------------
If you link say... A bone to a circle..
And then animate that circle...
And then bake out the keyframes of the BONE... You will NOT get any animation
to show up in the engine when you export the mesh and the bone.

Why? Because when an object is linked in 3DSmax, the controller values never change.

Try this:
Put a bone at [0,0,0] and then link it to something. Animate that something.
Then select the bone and execute the script:

$.pos.controller.value;

At different intervals along the timeline.

You will get the same value of [0,0,0] no matter where the bone is.

Solution:_________________________________
Put a script controller in a dummy object that controls ALL the linking constraints
for all the objects you want to export. The animation will now export properly.

Currently working on a script that will replace all linked child object's controllers
with a script controller.

I am calling it "ConvertLinkedChildrenToPuppets".

I already did a quick "by hand" test of my solution, so I know it works.
Time to start coding.

Tuesday, March 22, 2011

MaxScript Snippet: BitArray To Array


theBITS = #{2..5,7}
theARRAY = theBITS as array;

for i = 1 to theARRAY.count do(
ist = i as string;
print("[" + ist + "]==" + theARRAY[i] as string);
)--[x]

Number Of Texture Verticies in MaxScript UVW unwrap

Getting Number of Texture Vertices:

This:
UVertCount = GEOM.modifiers[#unwrap_uvw].NumberVertices()

NOT This:
MapCN = GEOM.modifiers[#unwrap_uvw].unwrap.getMapChannel();
UVertCount = polyop.getNumMapFaces GEOM MapCN;

Image Tube Source Code

Used to Automatically unwrap UVWS of segments of box or plane in order to make
a scrolling marque from a video of a scrolling marquee.
This is done by assigning each segment of the plane a different time offset of the video. We then then make a 3d scrolling marquee of any shape we desire from this setup created by the script.

Current Location of script on my system:
E:\TECH_ROOT\MaxScript\MyScripts\In_Developement\Image_Tube\Image_Tube_V5.ms





Blog Archive