3D physics in Director allows you to create a dynamic scene from a static 3D scene. Imagine you have created a ball and a floor model in your 3D world, inorder to create the bouncing effect, you need to move the ball towards the floor and detect collision at every frame instead the physics engine can be used to act like a middleware that handles your collision, motion and other interactions between the models.
The first step in adding physics to the 3D Scene is creating a physX internal cast member. Click on Insert->Media->Physics, name the castmember as “physX”.
Initialize the physics engine using Lingo.
mySprite = sprite(me.spriteNum)
tMember = mySprite.member
tMember.resetWorld()
-- Steps the physics world by the
actual time elapsed or by the time specified in the init call's timeStep
pTimeStepMode = #equal
-- Used in the #equal time step mode,
specifies the step time for the physics world.
pTimeStep = 0.33
-- Represents the number of substeps
for each simulate call
pSubSteps = 5
pPhysicsMember = member("physX")
pPhysicsMember.Init(member(tMember), vector(1,1,1),#equal, pTimeStep, pSubSteps )
The Init() method is used to initialize the physics world, it takes 4 arguments, the 3D world, the scaling factor, the Timestep, the Timestepmode and the subStepcount. The scaling factor determines the scaling factor of the 3D world in physics. The Timestep can be either #equal or #automatic, when it is initialized to #automatic the physics world is stepped by the actual time elapsed and when it is initialized to #equal the physics world is stepped by the time specified in the timeStep parameter, the subStepcount is used to provide accuracy.
A ‘-2’ error is thrown if an attempt is made to set/get a physics world property before the world is initialized.
The gravity property for the Physics World is set as follows
pPhysicsMember.gravity = vector(0,-10,0)
The vector specifies that the gravity force is applied in the y-direction since the ball has to move down towards the floor
The other Physics World properties that can be set are
- angularDamping
- contactTolerance
- friction
- gravity
- IsInitialized
- linearDamping
- restitution
- scalingFactor
- sleepMode
- sleepThreshold
- subSteps
- timeStep
- timeStepMode
The rigidbodies are created in the Physics world from the 3D models. The #meshdeform modifier must be added to the 3D model before creating a rigid body from it, a “-21” error is displayed if the #meshdeform modifier is not added.
-- create the sphere model
sphereResource = tMember.newModelResource("Sphere", #sphere)
sphereResource.radius
= 5
sphereModel = tMember.newModel("Sphere",
sphereResource)
-- create a rigid body for the
sphereModel
sphereModel.addmodifier(#meshdeform)
sphereRigidBody =
pPhysicsMember.createRigidBody(sphereModel.name,sphereModel.name,#sphere,#dynamic)
The rigid body is created using the createRigidBody() method, the first argument specifies the Model on which the rigidbody is created, the second argument specifies the name of the rigidbody, the third argument can be #box, #Sphere, #convexShape or #concaveShape depending on the shape of the rigid body, the fourth argument can either be #static, if the body is an immovable body or #dynamic if the body is movable. The last argument flipNormals is optional, and if specified it inverts the face normals of the object.
sphereRigidBody.restitution = 1
sphereRigidBody.mass = 1
The mass of the sphere is set to one since it has to be lighter than the floor to bounces off from it, setting the restitution value to 1, causes the ball to bounce when it collides with the floor. [The law of Restitution]
Other Rigid Body properties that can be set are
- angularDamping
- angularMomemtum
- angularVelocity
- centerOfMass
- contactTolerance
- friction
- isPinned
- isSleeping
- linearDamping
- linearMomemtum
- linearVelocity
- mass
- model
- name
- orientation
- position
- restitution
- properties
- shape
- sleepMode
- sleepThreshold
- type
- userData
The simulate() method is called at the end of each frame, it is used to step the physics world through the timeStep that is set during the init() call.
on exitFrame me
pPhysicsMember.simulate(pTimeStep, pSubSteps)
end
The destroy() method is used to stop the simulation and free all the resources in the Physics world .
on endSprite me
if pPhysicsMember.isInitialized then
pPhysicsMember.destroy()
end if
end
The destroy() method must be called before calling another init() function on the same 3D scene. And the resetworld() method should not be called between the init() and destroy() methods.
The code for the complete 3D physics application is as follows.
Import an Image and label it “MyImage” to create texture for the 3D models. Insert a 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 pTimeStep
property pSubSteps
property pPhysicsMember
property tMember
on beginSprite me
mySprite = sprite(me.spriteNum)
tMember = mySprite.member
tMember.resetWorld()
-- Steps the physics
world by the actual time elapsed or by the time specified in the init call's
timeStep
pTimeStepMode = #equal
-- Used in the #equal
time step mode, specifies the step time for the physics world.
pTimeStep = 0.33
-- Represents the
number of substeps for each simulate call
pSubSteps = 5
pPhysicsMember = member("physX")
pPhysicsMember.Init(member(tMember), vector(1,1,1),#equal, pTimeStep, pSubSteps )
pPhysicsMember.gravity = vector(0,-10,0)
-- create the sphere
model
sphereResource = tMember.newModelResource("Sphere", #sphere)
sphereResource.radius
= 5
sphereModel = tMember.newModel("Sphere",
sphereResource)
-- add new shader and
texture to the ball model
tMember.newTexture("Texture01",#fromImageObject,member("MyImage").image)
newShader01 = tMember.newShader("newPainter01",#standard)
newShader01.texture = tMember.texture("Texture01")
tMember.shader("newPainter01").texturemode = #wrapSpherical
sphereModel.shader = newShader01
-- create a rigid body
for the sphereModel
sphereModel.addmodifier(#meshdeform)
sphereRigidBody =
pPhysicsMember.createRigidBody(sphereModel.name,sphereModel.name,#sphere,#dynamic)
sphereRigidBody.restitution = 1
sphereRigidBody.mass = 1
-- create the floor
bwallResource = tMember.newModelResource("bwall", #box)
bwallResource.height
= 10
bwallResource.width
= 180
bwallResource.length
= 5
bottomwallModel = tMember.newModel("bwall",
bwallResource)
bottomwallModel.transform.identity()
bottomwallModel.transform.translate(0,-75,0)
-- add new shader and
texture to the ball model
tMember.newTexture("Texture02",#fromImageObject,member("MyImage").image)
tMember.model("bwall").shader.texture= tMember.texture("Texture02")
bottomwallModel.addmodifier(#meshdeform)
floorRigidBody =
pPhysicsMember.createRigidBody(bottomwallModel.name,bottomwallModel.name,#box,#static)
floorRigidBody.restitution = 1
floorRigidBody.mass = 100
end
on endSprite me
if pPhysicsMember.isInitialized then
pPhysicsMember.destroy()
end if
end
on exitFrame me
pPhysicsMember.simulate(pTimeStep, pSubSteps)
end
References:
[1] 3D samples from coderecipe http://coderecipe.com/physics-samples/
Feedback:
If you have any questions or comments concerning this article, please send me a message at srideviaishwariya@gmail.com
|