Movement and Drawing

Discuss any questions about BEPUphysics or problems encountered.
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Movement and Drawing

Post by NCreation »

Though the documentation seems very precise on the different types of entities and whatnot, it does not explain how to initialize, draw, or call any of these methods. I looked at the Demo Source Code, but found there to be too much extra info to sort out. Wouldn't it be better if the demo's were split up, with simpler implementations of each method?

Anyways, I'm trying to make a first-person camera move on a "level" or "map". This map has lots of varying types of geometry. I created a statictriangle group from my map like this:

Code: Select all

map = Content.Load<Model>("Models\\Maps\\map13ds");
mapTexture = Content.Load<Texture2D>("Models\\Textures\\blank");
StaticTriangleGroup mapGroup = new StaticTriangleGroup(.5f, 1, 0, 0, .4f, 0);
mapGroup.initializeData(map);
mapGroup.friction = .6f;
space.add(mapGroup);
mapGroup.worldMatrix = Matrix.CreateFromYawPitchRoll(0, 0, 0);
and to Initialize the engine:

Code: Select all

space = new Space(new PersistentUniformGrid(10));
I just did that. Is there anything else I need for the initialization?

Now, my next step is to create a collision entity for the camera. Is there a particular way to do that that would be best?
And do you have to do anything special to draw the models on the screen?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

You can see a very barebones integration of BEPUphysics at http://www.bepu-games.com/forums/viewto ... 7&start=15; it uses a separate thread to call space.update though it's still very simple.

What you have there is all you really need for the initialization. You don't technically need to assign the worldMatrix (it defaults to the identity anyway), and the friction is defined in the constructor of the group so you don't need to redefine it. The demos included that second definition accidentally and it has been removed. Call space.update from your update method and the physics will work.

You can draw your model any way you'd like. A simple way is to just use the model's basic effects (you can see an example in both the demos DisplayModel and the physicsthread demo's EntityModel). It will match your collision mesh if you set the effects' world matrices appropriately.

If you just want a free-flying camera as opposed to a character, you could most easily use a a floating, physically simulated sphere. Every frame, move the camera to the position of the sphere. Set its isAffectedByGravity flag to false so that it doesn't fall and then control its motion with keyboard input. From there, you can fine tune its behavior by modifying its velocity appropriately.

If you want a character, check out the CharacterController and CharacterControllerInput classes of the demos. It's basically the same idea as the above (moving the camera to an entity and controlling the entity's motion), but the character controller does a lot of the heavy lifting of movement calculations.
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

Ok, i got it kinda working. (I haven't implemented the camera yet though). So far i have this:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Threading;
using BEPUphysics;
using System.Diagnostics;

namespace AG_DMT
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Space space;
        Box box;
        Model boxModel;
        Model map;
        Texture2D mapTexture;
        Vector3 mapPosition = Vector3.Zero;
        Player p1;
        GamePadState oldGamePadState = GamePad.GetState(PlayerIndex.One);
        EntityModel boxEntity;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";            
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
                        
            base.Initialize();
        }

        protected void StartPhysicsEng()
        {

            space = new Space(new PersistentUniformGrid(10));
            //general settings (grav, etc) OMITTED see demo_source/current location for all settings default assigns

        }               


        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            p1 = new Player(1, new Vector3(0, 2, -10), new Vector3(0, 0, 1), graphics, Content.Load<Model>("Models\\Characters\\player_bounding"));

            StartPhysicsEng();   //Init physics engine space

            #region LoadMap
            map = Content.Load<Model>("Models\\Maps\\map13ds");
            mapTexture = Content.Load<Texture2D>("Models\\Textures\\blank");
            StaticTriangleGroup mapGroup = new StaticTriangleGroup(.5f, 1, 0, 0, .4f, 0);
            mapGroup.initializeData(map);
            mapGroup.friction = .6f;
            space.add(mapGroup);            
            #endregion            
            
            #region boxtest
            boxModel = Content.Load<Model>("Models\\Characters\\player_bounding");                        
            Box box = new Box(new Vector3(0, 50, 0), 20, 20, 20);
            space.add(box);
            EntityModel boxEntity = new EntityModel(box, boxModel, Matrix.CreateScale(box.width, box.height, box.length), this);
            Components.Add(boxEntity);
            #endregion


        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            //update player cameras
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            p1.UpdateMovement(gamePadState, oldGamePadState);
            p1.UpdateCamera(graphics);

            physicsLoop(gameTime);

            base.Update(gameTime);
        }

        void physicsLoop(GameTime gameTime)
        {
            
                space.update(gameTime);                
            
        }

        void DrawModel(Model model, Matrix world, Texture2D texture)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect be in mesh.Effects)
                {
                    be.EnableDefaultLighting();
                    be.PreferPerPixelLighting = true;                                        
                    be.Projection = p1.cProj;
                    be.View = p1.cView;
                    be.World = world;
                    be.Texture = texture;
                    be.TextureEnabled = true;
                }
                mesh.Draw();
            }
        }
        
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            DrawModel(map, Matrix.Identity, mapTexture);

            boxEntity.Draw(gameTime, p1.cView, p1.cProj);

            base.Draw(gameTime);
        }
    }
}
I'm also using a the EntityModel class from the example you sent me. I modified the Draw method though:

Code: Select all

public void Draw(GameTime gameTime, Matrix view, Matrix proj)
        {
            Matrix worldMatrix = transform * entity.orientationMatrix * Matrix.CreateTranslation(entity.centerPosition);

            model.CopyAbsoluteBoneTransformsTo(transforms);
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = transforms[mesh.ParentBone.Index] * worldMatrix;
                    effect.View = view;
                    effect.Projection = proj;
                }
                mesh.Draw();
            }
            base.Draw(gameTime);
        }
Now, whenever I compile, I get a message saying boxEntity not set to instance of object. Am I doing something wrong here? Maybe something to do with the drawablegamecomponent thing?

Sry if i'm missing something obvious. This is just my first time working with physics wrappers.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

Right now, the boxEntity.draw in your draw method is referring to the member variable boxEntity. However, in initialization, you created a method scope variable called boxEntity which hid the member variable. When you set it to something, it only set the local scope variable and not the member variable.

That said, you can safely get rid of your member variable boxEntity (unless you wanted to refer to it later specifically), because when you add it to the game components the draw method's base.Draw calls the draw method of all components as well. You don't need to call draw for that component manually.

Edit: just noticed the modification to the entitymodel draw method; since that doesn't override the Draw method of the DrawableGameComponent, it won't draw anything. You'll have to change it back to the previous override or call it manually like you were trying to do. If you call it manually, there's no real point for the EntityModel to be a DrawableGameComponent and you don't need to add it to the components.
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

ok, i removed the declarations for the box and entity. I removed the entity.draw too. I modified the EntityModel method so that it uses my camera's projection and view matrices (basically i just added a few more parameters)
Now I'm not seeing anything. just my map.

New EntityModel Class:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BEPUphysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace AG_DMT
{
    /// <summary>
    /// Component that draws a model following the position and orientation of a BEPUphysics entity.
    /// </summary>
    public class EntityModel : DrawableGameComponent
    {
        Entity entity;
        Model model;
        /// <summary>
        /// Base transformation to apply to the model before moving to the entity.
        /// </summary>
        public Matrix transform;
        Matrix[] transforms;
        Matrix view;
        Matrix proj;


        /// <summary>
        /// Creates a new EntityModel.
        /// </summary>
        /// <param name="entity">Entity to attach the graphical representation to.</param>
        /// <param name="model">Graphical representation to use for the entity.</param>
        /// <param name="transform">Base transformation to apply to the model before moving to the entity.</param>
        /// <param name="game">Game to which this component will belong.</param>
        public EntityModel(Entity entity, Model model, Matrix transform, Game game, Matrix view, Matrix proj)
            : base(game)
        {
            this.entity = entity;
            this.model = model;
            this.transform = transform;
            this.view = view;
            this.proj = proj;

            transforms = new Matrix[model.Bones.Count];
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                }
            }
        }

        public void Draw(GameTime gameTime)
        {
            Matrix worldMatrix = transform * entity.orientationMatrix * Matrix.CreateTranslation(entity.centerPosition);

            model.CopyAbsoluteBoneTransformsTo(transforms);
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = transforms[mesh.ParentBone.Index] * worldMatrix;
                    effect.View = view;
                    effect.Projection = proj;
                }
                mesh.Draw();
            }
            base.Draw(gameTime);
        }
    }
}
and the modified game1.cs:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Threading;
using BEPUphysics;
using System.Diagnostics;

namespace AG_DMT
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Space space;
        Model boxModel;
        Model map;
        Texture2D mapTexture;
        Vector3 mapPosition = Vector3.Zero;
        Player p1;
        GamePadState oldGamePadState = GamePad.GetState(PlayerIndex.One);
        
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";            
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
                        
            base.Initialize();
        }

        protected void StartPhysicsEng()
        {

            space = new Space(new PersistentUniformGrid(10));
            //general settings (grav, etc) OMITTED see demo_source/current location for all settings default assigns

        }               


        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            p1 = new Player(1, new Vector3(0, 2, -10), new Vector3(0, 0, 1), graphics, Content.Load<Model>("Models\\Characters\\player_bounding"));

            StartPhysicsEng();   //Init physics engine space

            #region LoadMap
            map = Content.Load<Model>("Models\\Maps\\map13ds");
            mapTexture = Content.Load<Texture2D>("Models\\Textures\\blank");
            StaticTriangleGroup mapGroup = new StaticTriangleGroup(.5f, 1, 0, 0, .4f, 0);
            mapGroup.initializeData(map);
            mapGroup.friction = .6f;
            space.add(mapGroup);            
            #endregion            
            
            #region boxtest
            boxModel = Content.Load<Model>("Models\\Characters\\player_bounding");                        
            Box box = new Box(new Vector3(0, 50, 0), 20, 20, 20);
            space.add(box);
            EntityModel boxEntity = new EntityModel(box, boxModel, Matrix.CreateScale(box.width, box.height, box.length), this, p1.cView, p1.cProj);
            Components.Add(boxEntity);
            #endregion


        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            //update player cameras
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            p1.UpdateMovement(gamePadState, oldGamePadState);
            p1.UpdateCamera(graphics);

            physicsLoop(gameTime);

            base.Update(gameTime);
        }

        void physicsLoop(GameTime gameTime)
        {
            
                space.update(gameTime);                
            
        }

        void DrawModel(Model model, Matrix world, Texture2D texture)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect be in mesh.Effects)
                {
                    be.EnableDefaultLighting();
                    be.PreferPerPixelLighting = true;                                        
                    be.Projection = p1.cProj;
                    be.View = p1.cView;
                    be.World = world;
                    be.Texture = texture;
                    be.TextureEnabled = true;
                }
                mesh.Draw();
            }
        }
        
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            DrawModel(map, Matrix.Identity, mapTexture);
            
            base.Draw(gameTime);
        }
    }
}
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

So, what happens to the parameters if its called automatically every base.draw?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

One second, taking a closer look- got a little mixed up.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

Make sure to put the override keyword on the entitymodel draw method. Without it, it just hides the method but the game class still calls the superclass's version (which draws nothing). Your current parameter passing in the EntityModel should be ok at a glance.
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

But if the view and projection matrices aren't updated every loop or so, the box is drawn always in front of the camera. Since I didn't declare a Variable for the EntityModel, there seems to be no way to call an update method
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

eh, ill just re-write it without all the fancy components stuff
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

In the original PhysicsThread EntityModel, you can see how I did it. Components have a reference to the game they belong to, so you can update anything in the game however you'd like and grab it from the components.
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

My cube is falling onto the level mesh, but once it hits it kinda rolls and turns a little, then the entire program just freezes. I have to click the stop debugging button to shut it down. Is there something that causes this?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

Could you give me (through email, PM, or just on the forums) the latest source/level mesh so I could test it out? Only thing I could think of is something with the geometry in the level, but I don't think I've seen the engine cause a similar crash.
NCreation
Posts: 11
Joined: Fri Jan 02, 2009 12:22 am

Re: Movement and Drawing

Post by NCreation »

http://www.fileden.com/files/2007/5/29/ ... AG_DMT.zip

the namespace is AG_DMT

Thanks for the help, i really appreciate it
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Movement and Drawing

Post by Norbo »

Everything you are doing on the code side seems fine. I switched out your map for the playground.fbx from the demos and it works.

The original map was too large, which causes significant robustness issues with collision detection. It's a good idea to keep to sizes near one (on a similar order of magnitude, between .2 and 50 or something). However, even when scaling it down, there were still issues. I would recommend using a different program/exporter. If it still doesn't work, try using a content processor to extract vertex data from a model rather than giving a model to the initializeData method. A discussion/example of this can be found on the forum: http://www.bepu-games.com/forums/viewto ... +processor
Post Reply