Adobe Director Online
 
Poonam Yadav

Sridevi Aishwariya .G
Director Developer

Physics for Beginners - Part 3

 
Download the source here
 

Creating a Terrain in Director is not rocket science, there are two simple steps to create a terrain, the height map and the mesh.

The height map is a [n,m] matrix, that can be created in two ways

  • The Random generator
  • The Height BitMap

-- create the height matrix using a random generator

nRows = 5

nColumns = 5

heightMatrix = newMatrix(nRows, nColumns)

repeat with i=1 to nColumns

  repeat with j=1 to nRows

      heightMatrix.setVal(i,j,random(3))

  end repeat

end repeat

The random generator method assigns random numbers which lies within the seed value to the height map.

-- create the height using the Bitmap

pMap = member("heightmap").image

pWidth = pMap.width

pHeight = pMap.height

 

nRows = pWidth

nColumns = pHeight

heightMatrix = newMatrix(nRows, nColumns)

 

repeat with i=1 to nColumns

  repeat with j=1 to nRowss

      tHeight = float(pMap.getPixel(i,j,#integer))/255

      heightMatrix.setVal(i,j,tHeight)      

 end repeat

end repeat

In the bitmap method, we assign the pixel values in the height bitmap to the heightmap.

The second step in creating the terrain is the mesh. In order to create the mesh we need the number of faces and vertices in the mesh.

Given HeightMatrix = [n,m]
Then,
number of Vertices = n * m
number of Quads = (n-1) * (m-1)
number of Faces = nQuads * 2

The vertices for the mesh is derived as follows.

meshWidth  = heightMatrix.numRows

meshHeight = heightMatrix.numColumns

 

nVertices = heightMatrix.numRows * heightMatrix.numColumns

nFaces = ( heightMatrix.numRows - 1 ) * ( heightMatrix.numColumns - 1 ) * 2

 

terrainMesh =tMember.newMesh("Terrain", nFaces, nVertices, nFaces, 3, 0)

 

pIndex = 0

rowScale = 10

colScale = 10

heightScale = 1

 

repeat with i = 1 to meshHeight  

  repeat with j = 1 to meshWidth

 

    YHeight=heightMatrix.getVal(i, j)          

    pIndex = pIndex + 1

    terrainMesh.vertexList[pIndex]= vector((i-1)*rowScale, YHeight*heightScale, (j-1)*colScale)

     

  end repeat   

end repeat

The vertex is given in the following format
vertex[1] = [x * rowScale, heightmap[m,n] * heightScale , z * columnScale]

The faces of the mesh is constructed as follows.

The face's triangulation is as below

-- v2---v3                     k+(meshWidth+1) --- k+1+(meshWidth+1)

--  |l /|                            |                 |

--  |/ r|                            |                 |

-- v0---v1  +x direction             k         ---    k+1

--

-- Note: the triangulation should really connect whichever verts

-- are more nearly equal

-- 

-- anticlockwise trinagulation [v0, v3, v2], [v0, v1, v3]

 

 

terrainMesh.colorList = [rgb(0,200,0), rgb(0,255,0), rgb(0,220,0)]  

pFaceIndex = 0

 

repeat with  i = 0 to meshWidth - 2

  repeat with j = 1 to meshWidth

     

     k = j+(i*meshWidth)

     pFaceIndex = pFaceIndex+1

     terrainMesh.face[pFaceIndex].vertices = [ k , k+1+(meshWidth+1), k+(meshWidth+1)]      

     terrainMesh.face[pFaceIndex].colors = [1,2,3]

     

     pFaceIndex = pFaceIndex+1

     

     terrainMesh.face[pFaceIndex].vertices = [k, k+1, k+1+(meshWidth+1)]

     terrainMesh.face[pFaceIndex].colors = [3,2,1]

     

    end repeat

  end repeat

terrainMesh.generateNormals(#smooth)

terrainMesh.build()

If you are wondering about the confusing face vertex statements, this is how it is derived,

k = j+(i*meshWidth)
terrainMesh.face[pFaceIndex].vertices = [ k , k+1+(meshWidth+1), k+(meshWidth+1)]      

Since the list of vertex is a 1Dimensional array, they are arranged on the vertex of the mesh as follows,

Here the meshWidth = 5

Inoder to plot face[1] we need to pick up the points V0, V8, V7
Given , i = 0 and j = 1

k = 1+(0*5) = 1
face[Index].vertices = [ k , k+1+(meshWidth+1), k+(meshWidth+1)] 
                              = [ 1 , 8, 7]      

Finally we create the terrain as follows

terrainDesc = pPhysicsMember.createterraindesc(heightMatrix,0.5,0.2)

terrainModel = tMember.newModel("Terrain1", terrainMesh)

tposition = tMember.model("Terrain1").transform.position

torientation = tMember.model("Terrain1").transform.axisAngle 

terrain =pPhysicsMember.createTerrain("myterrain",terrainDesc,tposition,torientation,1,1,1)

The createTerrainDesc() method takes three arguments, the elevationMatrix (heightmatrix), Friction and Restitution. The createTerrainDesc() should be initialized before the terrain is created.

The createTerrain() method is used to initialize the terrain, it takes the following arguments.
terrainName – name of the terrain
terrainDesc – reference to the terrain descriptor
position – vector to set the position for the terrain
orientation – vector to set the orientation for the terrain
rowScale – row scale
columnScale – column scale
heightScale – height scale

Here is a very simple terrain example, open Director, insert physics cast member (Insert-> Media Element-> Physics) and name it “physX”. Insert a 3D scenes (Insert-> Media Element-> Shockwave 3D), name the cast member as “3D world”.

Drag and Drop the “3D world” cast member on the stage, and then drag and drop the physics cast member on the 3D scene. Left click on the 3D scene and add the following code.

property tMember

property pTimeStep

property pSubSteps

property pPhysicsMember

 

on beginsprite me

 

  mySprite = sprite(me.spriteNum)

  tMember  = mySprite.member

  tMember.resetWorld()

 

  tCamera = mySprite.camera

  tCamera.transform.position = vector (65, 12, 250)

 

  pTimeStepMode = #equal

  pTimeStep = 0.33

  pSubSteps = 5

  pPhysicsMember = member("physX")

  pPhysicsMember.Init(member(tMember), vector(1,1,1),#equal, pTimeStep, pSubSteps )

 

  createterrain()

 

end

 

on createterrain

 

  -- create the height matrix

  nRows = 50

  nColumns = 50

  heightMatrix = newMatrix(nRows, nColumns)

 

  repeat with i=1 to nColumns

    repeat with j=1 to nRows

      heightMatrix.setVal(i,j,random(3))

    end repeat

  end repeat

 

  meshWidth  = heightMatrix.numRows

  meshHeight = heightMatrix.numColumns

 

  nVertices = heightMatrix.numRows * heightMatrix.numColumns

  nFaces = ( heightMatrix.numRows - 1 ) * ( heightMatrix.numColumns - 1 ) * 2

 

  terrainMesh =tMember.newMesh("Terrain", nFaces, nVertices, nFaces, 3, 0)

 

  texcord = []

  pIndex = 0

  rowScale = 10

  colScale = 10

  heightScale = 1

 

  repeat with i = 1 to meshHeight 

    repeat with j = 1 to meshWidth

     

      YHeight=heightMatrix.getVal(i, j)          

      pIndex = pIndex + 1

      terrainMesh.vertexList[pIndex]= vector((i-1)*rowScale, YHeight*heightScale, (j-1)*colScale)

     

    end repeat   

  end repeat

 

  -- create the face's triangulation as below

  --

  -- -z direction

  --

  -- v2---v3                     i+(meshWidth+1) --- i+1+(meshWidth+1)

  --  |l /|                            |                 |

  --  |/ r|                            |                 |

  -- v0---v1  +x direction             i         ---    i+1

  --

  -- Note: the triangulation should really connect whichever verts

  -- are more nearly equal

  -- 

  -- anticlockwise trinagulation [v0, v3, v2], [v0, v1, v3]

 

  terrainMesh.colorList = [rgb(0,200,0), rgb(0,255,0), rgb(0,220,0)]  

  pFaceIndex = 0

 

  repeat with  i = 0 to meshWidth - 2

    repeat with j = 1 to meshWidth

     

      k = j+(i*meshWidth)

     

      pFaceIndex = pFaceIndex+1

     

      terrainMesh.face[pFaceIndex].vertices = [ k , k+1+(meshWidth+1), k+(meshWidth+1)]      

      terrainMesh.face[pFaceIndex].colors = [1,2,3]

     

      pFaceIndex = pFaceIndex+1

     

      terrainMesh.face[pFaceIndex].vertices = [k, k+1, k+1+(meshWidth+1)]

      terrainMesh.face[pFaceIndex].colors = [3,2,1]

     

    end repeat

  end repeat

 

  terrainMesh.generateNormals(#smooth)

  terrainMesh.build()

 

  -- create the mesh model

 

  terrainModel = tMember.newModel("Terrain1", terrainMesh)

  terrainDesc = pPhysicsMember.createterraindesc(heightMatrix,0.5,0.2)

  tposition = tMember.model("Terrain1").transform.position

  torientation = tMember.model("Terrain1").transform.axisAngle 

  terrain = pPhysicsMember.createTerrain("myterrain",terrainDesc,tposition,torientation,1,1,1)

 

end

 

on endSprite me

  if pPhysicsMember.isInitialized then

    pPhysicsMember.destroy()  

  end if 

end 

 

on exitFrame me  

 

   if pPhysicsMember.isInitialized then

    pPhysicsMember.simulate(pTimeStep, pSubSteps) 

  end if

end

Terrain is something I have found very confusing for a long time, thanks to Ravi, Iam finally able to decipher it. I hope you guys find this article useful :)

Feedback:
If you have any questions or comments concerning this article, please send me a message at srideviaishwariya@gmail.com

 
spacer image
This is not an official site from Adobe. If you need any clarifications, please mail me at info@adobedirectoronline.com