GroundWiz Planter MAXScript API

GroundWiz Planter can be accessed and controlled from MaxScript. It is possible to access and modify most of the internal data for many different purposes: exporting data to game engine, adding & repositioning plants, writing custom scripts for plant control & positioning.


Planter Data Structure
Planter object contains a list of plants that are used by the current Planter. Each of those plants in turn contains a list of all the LOD (level of detail) objects, used by each plant as shown in the following example:

     

Internally, Planter uses generic Planter structure 'GwPlanter' for all 3 data structures: Planter Object, Plant Object and Plant LOD to simplify data organization. Therefore, most parameters are used only by either Planter Object, Plant Object or Plant LOD.

In the following section, we will explain parameters and functions that are relevant for each Planter's data structure.




Planter Object
Planter object can be accessed through MAXScript just like any other 3ds Max object.
As an example, for Planter object named 'GwPlanter01' you can set viewport display to proxy mode with the following MAXScript command:
     $GwPlanter01.dpDisplayType = 2

What follows are parameters(fields) & functions used to control the main Planter object.


Basic Parameters / functions
obPlant (maxObject array field, read only)
     Array of plants of the current Planter. This array is read only and must not be directly modified. To add/remove plants, use functions AddPlant and RemPlant.

AddPlant <node plantObj> (function, no return value)
     Appends a new plant to the end of the obPlant list. The same as using 'Planted Objects' -> 'Planted Object' -> Add. Node must be renderable object.

     For example, to add a new cone as a plant to the Planter, you could use:
     $GwPlater01.AddPlant( Cone())


RemPlant <integer plantIdx> (function, no return value)
     Removes(deletes) plant from the obPlant list. The Same as using 'Planted Objects' -> 'Planted Object' -> X (Delete).

obPlantCurr (integer field, range 0 to number of plants-1)
     Zero based index to the currently selected plant in the obPlant array (first plant is index 0, second plant is index 1 and so on). Plant with this index will be displayed in the modifier panel.
     Example - to access current plant on planter 'GwPlanter01':
     $GwPlanter01.obPlant[ $GwPlanter01.obPlantCurr+1 ]


obTerrain (node array field)
     Lists all max mesh objects (nodes) whose surfaces will be used for planting. Objects must be convertible to mesh.

cfgMaterial (material field, read only)
     Multi material used by the current Planter containing materials for all the plants and their LODs. This multi material is automatically rebuilt and updated when plants and their materials are changed and should therefore never be modified by the user directly. Instead, modify materials on plants when needed and expect cfgMaterial to reflect the changes.

cfgVisScreen (integer field, range 0 to 1)
     When set to 1, LOD selection for the current Planter will be based on the screen size of the object and not the distance from the camera. Note that this parameter affects all plants within the current Planter.

cfgRandomSeed (integer field)
     This is internal parameter that controls how Planter will calculate random features when planting. Two Planters with the same parameters will still look different after the planting is done as long as this parameter is different. This value gets reset when the user presses Clear button on Planter's interface.

obPlantInfo (integer field, range 0 to 1)
     Internal parameter that records state of 'Planter Objects' -> Info user interface.

Rebuild (function, no return value)
     Must be called when major rebuild of Planter internal structures is required. See AddInstances and RemInstances.


Viewport Display
The following fields control Planter viewport display and are directly related to the 'Display: Obj / Tri' panel.

dpGizmoSize (float field)
     The size of viewport gizmo for Planter. Setting it to 0.0 will disable gizmo display.

dpDisplayType (integer field, range 0 to 2)
     How instances of planted objects are displayed in the viewport: 0(normal mesh display), 1(lowestest quality LOD), 2(proxy display).

dpDisplayProxyType (integer field, range 0 to 2)
     When viewport display type is set to proxy mode (dpDisplayType = 2) then this parameter sets the type of proxy to draw in viewports: 0(pyramid), 1(box), 2(cylinder).

dpSkipObjects (integer field, range 0 and up)
     To speedup viewport redraw, you may want to allow redraw to skip some planted objects. Value of 0 will disable skipping, value of 1 will show ½ of objects, value 2 will show ¼, next one half of the previous, and so on.

dpDisplayMax (integer field)
     Limits the maximum number of objects shown in the viewport.

dpShowAnimOffset (boolean field)
     See 'Display: Obj / Tri' -> 'Show Animation Offset'


Render Settings
Parameters below are exposed through 'Render Settings' panel. As the name implies, they control how the Planter will be rendered.

rdClipPlanes (worldUnits field)
     See 'Render Settings' -> Expand Clip Planes.

rdSkipObjOn (boolean field)
     Controls if 'Testing Setup' feature is used.

rdSkipObjects (integer field)
     Used only if 'Testing Setup' is enabled. See 'Render Settings' -> 'Skip Objects'

rdRenderObjects (integer field)
     Used only if 'Testing Setup' is enabled. See 'Render Settings' -> 'Max Objects'

rdShaderType (integer field, range 0 to 2)
     Select shader mode: 0(standard shader), 1(mental ray shader), 2(custom object shader).

rdRenderTris (integer field)
     Used only if standard shader is enabled (rdShaderType = 0). See 'Render Settings' -> 'Max Tris(x1000)'.

rdRenderUseCaching (boolean field)
     Used only if standard shader is enabled (rdShaderType = 0). See 'Render Settings' -> 'Use Mesh Caching'.

rdNativeMRAnimOffset (integer field)
     Used only if mental ray shader is enabled (rdShaderType = 1). See 'Render Settings' -> 'Anim Offset Frames'.

rdCustomMaxObjects (integer field)
     Used only if custom object shader is enabled (rdShaderType = 1). See 'Render Settings' -> 'Custom object shader'.


Planting Process Parameters
The following parameters are used to control transformation properties of the planting process and are directly related to the 'Setup Transformations' panel. They will be used when planting happens (using PlantNow or brush planting).

trUp (percent field)
     Pointing Direction

trOrient_minX (angle field)
trOrient_maxX (angle field)
trOrient_minY (angle field)
trOrient_maxY (angle field)
trOrient_minZ (angle field)
trOrient_maxZ (angle field)
     Orientation Range parameters

trScaleXYZ_min (percent field)
trScaleXYZ_max (percent field)
     Uniform Scale Range

trScale_minX (percent field)
trScale_maxX (percent field)
trScale_minY (percent field)
trScale_maxY (percent field)
trScale_minZ (percent field)
trScale_maxZ (percent field)
     Scale Range parameters

trScale_lockXY (boolean field)
     Lock X and Y Scale Range factors

trOffset_min (float field)
trOffset_max (float field)
     Surface Offset Range parameters

trOffsetType (integer field, range 0 to 1)
     Surface Offset Type modes : 0(Absolute Value Z) and 1(Object Height %)


Parameters in the next section are directly related to the 'Setup Collisions / Layers' panel. They will be used when planting happens (using PlantNow or brush planting).

plLayersUse (boolean field)
     Enable GroundWiz Layer Limits.

plLayers (string array field)
     GroundWiz Layer Limits array of strings (names of all GroundWiz layer prefixes used for planting).

plLayersRadius (worldUnits field)
     GroundWiz Layer Limits Sample Siz parameter.

plLayersDensity (percent field)
     See 'Layer Intensity Influence' -> 'Density Min %' parameter.

plLayersScale (percent field)
     See 'Layer Intensity Influence' -> 'Scale Min %' parameter.

plCollEnabled (boolean field)
     The same as Collisions-> Enabled parameter.

plSelfCollision (boolean field)
     'Do self collision' parameter.

plOtherPlanters (boolean field)
     'Use other GW Planters' parameter.

plOtherObjectsUse (boolean field)
     Enable 'Max Objects with prefix' feature.

plOtherObjects (string array field)
     Array of strings - prefixes of max objects that will be used for collision detection. See 'Max Objects with prefix'.

plBorderRadius (worldUnits field)
     See 'Max Objects Influence' -> 'Border Radius' parameter.

plDensityMin (percent field)
     See 'Max Objects Influence' -> 'Density Min %' parameter.

plScaleMin (percent field)
     See 'Max Objects Influence' -> 'Scale Min %' parameter.


Parameters below are exposed through 'Planting Tools' panel.

plDensity (float field)
     See 'Planting Controls' -> 'Density per Unit' section.

plSelected (boolean field)
     See 'Planting Controls' -> 'Ground's selected faces' section.

plBrushSize (worldUnits field)
     Planting brush size: see 'Planting Controls' -> brush size.

plBrushSelectAmount (percent field)
     See 'Planting Controls' -> Brush Select amount.




Plant Object
Main Planter object contains array of plants (plant objects).
Each plant object holds the following crucial data:
- list of all planed instances of the current plant
- list of Plant LOD objects to be able to draw the current plant

As mentioned before, to access the first plant on Planter 'GwPlanter01', you can type the following in the MAXScript listener:
     $GwPlanter01.obPlant[1]

And to retrieve a number of plants on Planter 'GwPlanter01', use:
     $GwPlanter01.obPlant.count


Plant Object Parameters & functions
poName (string field)
     Name of the current Plant (can be anything).

poEnabled (boolean field)
     Get/set whether current plant is enabled (visible & renderable).

poUsable (boolean field)
     Get/set whether current plant can be used for planting. If set to false then current plant doesn't participate in planting operations (mass planting, brushing, moving...). It will still be rendered though.

poPresence (float field)
     Used by the planting process, see Plant -> Presence parameter.

poCollUse (boolean field)
     Used by the planting process, see Plant -> Collision Cylinder.

poCollRadius (worldUnits field)
     Used by the planting process, see Plant -> Collision Cylinder.

poCollHeight (worldUnits field)
     Used by the planting process, see Plant -> Collision Cylinder.

poAnimOffset (float field)
     For description see Plant -> Animation Offset.

poAnimOffsetLoop (boolean field)
     For description see Plant -> Animation Offset.


Working with Plant LOD Objects
obPlant (maxObject array field, read only)
     Each Plant object just like Planter Object contains obPlant field. In this case, it contains a list of 'gwPlanter' data structures that are used to hold LOD object data. This array is read only and must not be directly modified. To add/remove LOD objects, use functions AddLOD and RemLOD.

     Example: To access the first LOD of the second plant on planter 'GwPlanter01':
     $GwPlanter01.obPlant[2].obPlant[1]
     Note that obPlant field was used twice: first to access the plant and second time to access LOD object data of the plant.


AddLOD <node lodObj> (function, no return value)
     Appends a new LOD object to the end of the obPlant list. The same as using 'Plant' -> 'Level of Detail (LOD)' -> Add. Node must be renderable object.

     For example to add a new cone as LOD object to plant#1, you could use:
     $GwPlater01.obPlant[1].AddLOD( Cone())


RemLOD <integer lodIdx> (function, no return value)
     Removes(deletes) LOD from the obPlant list. The same as using 'Plant' -> 'Level of Detail (LOD)' -> X (Delete).


Working With Plant Instances
Plant holds a list of all planted instances as a list of compressed transformation matrices. Since each plant instance occupies only a small amount of memory, it is possible to store literally millions of instances: each one has its own position, size and non-uniform scale factors, just like in case of normal max objects.
To access instance data, use the following functions:

GetNumInstances (function, returns integer)
     Returns number of planted instances of that plant.

     Example: On Planter named 'GwPlanter01' visit the first plant (obPlant[1]) and return the number of planted instances of that plant.
     $GwPlanter01.obPlant[1].GetNumInstances()


GetInstanceMtx <integer index> (function, returns Matrix3)
     Returns transformation matrix in local space of a particular instance.

     Example#1: On Planter named 'GwPlanter01' visit the first plant (obPlant[1]) and return transformation matrix in local space for instance#3.
     $GwPlanter01.obPlant[1].GetInstanceMtx 3
     Returned value depends on a scene, in our case, it prints:
     (matrix3 [0.959961,0.278809,0] [-0.278809,0.959961,0] [0,0,1] [-2494.16,-2208.87,0])

     Example#2: Similar to the previous example except that this time matrix is transformed to the world space.
     ($GwPlanter01.obPlant[1].GetInstanceMtx 3) * $GwPlanter01.objecttransform


GetInstanceMtxList <integer index> <integer num> (function, returns array of Matrix3)
     Similar to GetInstanceMtx except that it returns an array of transformation matrices. This method was added for speed reasons only to be able to retrieve more matrices with a single call. Do not try to return too many matrices at once since script can run out of memory.

     Example: On Planter named 'GwPlanter01' visit the first plant (obPlant[1]) and return array of 30 transformation matrices in local space for planted objects from #1 to #30.
     $GwPlanter01.obPlant[1].GetInstanceMtxList 1 30


SetInstanceMtxList <integer index> <array of Matrix3 matrixList> (function, no return value)
     Similar to GetInstanceMtxList except that this one will modify existing instances. Once all the modifications are complete, Rebuild function must be called on the main Planter object.

AddInstances <array of Matrix3 matrixList> (function, no return value)
     Allows user to add instances of the current plant to the Planter. New instances will be added to the end of the internal instance list. Once all the modifications are complete, Rebuild function must be called on the main Planter object.

     Example: First create 100 matrices with random positions. Then on Planter named 'GwPlanter01' visit the first plant (obPlant[1]) and add 100 instances, using the matrices created before. Finally call Rebuild to tell Planter that modifications are complete and to rebuild internal data.
     posA = for i=1 to 100 collect (transMatrix(random [0,0,0] [100,100,0]));$GwPlanter01.obPlant[1].AddInstances posA;$GwPlanter01.Rebuild();


RemInstances <integer index> <integer num> (function, no return value)
     Allows you to remove a range of unneeded instances from the current plant. Once all the modifications are complete, Rebuild function must be called on the main Planter object.

     Example: On Planter named 'GwPlanter01' visit the first plant (obPlant[1]) and remove first half of all instances. Call Rebuild when done.
      numInst = $GwPlanter01.obPlant[1].GetNumInstances();$GwPlanter01.obPlant[1].RemInstances 1 (numInst/2);$GwPlanter01.Rebuild();




LOD Object
As mentioned in the previous section, each plant contains a list of LOD objects accessible via Plant's obPlant field.
Just like 'Main Planter Object' and 'Plant Object', LOD Object also keeps all of its data in a gwPlanter data structure.

So, for example, to access second LOD of the first plant of Planter 'GwPlanter01', you can type the following in the MAXScript listener:
     $GwPlanter01.obPlant[1].obPlant[2]

The following parameters and functions are used to access LOD object data.

poName (string field)
     Name of the current LOD Object (can be anything). This field will be updated by ReplaceLOD.

poEnabled (boolean field)
     Get/set whether current plant is enabled (visible & renderable).

poObject (maxObject field, read only)
     Internal field that holds max object that will be used to draw the current LOD. To replace it, please use ReplaceLOD. This field will be updated by ReplaceLOD.

poMaterial (material field)
     Contains material used by the current LOD; can also be multi-material. This field will be updated by ReplaceLOD.

poMtx (matrix3 field)
     This matrix holds current LOD's pivot point transformation matrix. Final world transformation for an instance with some LOD is calculated as:
     poMtx * GetInstanceMtx * $GwPlanter01.objecttransform
     This field will be updated by ReplaceLOD.

poMtxOrig (matrix3 field)
     This field holds original world matrix on where LOD object was positioned in the world before it was added to the Planter. This is only used when LOD is put back to scene with PutLODToScene or via user interface.

poVisScreen (percent field)
     This field will be used if cfgVisScreen for the current Planter was set to 1. For detailed explanation see Plant -> Screen Size.

poVisDistance (worldUnits field)
     This field will be used if cfgVisScreen for the current Planter was set to 0. For detailed explanation, see Plant -> Distance Based LOD.

poVisVariation (float field)
     See Plant -> Variation.

poType (integer field, range 0 to 2)
     LOD Draw Type : 0(Draw 3D), 1(Rotate to View), 2(Align to View).

ReplaceLOD <node lodObj> (function, no return value)
     The same as using 'Plant' -> 'Current LOD' -> Replace feature. Node must be renderable object.

PutLODToScene <integer lodIdx> (function, no return value)
     The same as using 'Plant' -> 'Current LOD' -> Put feature.




Final Examples

Example#1: The following script will create a new Planter object that contains a grid of 250,000 evenly spaced teapots. You may wish to copy this example to a blank file with maxscript extension (ex. test1.ms) and run script through MAXScript Listener.



-- create a new planter object
oPlanter = GwPlanter();

-- create a simple teapot in the scene
oTeapot = teapot radius:2 segs:4

-- create a new plant in the planter from the teapot
oPlanter.AddPlant( oTeapot );

-- for each row Y
for y=1 to 500 do
(

  -- create array of evenly placed positions
  oArray = for x=1 to 500 collect (transMatrix([x*10,y*10,0]));

  -- add a row of new instances to plant#1, created above by AddPlant
  oPlanter.obPlant[1].AddInstances oArray;
)


-- finish off by letting planter rebuild its internal structures
oPlanter.Rebuild();



Example#2: Teapots created in the previous example will get displaced in a horizontal direction a bit and also randomly rotated just to destroy the perfect placement.



-- pick planter to work on (change the name if necessary)
oPlanter = $GwPlanter01;

cIdx = 1;
mIdx = oPlanter.obPlant[1].GetNumInstances();
while cIdx<=mIdx do
(

  -- will retrieve maximum 100 matrices(instances)
  oArray = oPlanter.obPlant[1].GetInstanceMtxList cIdx 100;

  -- for each instance, apply random orientation+pos offset
  for i=1 to oArray.count do
  (
    cPos = oArray[i].pos;
    oArray[i] = rotateZMatrix(random -15 15) *
      transMatrix(random (cPos-[1.5,1.5,0]) (cPos+[1.5,1.5,0]));
  )


  -- set modified matrices(instances)
  oPlanter.obPlant[1].SetInstanceMtxList cIdx oArray;

  cIdx = cIdx + oArray.count;
  format "Current index %\n" cIdx;
)


-- finish off by letting planter rebuild its internal structures
oPlanter.Rebuild();