Page 2 of 3

Re: Beginner desperately needs help:)

Posted: Sun Apr 15, 2012 11:38 pm
by Norbo
XNA game components are just classes with an update method (and, in the case of DrawableGameComponents, a draw method) called by the game. They aren't required at all, and they don't get in the way of the internals of the component. The XNA website samples would be a good place to start on this sort of thing- conquering the complexity of the API, graphics, and physics separately might help clear things up.

If EntityModel is the EntityModel from the BasicSetupDemo, then in the Draw method there is this line:

Code: Select all

            Matrix worldMatrix = Transform * entity.WorldTransform;
The Transform used by the EntityModel does indeed act as a local transform.
But it doesn't work.
In what way does it fail?

Re: Beginner desperately needs help:)

Posted: Mon Apr 16, 2012 2:29 am
by ole_92
So sorry, it actually does work :/ Don't know what was wrong with is.
Thanks, I'm fine for now, I might post some questions later

Re: Beginner desperately needs help:)

Posted: Mon Apr 16, 2012 11:19 am
by ole_92
Are there any demos/tutorials on how to enable "picking objects up"?
I can get entities out of the space, and keep them in front of camera while pressing a button, but how would I get the specific one I'm looking at?
First I would probably check if it's close enough to the character, but how do I calculate if I'm actually looking at it?
I imagine it has something to do with the camera orientation quaternion and vector subtraction, but I have no idea how to implement that.
This isn't very related to the physics engine, but just in case you know...
Thanks!

Re: Beginner desperately needs help:)

Posted: Mon Apr 16, 2012 12:13 pm
by ole_92
Never mind, I've already figured it out!
Here's the code that I'm using, just in case someone finds it useful

Code: Select all

ray.Position = cci.CharacterController.Body.Position;
            ray.Direction = Vector3.Normalize(cci.Camera.WorldMatrix.Forward);

            for (int i = 0; i < space.Entities.Count; i++)
            {
                if ((string)space.Entities[i].Tag == "pickupable") 
                {
                    if (ray.Intersects(space.Entities[i].CollisionInformation.BoundingBox) <= 50)
                        if (((Game1)Game).MouseInput.LeftButton == ButtonState.Pressed)
                        {
                            Vector3 pos = cci.CharacterController.Body.Position;

                            space.Entities[i].LinearVelocity = cci.Camera.WorldMatrix.Forward * 50;
                            space.Entities[i].AngularVelocity = Vector3.Zero;
                            space.Entities[i].Position = pos + cci.Camera.WorldMatrix.Forward * 20.0f;

                            // breaking out of the loop
                            i = space.Entities.Count;
                        }
                }

            }

Re: Beginner desperately needs help:)

Posted: Mon Apr 16, 2012 2:49 pm
by ole_92
Ok, just a minor issue here.
When I'm holding an entity in front of me, and rotate the camera with a mouse, the entity follows correctly, but its movement is a little "buggy" and not smooth at all.
It's weird because when I "move" with keyboard keys, the entity follows very nicely and smoothly.

I've noticed, that in demos, MotorizedGrabSpring and LineDisplayObjectBase are used.
Is it possible to fix the problem and not use them? Or is it a bad idea?

Re: Beginner desperately needs help:)

Posted: Mon Apr 16, 2012 3:02 pm
by Norbo
That can work, but it can be accelerated by using a Space.RayCast.

The RayCast queries the broad phase acceleration structure (Space.BroadPhase.QueryAccelerator) to find intersected bounding boxes. It then goes through the BroadPhaseEntry objects it detected from the broad phase and performs a narrow ray cast against them (if they are accepted by the RayCast filter, if one is specified). Since it only tests objects identiifed by the query accelerator, this is very fast.

There are multiple overloads of the Space.RayCast function. Some return multiple hits, some return the first hit. Some have a filter. Some have a maximum length, others have implicitly infinite length.

The ray cast returns whether or not the ray hit anything. It also has has parameters which output the hit data. This includes location, normal, T value (distance along the ray in terms of the ray direction's length), and the BroadPhaseEntry object which was hit.

StaticMeshes, Terrains, InstancedMeshes, and EntityCollidables all inherit from BroadPhaseEntry and live in the BroadPhase. So, the ray cast can hit them. Since your goal is to pick an object up, you're looking for entities. If the BroadPhaseEntry found by the ray cast is an EntityCollidable, cast it and check the EntityCollidable's Entity property to find the entity.

You can also use tags to do this. The BroadPhaseEntry has a Tag property which is separate from the Entity Tag property. Instead of doing the cast first, you could check the BroadPhaseEntry's Tag to see if it's a pickupable object before attempting to find the entity. Since the entity.CollisionInformation property returns the EntityCollidable associated with the entity, the entity.CollisionInformation.Tag is what would need to be set for this purpose.
When I'm holding an entity in front of me, and rotate the camera with a mouse, the entity follows correctly, but its movement is a little "buggy" and not smooth at all.
It's weird because when I "move" with keyboard keys, the entity follows very nicely and smoothly.
I'd guess this is a byproduct of the particular way the velocity is being controlled.

First, it's being teleported. This is a dangerous operation as an object which is teleported can teleport into things without resistance. Only the post-overlap penetration resolution system will fight back, and it's not rigid. It can work, but the less physical interaction between a teleporting object and its environment, the better. It might be good to set the collision rule of the box such that it cannot collide while held to avoid this (though then you must handle the case where the object can be effortlessly stuck through walls still, to stop players from just tossing objects into the void or whatever else). This is probably not at fault for the unsmoothness, but it is something to be aware of.

Second, the velocity does not match the motion of the character. The linear velocity is always shooting directly forwards despite it being held with teleportation. A held object should have a velocity matching its position relative to the character. That is, if the character isn't turning, the held object's linear velocity should be the character's linear velocity. If the character is turning, then there will be a secondary component to the velocity from the angular motion. Determining the position goal and then computing the exact velocity needed to match the change in position is a good way to handle this. (velocity = frameOffset / dt;)

Using a more physical approach like the MotorizedGrabSpring avoids most special cases. However, don't get stuck on the idea that it's the MotorizedGrabSpring or nothing; there are many options out there (and the LineDisplayObjectBase is just another visualization tool, not a necessary physical object).

Re: Beginner desperately needs help:)

Posted: Tue Apr 17, 2012 12:55 am
by ole_92
I attempted to use space.RayCast, but the result that it returns(RayCastResult), doesn't store the information about which space entity it is. So, basically I'd be searching through the whole space to find the thing that was just detected...
Instead, I just added this check up the top:

Code: Select all

if (space.RayCast(ray, 50, out rcr))
, so processing will only happen if something is within 50 units of camera, and only until the pickupable thing is found. That's efficient enough for me. If you have a better suggestion, please let me know so I can try it out!

Now, thanks for the hint about modifying entity's velocity rather than position itself. This works really well,

Code: Select all

Vector3 goalpos = cci.Camera.Position + cci.Camera.WorldMatrix.Forward * 25.0f;
space.Entities[picking].LinearVelocity = (goalpos - space.Entities[picking].Position) * 15;
... but yes, it can still go through the walls, which is undesirable.

What I'm thinking, is that if the goal position is intersecting with any geometry in the space (except object itself), then don't reset it this update. That way, the object will keep moving towards the previous valid goal. Do you have any hints about this?

Thanks

Re: Beginner desperately needs help:)

Posted: Tue Apr 17, 2012 1:10 am
by ole_92
Just realized it will not work if the goal is on the other side of the geometry - it will just move straight through it.
It might be good to set the collision rule of the box such that it cannot collide while held to avoid this
How can I do that?

Re: Beginner desperately needs help:)

Posted: Tue Apr 17, 2012 1:48 am
by Norbo
I attempted to use space.RayCast, but the result that it returns(RayCastResult), doesn't store the information about which space entity it is.
The RayCastResult does contain which object it hit in the HitObject field. It is a BroadPhaseEntry. Each entity has a entity.CollisionInformation which returns an EntityCollidable, which inherits from BroadPhaseEntry. That EntityCollidable is the entity's proxy in the collision detection pipeline that the ray cast sees. The associated Entity can be grabbed from it; read the first section of my previous post for more information.
How can I do that?
One option would be to set the entity.CollisionInformation.CollisionRules.Personal = CollisionRule.NoBroadPhase. Keep in mind this still lets you push things through walls (in fact, it becomes trivially easy because it doesn't collide with anything).
What I'm thinking, is that if the goal position is intersecting with any geometry in the space (except object itself), then don't reset it this update. That way, the object will keep moving towards the previous valid goal. Do you have any hints about this?
I'd stick to one of two main options:

1) The picked up object no longer exists in the physical world. It is either respawned in a guaranteed safe-spot when dropped, or use explicit queries to ensure it never enters an invalid state. Modern iterations of 'pickup' mechanics in Source games (e.g. Portal 2) seem to use convex casts to to position the picked-up object in front of the character, drawing it closer if there's a wall or obstruction in the way. You can do this with the BroadPhaseEntry's support for ConvexCasts. Gather up the nearby objects with space.BroadPhase.QueryAccelerator query, convex cast each of them, position the object with the earliest hit. If the held object is not convex, use a proxy convex object which contains the picked up object.

2) Hold the object with something physical, perhaps resembling the grab constraint. If the grabber is too strong, weaken the grabber motors a bit (reduce stiffness and damping constants). This is the easiest approach and is quite robust with little tuning.

Trying to do intermediate hacks usually ends up with some nasty results.

Re: Beginner desperately needs help:)

Posted: Tue Apr 17, 2012 2:24 am
by ole_92
Both seem quite hard, but I''ll have a go with the grabber approach, and see what happens. Thanks!

Re: Beginner desperately needs help:)

Posted: Sat Apr 21, 2012 12:34 pm
by ole_92
Ok, I've got a really stupid question: how can I alter the scale of dynamic objects?
Here's the code I use to create them:

Code: Select all

public void addDynamic(string modelName, float mass, Vector3 position) {

            Model temp = ((Game1)Game).Content.Load<Model>("Models/" + modelName);
            Vector3[] vertices;
            int[] indices;

            TriangleMesh.GetVerticesAndIndicesFromModel(temp, out vertices, out indices);

            ConvexHull ch = new ConvexHull(vertices, mass);
            
            EntityModel entMod = new EntityModel(ch, temp, Matrix.CreateTranslation(-ch.Position), ((Game1)Game));
            ((Game1)Game).Components.Add(entMod);
            
            ch.Position = position;
            ch.Tag = modelName;
            space.Add(ch);
        }
I tried to alter the entMod.Transform, but it's only responsible for graphics. I also tried to do this:

Code: Select all

ch.WorldTransform *= Matrix.CreateScale(2);
, but it doesn't seem to do anything.
The reason I'm doing this, is that collision detection against small items (like a key or a match box) is really bad, and it just goes through the floor sometimes. So, I increased the size of actual models, and I want to scale them down in the actual game, perhaps that will make it better.

Thanks

Re: Beginner desperately needs help:)

Posted: Sat Apr 21, 2012 2:39 pm
by ole_92
I've searched in the forums, and apparently, it's possible to accomplish that by using TransformableShape?
I've spent hours trying to figure out how to do that, but I'm still stuck.
I would probably do this first:

Code: Select all

ConvexHullShape chs = new ConvexHullShape(vertices);
         TransformableShape ts = new TransformableShape(chs, Matrix3X3.CreateScale(scale.X));
But then I still need a ConvexHull to add to the space!

Re: Beginner desperately needs help:)

Posted: Sat Apr 21, 2012 3:49 pm
by Norbo
how can I alter the scale of dynamic objects?
Most shapes have settable properties, like a box's Width, Length, and Height. ConvexHullShapes are not easily transformed since they just have a local vertex list. Putting a ConvexHullShape into a TransformableShape and using that TransformableShape to construct an entity is the easiest approach for convex hulls. Check out the EntityConstructionDemo in the BEPUphysicsDemos for an example of how to do this, but read the rest of the post before going down that road.
I also tried to do this:
ch.WorldTransform *= Matrix.CreateScale(2);
, but it doesn't seem to do anything.
An entity's world transform can only contain a rigid transform. This means it contains a position and orientation. Attempting to assign a transformation which contains other components, such as scale, will be decomposed into position and orientation. The 'extra' components could cause the position and orientation to be incorrect.
The reason I'm doing this, is that collision detection against small items (like a key or a match box) is really bad, and it just goes through the floor sometimes. So, I increased the size of actual models, and I want to scale them down in the actual game, perhaps that will make it better.
The following assumes that this is truly related to objects which are too small. If you'd like me to verify that the problem is related, recreate a tiny isolated portion of the simulation including one of the too-small objects that has the problem in a BEPUphysicsDemo. I'll copy the code and take a look to make sure the problem is what it appears to be. (Attempting to fix a problem which isn't the real problem is, historically, ineffective :))

Increasing the model size and then re-shrinking it after the fact will not help if it is reduced all the way back down to a size which is too tiny; the engine only cares about the final state of the simulation shape.

The problem you're encountering is a set of tuning factors designed for larger scales. I would recommend first making these tiny objects as large as possible. If the graphics look silly being too large, keep the graphics the same and just increase the size of the physics to a reasonable maximum. If the problem still happens at that point, you can look into adjusting the tuning factors to tell the engine to work with smaller scales.

To do this, check out the ScaleDemo and ConfigurationHelper in the BEPUphysicsDemos. While your game doesn't sound like everything needs to be rescaled, telling the engine to shrink its perspective down a bit by calling ConfigurationHelper.ApplyScale(scale); for some value of scale below 1 will let the collision detection system pick better values. You may also want to only use the portion of the ApplyScale method which modifies the CollisionDetectionSettings only, since the CollisionResponseSettings might not need to be changed at all.

Re: Beginner desperately needs help:)

Posted: Sat Apr 21, 2012 8:27 pm
by ole_92
Increasing the model size and then re-shrinking it after the fact will not help if it is reduced all the way back down to a size which is too tiny; the engine only cares about the final state of the simulation shape.
Oh, ok. That sounds awfully correct - I don't know why I hesitated.

Code: Select all

ConfigurationHelper.ApplyScale(28);
... solved my problem, and 28 is the lowest value that works! Thank you!

Just got one more question right now - is it possible to get the CharacterController to "crawl"? Or is it just a matter of reducing the crouching height?

Re: Beginner desperately needs help:)

Posted: Sat Apr 21, 2012 8:46 pm
by ole_92
Yeah, I think it's better to adjust the crouch height - also easier for the player (less keys need to be pressed)