PDA

View Full Version : Scripted SimpleObject Plug-ins - (moving inside it)


fferro2
12-31-2007, 03:22 PM
From the maxscript reference:

Creating Maxscript Tools > Scripted Plug-ins > Scripted SimpleObject Plug-ins > Script:

plugin simpleObject squareTube
name:"SquareTube"
classID:#(63445,55332)
category:"Scripted Primitives" (
local box1, box2
parameters main rollout:params (
length type:#worldUnits ui:length default:1E-3
width type:#worldUnits ui:width default:1E-3
height type:#worldUnits ui:height default:1E-3
)

rollout params "SquareTube" (
spinner height "Height" type:#worldUnits range:[1E-3,1E9,1E-3]
spinner width "Width" type:#worldUnits range:[1E-3,1E9,1E-3]
spinner length "Length" type:#worldUnits range:[-1E9,1E9,1E-3]
)

on buildMesh do (
if box1 == undefined then
(box1 = createInstance box; box2 = createInstance box)
box1.height = height; box2.height = height
box1.width = width; box2.width = width * 2
box1.length = length; box2.length = length * 2
mesh = box2.mesh - box1.mesh
)

tool create (
on mousePoint click do
case click of (
1: nodeTM.translation = gridPoint
3: #stop
)

on mouseMove click do
case click of (
2: (width = abs gridDist.x; length = abs gridDist.y)
3: height = gridDist.z
)
)
)


Is it possible to move box2 over box1 to perform a union instead of a substract boolean operation?

thanks

Bobo
12-31-2007, 04:04 PM
Is is possible to move box2 over box1 to perform a union instead of a substract boolean operation?


Yes, with a bit of creativity :)
All instances you create will have their mesh in object space. The local origin of all objects (the center of a sphere, the bottom center of the box or cylinder etc.) will be coincident.

You can write a short function where you pass the TriMesh and transform all its vertices as desired, then return the changed mesh and perform the union or other boolean operation with it. The universal form of such function could be given a whole transformation matrix, so you could perform scaling, rotation and translation of the mesh in any combination.

Try to write it and if you have any problems, post here...

fferro2
12-31-2007, 06:21 PM
So, after moving all the vertices with :
fn moveMesh theMesh = (
box3 = editable_mesh()
box3.mesh = theMesh.mesh
move box3.verts [0,0, this.box1.height]
update box3
?????
)
How could I update the original box2 trimesh?

Thanks

Bobo
12-31-2007, 08:32 PM
So, after moving all the vertices with :
fn moveMesh theMesh = (
box3 = editable_mesh()
box3.mesh = theMesh.mesh
move box3.verts [0,0, this.box1.height]
update box3
?????
)
How could I update the original box2 trimesh?

Thanks


Uhm, no. You don't want an actual object created in the scene, the idea is to transform each vertex separately in memory.

fn transformMesh theTriMesh theMatrix =
(
for v = 1 to theTriMesh.numverts do
setVert theTriMesh v ((getVert theTriMesh v)*theMatrix)
theTriMesh
)

Now if you want to move a mesh 12.34 units along Z, pass the .mesh of your box to the function together with a matrix that looks like

matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,12.34]

To scale, use a ScaleMatrix constructor or pass a matrix like

matrix3 [2,0,0] [0,3,0] [0,0,4] [0,0,0]

which will scale X 2 times, Y 3 times and Z 4 times, while not moving anything.
You can use a constructor like rotateZmatrix 90.0 to create a rotation matrix which will move all vertices so that the mesh will be turned 90 degrees around Z, and so on...

Note that you don't pass the BOX instance, but the .mesh property of the box as the parameter, and then receive a TriMesh value back which you can use in the boolean operation.

Hope this helps.

fferro2
01-01-2008, 01:53 PM
Hi Bobo, thanks!

What do you say about this solution? (It works)
Creates a cylinder over a box.


on buildMesh do (
if box1 == undefined then (box1 = createInstance box; cyl1= createInstance cylinder)
box1.height = cyl1.height = height
box1.width = box1.length = width
cyl1.radius = width / 2
cyl2 = cyl1.mesh
for v = 1 to getNumVerts cyl2 do ( --loop through all vertices
vert = getVert cyl2 v --get the v-th vertex
vert.z += this.height --change the Z coordinate to this.height
setVert cyl2 v vert --assign back to the v-th vertex
)
update cyl2
mesh = box1.mesh + cyl2.mesh
)



I couldn't manipulate the cyl1 vertices. So, I had to copy it as a .mesh.
Is it efficient to move the vertices inside the buildMesh handler? (no function created)

Happy new year!

Bobo
01-01-2008, 03:20 PM
Hi Bobo, thanks!

What do you say about this solution? (It works)
Creates a cylinder over a box.


on buildMesh do (
if box1 == undefined then (box1 = createInstance box; cyl1= createInstance cylinder)
box1.height = cyl1.height = height
box1.width = box1.length = width
cyl1.radius = width / 2
cyl2 = cyl1.mesh
for v = 1 to getNumVerts cyl2 do ( --loop through all vertices
vert = getVert cyl2 v --get the v-th vertex
vert.z += this.height --change the Z coordinate to this.height
setVert cyl2 v vert --assign back to the v-th vertex
)
update cyl2
mesh = box1.mesh + cyl2.mesh
)



I couldn't manipulate the cyl1 vertices. So, I had to copy it as a .mesh.
Is it efficient to move the vertices inside the buildMesh handler? (no function created)

Happy new year!

Happy New Year!

Yes, it is ok, and if fact faster to manipulate the vertices of the TriMesh inline instead of with a function. The good thing about the function was that it was universal for moving, scaling and rotating, so you could do lots of transformations without explicit code.

One thing to remember though - each time you store the .mesh property of an object in a variable, you are LEAKING MEMORY! The local variable should be garbage collected, but since it points at a TriMesh value, it might be skipped and after a while, lots of memory could be consumed by TriMesh values. It is a good idea to add the line

delete cyl2

at the end of the buildMesh handler - this will release the memory used by the TriMesh of the cylinder you manipulated and the garbage collection will be able to reclaim it.

fferro2
01-01-2008, 07:18 PM
Thank again for the advice Bobo,

I cannot set different MatIDs to each primitive inside the scripted plugin, right?

So. How could I “remember” each element in the final mesh?

I need the Boolean operation to delete some faces, but at the end I need each one as different elements in the object.

May be "Volume selecting" each one before the boolean?

Best,

Bobo
01-01-2008, 07:26 PM
Thank again for the advice Bobo,

I cannot set different MatIDs to each primitive inside the scripted plugin, right?

So. How could I “remember” each element in the final mesh?

I need the Boolean operation to delete some faces, but at the end I need each one as different elements in the object.

May be "Volume selecting" each one before the boolean?

Best,

You have to change your mindset when building meshes in the plugin. You are creating a mesh out of meshes. You don't have scene objects to operate on, only IN MEMORY. CreateInstance() does not make scene objects, it creates in-memory instances of base objects that are not in the scene.
Thus, you can call methods that manipulate TriMeshes, their faces and vertices, but you cannot add modifiers or modify at node level (because there is no node).
Of course, in order to set the MatID of the separate meshes, all you have to do is loop through their faces and set the Material IDs of each face to the desired value.
From top of my head, something like:
for f = 1 to theMesh01.numfaces do setFaceMatID theMesh01 f 1
for f = 1 to theMesh02.numfaces do setFaceMatID theMesh02 f 2

focomoso
01-02-2008, 02:18 AM
fn transformMesh theTriMesh theMatrix =
(
for v = 1 to theTriMesh.numverts do
setVert theTriMesh v ((getVert theTriMesh v)*theMatrix)
theTriMesh
)
By the way, big thanks for that. I just used it in an ellipsoid plugin. So simple and yet, I probably would have written mountains of code before I whittled it back down.

fferro2
01-02-2008, 03:17 PM
Thanks again,

This code will create columns for architecture projects:



plugin simpleObject Column
name:"Column"
classID:#(63446,55333)
category:"3DEmpire" (
local cyl1, cyl2, cyl3, box1, tempMesh1, tempMesh2

fn transformMesh theTriMesh theMatrix = (
for v = 1 to theTriMesh.numverts do
setVert theTriMesh v ((getVert theTriMesh v)*theMatrix)
theTriMesh
)

fn createMesh theMesh = (
if cyl1 == undefined then (
cyl1 = createInstance cylinder -- zócalo
cyl2 = createInstance cylinder heightsegs:1 sides:18 smooth:true realWorldMapSize:on -- columna
box1 = createInstance box lengthsegs:3 widthsegs:3 height:0.0 -- remate
)
cyl1.height = this.zocHeight ; cyl2.height = this.height - this.zocHeight
cyl2.radius = this.radius
cyl1.radius = this.radius + this.zocWidth
box1.width = box1.length = this.radius * 2 * 1.1

-- eleva los vértices del cilindro hasta arriba del zócalo
tempMesh1 = transformMesh cyl2.mesh (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,this.zocHeight])

-- eleva los vértices de la tapa hasta arriba del cilindro
tempMesh2 = transformMesh box1.mesh (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,this.height])

-- suma las partes del mesh

theMesh = tempMesh1.mesh + cyl1.mesh + tempMesh2.mesh
-- elimina meshes temporales (para reducir consumo de memoria)

delete tempMesh1
delete tempMesh2
theMesh
)



parameters main rollout:params (
-- width type:#worldUnits ui:width default:1E-3
radius type:#worldUnits ui:radius default:0.3
height type:#worldUnits ui:height default:2.4
zocHeight type:#float ui:zocHeight default: 0.1
zocWidth type:#float ui:zocWidth default: 0.2
)

rollout params "Column" (
group "Dimensions" (
spinner radius "radius" type:#worldUnits range:[0.0,1E9,1E-3]
spinner height "height" type:#worldUnits range:[0.0,1E9,1E-3]
)

group "Zocalo" (
spinner zocHeight "height" type:#float range:[0.0,1E9,1E-3]
spinner zocWidth "width" type:#float range:[0.0,1E9,1E-3]
)

group "Parameters" (
checkbutton radiosidad "Radiosidad" checked:false tooltip:"Densidad de la malla"
)
)



on buildMesh do (
mesh = createMesh mesh
)



tool create (
on mousePoint click do
case click of (
1: nodeTM.translation = gridPoint
5: #stop
)



on mouseMove click do
case click of (
2: radius = abs gridDist.x; --length = abs gridDist.y)
3: height = abs gridDist.z
4: zocHeight = if (abs gridDist.z < height) then abs gridDist.z else height
5: zocWidth = abs gridDist.x
)

on radiosidad changed state do
if state == on
then cyl1.heightsegs = cyl2.heightsegs = 5
else cyl1.heightsegs = cyl2.heightsegs = 1
)
)







I’v learned how to divide the mesh to apply different materials to elemens.
Now I would like to know how to update the mesh when you change a parameter on the modify panel.
As you see, the buildMesh handler calls a function named createMesh.
The rollout includes a checkbutton to increase the polygon density of part of the mesh (just one cylinder).

How could I call this function from inside this check button?

May I recreate the complete mesh this way?


Summing: The "mesh" property of the plugin can be called after the creation process?

Bye

Bobo
01-02-2008, 08:17 PM
This is pretty cool.

A couple of notes:
*You don't have to pass the mesh to the createMesh function. You can remove theMesh parameter from the function and just call the createMesh() function with no parameters. The mesh is defined and returned in the function, you don't care what the current mesh contains.

*If you define the function AFTER the parameters definition, you can use the parameter names like radius, height etc. without prefixing them with this. Makes the code shorter ;)

*To get the checkbutton working, just link it to a boolean parameter in the paramBlock like you did with the spinners. Each time a UI control linked to a parameter is changing state, the build handler will be called automatically, so you don't even have to call the function yourself. This means that you could move the whole createMesh function code inline into the on build handler's body - calling a function involves a slight overhead and only makes sense if the same code is invoked from multiple places. If you can get the checkbutton to activate the on build handler, then you don't need that code outside of the handler...
Then move the IF that decides the number of segments in the cylinders out of the TOOL CREATE body (it should have never been there to start with, this is a change handler that normally belongs into the rollout) and put it in the createMesh code, right after the IF which decides whether to create the building blocks. Replace 'state' with the name of the boolean parameter linked to the checkbutton.

Good work!

fferro2
01-03-2008, 12:22 AM
SWEEETTTTTT! (thank you again)

plugin simpleObject Column
name:"Column"

classID:#(63446,55333)

category:"3DEmpire" (
local cyl1, cyl2, cyl3, box1, tempMesh1, tempMesh2, tempMesh3

parameters main rollout:params (
radius type:#worldUnits ui:radius default:0.3
height type:#worldUnits ui:height default:2.4
zocHeight type:#float ui:zocHeight default: 0.1
zocWidth type:#float ui:zocWidth default: 0.2
radiosity type:#boolean ui:radiosity
)

fn assignMatID theMesh IDnum = (
for f = 1 to theMesh.numfaces do setFaceMatID theMesh f IDnum
)

fn transformMesh theTriMesh theMatrix = (
for v = 1 to theTriMesh.numverts do
setVert theTriMesh v ((getVert theTriMesh v)*theMatrix)
theTriMesh
)

rollout params "Column" (
group "Dimensions" (
spinner radius "radius" type:#worldUnits range:[0.0,1E9,1E-3]
spinner height "height" type:#worldUnits range:[0.0,1E9,1E-3]
)
group "Zocalo" (
spinner zocHeight "height" type:#float range:[0.0,1E9,1E-3]
spinner zocWidth "width" type:#float range:[0.0,1E9,1E-3]
)
group "Parameters" (
checkbutton radiosity "Radiosity" checked:false tooltip:"Increase the number of polygons"

)
)

on buildMesh do (
if cyl1 == undefined then (
cyl1 = createInstance cylinder heightsegs: 1
cyl2 = createInstance cylinder heightsegs: 1 sides: 18 smooth:true realWorldMapSize: on
box1 = createInstance box lengthsegs: 3 widthsegs: 3 height: 0.0
)
if radiosity == on then cyl2.heightsegs = 5 else cyl2.heightsegs = 1

cyl1.height = zocHeight ; cyl2.height = height - zocHeight
cyl2.radius = radius
cyl1.radius = radius + zocWidth
box1.width = box1.length = radius * 2 * 1.1

tempMesh1 = cyl1.mesh
tempMesh2 = cyl2.mesh
tempMesh3 = box1.mesh
assignMatID tempMesh1 3
assignMatID tempMesh2 4
assignMatID tempMesh3 5

tempMesh2 = transformMesh tempMesh2 (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,this.zocHeight])
tempMesh3 = transformMesh tempMesh3 (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,this.height])
mesh = tempMesh2.mesh + tempMesh1.mesh + tempMesh3.mesh
delete tempMesh1
delete tempMesh2
delete tempMesh3
)

tool create (
on mousePoint click do
case click of (
1: nodeTM.translation = gridPoint
5: (#stop
)
)

on mouseMove click do
case click of (
2: radius = abs gridDist.x
3: height = abs gridDist.z
4: zocHeight = if (abs gridDist.z < height) then abs gridDist.z else height
5: zocWidth = abs gridDist.x
)
)
)


Now the last thing ;-)

I have to delete faces at the top, looking up, and faces at the bottom looking down.
I've written to functions to do this:
The first one select the faces whose normals look up/down:

fn selFaceNormal obj FaceNumbers = (
MySelectionSet=#()
for i = 1 to FaceNumbers do (
theVector = [0,0,1]
theThreshold = 0.01
theFace = i
theNormal= polyOp.getFaceNormal obj theFace
theAngle = acos ( dot (normalize theNormal) (normalize theVector))
if theAngle <= theThreshold do join MySelectionSet #(theFace)
)
MySelectionSet
)

myFaceNumbers = polyOp.getNumFaces $
normalFaces = setFaceSelection $ (selFaceNormal $ myFaceNumbers)

The second function selects from the first, only the faces at certain Z coordinate (base/heigth of the mesh):

fn selFaceCoordZ obj Faces coordZ Threshold = (
MySelectionSet=#()
for theFace in Faces do (
bitVerts = polyOp.getVertsUsingFace obj theFace as array
inZ = true
for i = 1 to (bitVerts as array).count do (
vertCoordZ = (polyop.getvert obj bitVerts[i]).z
if abs(vertCoordZ - coordZ) > Threshold do inZ = false

)
if inZ do join MySelectionSet #(theFace)
)
MySelectionSet
)
coordZdeFacesParaEliminar = 43.016
setFaceSelection $ (selFaceCoordZ $ normalFaces coordZdeFacesParaEliminar 0.001)


I've tested them and work OK with a polymesh. The rigth faces are selected and ready to be deleted.
I would like to run this two functions AFTER all the creation process of the mesh.

So, where is the right place to call them?
I am thinking about adding an Edit Poly modifier to run them and collapse the stack after. May be from the ON MOUSPOINT handler, after the #stop sentence OR in a ON STOP ...
Is it correct?

Bye

Bobo
01-03-2008, 09:33 AM
Once again, FORGET about using selections, modifiers, or EditablePoly.
When the scripted plugins were introduced in Max 3, there was NO EditablePoly in Max, so the two are not compatible.

The right way to go is to operate on the TriMesh - just check each face normal against +Z and -Z vectors and delete if necessary. To do this, loop BACKWARDS from the last face to the first using for f = theMesh.numaces to 1 by -1 do ..., then use theNormal = getFaceNormal theMesh f to get the face normal vector, calculate the angle to [0,0,1] using acos(dot theNormal [0,0,1]) and if the angle is 0, delete the face. Then do the same with [0,0,-1] to delete faces looking down. You can even use a small threshold, for example if the angle is < 0.0001, then delete the face.

Think of the mesh you are building as VIRTUAL - while you are creating it, it does not exist in the scene, only in memory. It becomes the mesh of the base object of your scripted plugin AFTER you assign the result to the internal mesh variable. You CANNOT perform any operations on the stack of the plugin object, because your code is at the bottom of the stack and does not "see" the rest. Also, you want to keep your object procedural, even if it was possible to collapse the object to get the desired look, you would kill all parameters and that would negate the whole idea of a procedural object. And you can only use methods which are described as operating on meshes. If a method is noted to not be applicable to TriMesh, you cannot use it. Note that you can build your column vertex by vertex and face by face the way the C++ plugins define a sphere, a cylinder etc. It would be slower, but it is the lowest level of control you can get at. It is a lot of fun, too. ;)

EverZen
01-03-2008, 09:52 AM
Just a quick note to say thanks guys for going into the level of detail in both describing the problem and the solution, this thread has helped me no end with getting my head around simple Object Plugins, and I am definitely now in a position to have a play :)

Thanks!

Rich

fferro2
01-03-2008, 06:46 PM
IUUUJJJUUUUUU!
thanks God (Bobo) it works:

plugin simpleObject Column
name:"Column"
classID:#(63446,55333)
category:"3DEmpire" (
local cyl1, cyl2, cyl3, box1, tempMesh1, tempMesh2, tempMesh3
parameters main rollout:params (
radius type:#worldUnits ui:radius default:0.3
height type:#worldUnits ui:height default:2.4
zocHeight type:#float ui:zocHeight default: 0.1
zocWidth type:#float ui:zocWidth default: 0.2
radiosity type:#boolean ui:radiosity
)
fn assignMatID theMesh IDnum = (
for f = 1 to theMesh.numfaces do setFaceMatID theMesh f IDnum
)
fn transformMesh theTriMesh theMatrix = (
for v = 1 to theTriMesh.numverts do
setVert theTriMesh v ((getVert theTriMesh v)*theMatrix)
theTriMesh
)
fn deleteFacesLookingUpDown theTriMesh lookVect = (
for vect in lookVect do (
for f = theTriMesh.numfaces to 1 by -1 do (
theNormal = getFaceNormal theTriMesh f
-- delete faces looking up/down
if acos(dot theNormal vect) == 0 do deleteFace theTriMesh f
)
)
)
rollout params "Column" (
group "Dimensions" (
spinner radius "radius" type:#worldUnits range:[0.0,1E9,1E-3]
spinner height "height" type:#worldUnits range:[0.0,1E9,1E-3]
)
group "Zocalo" (
spinner zocHeight "height" type:#float range:[0.0,1E9,1E-3]
spinner zocWidth "width" type:#float range:[0.0,1E9,1E-3]
)
group "Parameters" (
checkbutton radiosity "Radiosity" checked:false tooltip:"Increase the number of polygons"
)
)
on buildMesh do (
if cyl1 == undefined then (
cyl1 = createInstance cylinder heightsegs: 1
cyl2 = createInstance cylinder heightsegs: 1 sides: 18 smooth:true realWorldMapSize: on
box1 = createInstance box lengthsegs: 3 widthsegs: 3 height: 0.0
)
if radiosity == on then cyl2.heightsegs = 5 else cyl2.heightsegs = 1

cyl1.height = zocHeight ; cyl2.height = height - zocHeight
cyl2.radius = radius
cyl1.radius = radius + zocWidth
box1.width = box1.length = radius * 2 * 1.1
tempMesh1 = cyl1.mesh
tempMesh2 = cyl2.mesh
tempMesh3 = box1.mesh
assignMatID tempMesh1 3
assignMatID tempMesh2 4
assignMatID tempMesh3 5

deleteFacesLookingUpDown tempMesh1 #([0,0,-1])
deleteFacesLookingUpDown tempMesh2 #([0,0,1],[0,0,-1])
deleteFacesLookingUpDown tempMesh3 #([0,0,1])
tempMesh2 = transformMesh tempMesh2 (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,this.zocHeight])
tempMesh3 = transformMesh tempMesh3 (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,this.height])

mesh = tempMesh2.mesh + tempMesh1.mesh + tempMesh3.mesh

delete tempMesh1
delete tempMesh2
delete tempMesh3
)
tool create (
on mousePoint click do
case click of (
1: nodeTM.translation = gridPoint
5: #stop
)

on mouseMove click do
case click of (
2: radius = abs gridDist.x
3: height = abs gridDist.z
4: zocHeight = if (abs gridDist.z < height) then abs gridDist.z else height
5: zocWidth = abs gridDist.x
)

)
)


I will follow improving it till the end...

Next steps:
1- create an array of columns, joining them at bottom and top with two elements of the same mesh: floor and ceiling.
As manual example shows with boxes at: Creating Maxscript Tools > Scripted Plug-ins

2- change shape between square and circle.

Bobo: I will never ask you again how to add a modifier inside a scripted geometry plugin . ;-)

fferro2
01-03-2008, 11:43 PM
homework almost done:

Modifying the script in the Maxscript reference manual, at:

Creating Maxscript Tools > Scripted Plug-ins > Scripted Geometry Plug-ins > Example

I can create Instances of a box with this:

plugin geometry foo_plugin_def
name:"FooBar"
category:"Scripted Primitives" (
local boxes = #(), clickAt
tool create (
on mousePoint click do (
clickAt = worldPoint
boxes[1] = box pos:[1,0,0]
for i in 1 to 9 do (
append boxes (instance boxes[1])
boxes[i].pos = [i*20,0,0] + clickAt
)
#stop
)
)
rollout frab "Parameters" (
spinner frab_value "Frabulate" range:[-1000,1000,20]
on frab_value changed val do
for i in 1 to 10 do boxes[i].pos = [i*val,0,0] + clickAt
)
)


Is it possible to insert my Scripted plugin inside a similar code to create instances of my Column?

This way I will obtain an array of my column, may be with 20 or 30 instances.
Perhaps too much to ask for a simple scripted plugin...

Thanks in advance.

fferro2
01-04-2008, 12:21 AM
Hey! my lastest discovery.
With the plugin installed:
showClass "Column.*"
lists all the properties of this new geometry:

Column : GeometryClass {f7d6,d825}
.radius : worldUnits
.height : worldUnits
.zocHeight : float
.zocWidth : float
.Radiosity : boolean
OK

And
b = column pos:[1,0,0] heigth:3 radius:.2 zocHeight:.1 zocWidth:0.02
Will create a column with this values.
Not bad...

fferro2
01-04-2008, 12:29 AM
SO...:

plugin geometry foo_plugin_def
name:"FooBar"
category:"Scripted Primitives" (
local columns = #(), clickAt
tool create (
on mousePoint click do (
clickAt = worldPoint
columns[1] = column pos:[1,0,0] heigth:3 radius:.2 zocHeight:.1 zocWidth:0.02
for i in 1 to 9 do (
append columns (instance columns[1])
columns[i].pos = [i*20,0,0] + clickAt
)
#stop
)
)
rollout frab "Parameters" (
spinner frab_value "Frabulate" range:[-100,100,5]
on frab_value changed val do
for i in 1 to 10 do columns[i].pos = [i*val,0,0] + clickAt
)
)


Will create 10 Columns (instances) with 5 meters between each

IT WORKS!

fferro2
01-07-2008, 07:03 PM
The complet code here:
http://forums.cgsociety.org/showthread.php?p=4872265#post4872265

CGTalk Moderation
01-07-2008, 07:03 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.