This project is read-only.

Model in Tutorial 12

Nov 9, 2009 at 10:22 PM

Hi Ohan,

I've tried to add the spaceship model from Tutorial 2 into Tutorial 12 by modifying the VehicleCreator class. The problem is that when I change the scale, the model still appears with its original size. It seems it's ignoring the scale factor. It only recognizes the rotation and translation. Why is this happening? This is what I did:

public class VehicleCreator
    {
        public static RaceCar AddRaceCar(Scene scene, TransformNode parentTrans)
        {
            TransformNode transNode = new TransformNode();
            transNode.Translation = new Vector3(0, 10, 10);
            transNode.Scale = new Vector3(0.005f, 0.005f, 0.005f);

            /*Material carMat = new Material();
            carMat.Diffuse = Color.Pink.ToVector4();
            carMat.Specular = Color.White.ToVector4();
            carMat.SpecularPower = 10;*/

            ModelLoader loader = new ModelLoader();
            Model carModel = (Model)loader.Load("", "p1_wedge");

            GeometryNode carNode = new GeometryNode("Race Car");
            //carNode.Model = new Box(3, 1.0f, 2);
            carNode.Model = carModel;
            carNode.Model.UseInternalMaterials = true;
            //carNode.Material = carMat;
            carNode.Model.CastShadows = true;
            carNode.Model.ReceiveShadows = true;

            NewtonPhysics physicsEngine = (NewtonPhysics)scene.PhysicsEngine;

            RaceCar car = new RaceCar(carNode, physicsEngine);
            for (int i = 0; i < 4; i++)
                car.Tires[i] = CreateTire((TireID)Enum.ToObject(typeof(TireID), i), 
                    car.TireTransformNode[i], carNode, scene.PhysicsEngine.Gravity);

            car.Collidable = true;
            car.Interactable = true;

            carNode.Physics = car;
            carNode.Physics.NeverDeactivate = true;
            carNode.AddToPhysicsEngine = true;

            parentTrans.AddChild(transNode);
            transNode.AddChild(carNode);

            Newton.NewtonSetBodyLeaveWorldEvent(physicsEngine.NewtonWorld,
                car.LeaveWorldCallback);

            return car;
        }

Thanks,

Emerson

Coordinator
Nov 10, 2009 at 12:51 PM

Hi Emerson,

Scaling the models for either NetwonVehicle or NewtonTire is a little more complicated.

Since Newton does not consider the scaling factor of the transformation, I do this scaling internally in NewtonPhysics and store a table of scaling factors for all of the added IPhysicsObject including NewtonVehicle. 

For any IPhysicsObject other than NewtonVehicle, I re-scale the transformation got back from Newton in the default transform callback I defined in NewtonPhysics, but since you're supposed define your own transform callback for NewtonVehicle, this scaling factor is not applied unless you apply the scaling yourself in the callback. 

To do this, first add a function called GetScale in NewtonPhysics.cs in the Goblin XNA framework:

 

public Vector3 GetScale(IntPtr body)
{
    if (scaleTable.ContainsKey(body))
        return scaleTable[body];
    else
        return Vector3.One;
}

Then, modify line 72 in the transform callback for the car in RaceCar.cs as following:

 

Matrix mat = Matrix.CreateScale(engine.GetScale(body)) * MatrixHelper.FloatsToMatrix(matrix);

I updated the SVN repository to deal with car model scaling, so you can also get the modified code from SVN (NewtonPhysics.cs and RaceCar.cs)

For re-scaling the tire models, I need to investigate a little more since it can be more complicated, so for now, it's best to use the original size of the tire model (rescale it using a modeling software like GoogleSketchUp if necessary).

Ohan

 

 

Nov 10, 2009 at 5:13 PM

Thanks Ohan, it worked!

Also I would like to know how can I reset all objects values when two of them collide. For example, I am developing a system which controls robots and I'm trying to simulate a soccer match between them. So, when one of the robots scores, the ball should be moved to its start position in the middle of the field and the robots should be moved to each side of the field, facing each other, just like in the real world. What I tried to do is create a collision pair and a collision callback function called when the pair collides

NewtonPhysics.CollisionPair goalsphere1 = new NewtonPhysics.CollisionPair(goalNode1.Physics, sphereNode.Physics);
            ((NewtonPhysics)scene.PhysicsEngine).AddCollisionCallback(goalsphere1, GoalSphereCollision1);

And my callback function do the following:

private void GoalSphereCollision1(NewtonPhysics.CollisionPair goalsphere1) { if (goalsphere1.ContactPoints > 0) score1++; Console.WriteLine("Robot 2 " + score1); Matrix mat = robot.CompoundInitialWorldTransform; Matrix mat1 = robot1.CompoundInitialWorldTransform; Matrix mat2 = sphereNode.Physics.CompoundInitialWorldTransform; ((NewtonPhysics)scene.PhysicsEngine).SetTransform(robot, mat); ((NewtonPhysics)scene.PhysicsEngine).SetTransform(robot1, mat1); ((NewtonPhysics)scene.PhysicsEngine).SetTransform(sphereNode.Physics, mat2); }
robot is based on RaceCar.cs and VehicleCreator.cs. So to add a robot I just do this:
robot = VehicleCreator.AddRobot(scene, parentTransNode);

All objects are moved to the right place but they still have physics values assigned to them. I need to reset all the values so they don't keep appearing just in the right place but with no acceleration applied on them too. Since my code just move them but do not reset the values, next thing I tried was to restart simulation, so the code changed to this:

private void GoalSphereCollision2(NewtonPhysics.CollisionPair goalsphere2)
        {
            if (goalsphere2.ContactPoints > 0)
                score2++;
            Console.WriteLine("Robot 1 " + score2);         

            ((NewtonPhysics)scene.PhysicsEngine).RestartsSimulation();
        }

At first I thought it solved my problem but making the ball collides twice gave me a KeyNotFoundException in NewtonPhysics.cs at

        /// <summary>
        /// Gets the velocity of an IPhysicsObject.
        /// </summary>
        /// <param name="physObj">The physics object to get velocity</param>
        /// <returns>A velocity vector</returns>
        public Vector3 GetVelocity(IPhysicsObject physObj)
{
float[] speed = new float[3];
Newton.NewtonBodyGetVelocity(objectIDs[physObj], speed); <- (this is where the exception is detected)
return new Vector3(speed[0], speed[1], speed[2]);
}

How can I move my objects to its original place with its original physics values, something like a reset function?

Thanks,

Emerson

Coordinator
Nov 10, 2009 at 9:55 PM

Hi Emerson,

You're doing right to call RestartSimulation() to reset the physics simulation.

However, the problem is that in RestartSimulation(), it removes all of the physics object from the engine, and re-add them back to the engine with initial values. 

It is possible that GetVelocity (I guess you're calling this somewhere in your code?) is called while things and removed from the engine, and not re-added back to the engine yet, so it can't find the key in the engine yet. Update and Draw functions are in separate thread, so this kind of problem can happen.

What you should do is to make sure that you don't call GetVelocity while the physics engine is restarting. This can be done by using a semaphore around RestartSimulation() code. Another way is to simply try and catch your code that calls GetVelocity method. In this case, I believe it's in the GetSpeed method of RaceCar.cs if you didn't change it much.

Ohan

Nov 12, 2009 at 5:48 PM

Hi Ohan,

 

Since I didn't change much tutorial 12, I believe SetTireTorque and SetSteering in Draw function, which calls GetSpeed method, may be called before RestartSimulation() finishes re-adding all physics objects back to the engine. However, I'm not familiar with try/catch or semaphores so I'm not sure how to use them in the code to avoid the problem. I tried something like this:

public float GetSpeed()
        {
            try
            {
                return Vector3.Dot(this.PhysicsWorldTransform.Forward, engine.GetVelocity(this));
            }
            catch (KeyNotFoundException)
            {
            }
        }

And Visual Studio gives me this error:

'Sistema_de_controle.Robot.GetSpeed()': not all code paths return a value

Forgot to mention that I'm mixing elements from Tutorial 8 and Tutorial 12, therefore, on CreateObjects() I created a collision pair and a collision callback function to be called when two objects collides, which is the

private void GoalSphereCollision2(NewtonPhysics.CollisionPair goalsphere2)

This function is similar to the one used in Tutorial 8, called when the the sphere and box model collides, but instead of just writting a message on the console, I'm also calling RestartsSimulation(). That's what I'm using from Tutorial 8. As for Tutorial 12, my Draw function verifies if I'm pressing Up or Down arrow from keyboard to set values for SetSteering and SetTireTorque. I think this is what causes the KeyNotFoundException. Probably while things are being re-added to the engine, the Draw function is trying to get speed values from SetSteering and SetTireTorque which are not in the engine yet. I just don't know how to isolate RestartsSimulation() so it can re-add everything to the engine before Draw function gets in.

Thanks

Emerson

Coordinator
Nov 12, 2009 at 6:21 PM

GetSpeed() needs a return value, but you don't have a return when exception is caught, so simply add "return 0;" statement in your catch close.

Ohan

Nov 13, 2009 at 2:03 PM

Hi Ohan,

Thanks.

It's sort of working now. But after a few tests with the program its FPS drops from 50 to 7, and runs like in a slow motion video, it's as if something is missing. I'll test some more to see if I get an error from visual studio.

Emerson

Coordinator
Nov 15, 2009 at 5:49 AM

Hi Emerson,

Hmm... I don't know what's the cause of the frame drops since I haven't experienced it yet. It'll be great if you could figure out what's causing that, and I can probably try to fix that if there is a problem in Goblin.

Ohan

Nov 22, 2009 at 6:06 AM
Edited Nov 22, 2009 at 10:20 PM

Hi Ohan,

I`ve added a semaphore and resolved the problem.

Now I would like to know how can I change a model during gameplay, for example, based on the code posted at the beginning of this topic for the VehicleCreator class where I've added the p1_wedge model for the car, which steps should I take to change from the ship model to another model without having to quit the game? I was thinking about using the radio button component from 2D GUI to select the models. If a radio button is selected then a new model should appear immediately.

 

Thanks,

 

Emerson

Coordinator
Nov 23, 2009 at 3:44 PM

If you simply want to have a different "look", it's better to create another RaceCar object that contains different set of models, and switch between those different RaceCar based on your radio button input. I didn't expect people to switch the car model, so it may not work if you simply switch the Model property to something else. It may render correct, but the new physical properties may not get correctly propagated to the physics engine.

 

Ohan

Nov 16, 2010 at 7:41 PM
emersonmk wrote:

Hi Ohan,

I`ve added a semaphore and resolved the problem.

Now I would like to know how can I change a model during gameplay, for example, based on the code posted at the beginning of this topic for the VehicleCreator class where I've added the p1_wedge model for the car, which steps should I take to change from the ship model to another model without having to quit the game? I was thinking about using the radio button component from 2D GUI to select the models. If a radio button is selected then a new model should appear immediately.

 

Thanks,

 

Emerson

I am having a similar problem with fps and physics callbacks. How did you fix this with a semaphore?