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
|