Stupid Questions Thread from Zammy

Nov 6, 2008 at 8:32 PM
Hello

My name is Evgeni and I am from Bulgaria. Student in Computer Science junior year.
I am leader in 4 students team. We are going to build a 3D game to compete in ImagineCup.
I have been playing with XNA for over an year now but not much with 3D.
For me it is pretty complicated how many things you need to do simple stuff in 3d.
I want to say that I love the way XEN is structured and I hope we will be able to build neat game on top of it.
In this thread I am going to ask questions for people involved in XEN and (UnknownStatus in particular).
They might be pretty stupid but you must understand that I am learning now and its fuzzy what is going on behind the scenes.

Here goes with questions:
  • What excatlly do I need to perform in CullTest() when drawing? Check if the object is inside the camera frustrum?
  • What does shader.bind() does?
  • I have created a cube (with vertices) and now I want to put texture on them.
    • My ultimate goal is to simulate the effect of normal mapping from chapter 14 but on a cube
    • So how to set the texture correctly and how to set the normals and binormals correctly so when I shine it from different sides to get specular shine effect.
Coordinator
Nov 7, 2008 at 3:03 AM
Edited Nov 16, 2008 at 8:57 PM
  • What excatlly do I need to perform in CullTest() when drawing? Check if the object is inside the camera frustrum

Yes. The idea is that high level drawing code looks like this:

if (item.CullTest(state))
{

   //possible other logic (eg, setting up shaders)

    item.Draw(state);

}

So the CullTest method should return true when the object should be drawn. This usually means the object is on screen, but it doesn't have to - if your object has a 'IsVisible' property, then CullTest could return false when IsVisible is false.

To perform frustum culling, then you use the ICuller to call the culling methods you wish. The ICuller knows the current world matrix and frustum.

So (for example) if your geometry is a sphere of radius 10.0, centred at 0,0,0, then you would use a call to culler.TestSphere(10.0f). This will perform a frustum test with a sphere at the current world matrix coordinates. It will return false if the sphere is off screen. Other cases get more complex, of course.

To test your culling is working correctly, tutorial 16 shows how to 'pause' updating the frustum cull planes. This lets you look around, while not updating the culling process. This will show up any objects that are not getting culled properly. (It's quite hard to describe)

Note that it is assumed that the world matrix will not be modified between the call to CullTest() and Draw(). All your objects should take this int account.

Eg: The following would be very bad:

if (object.CullTest(state))

{

  state.PushWorldMatrix(...);

  object.Draw(state);

  state.PopWorldMatrix();
}

This would be bad, because CullTest would be using a different world matrix to draw - so the test could easily be incorrect.

A similar situation, what should never happen is:

if (this.CullTest(state))
{

   item.Draw(state);
}

The reason for this, is that CullTest is intended to be called by the parent class, not by a class itself. You don't want to call this.CullTest() in the Draw() method, because the parent object should have already called CullTest for you. You always want to call if (child.CullTest()) { ... child.Draw() }.

I'm sorry about this confusion. It's both complex yet simple at the same time, and I realise I haven't explained it very well in the tutorials.

  • What does shader.bind() does?

On modern shader driven videos cards, at any point a valid vertex and pixel shader must be 'bound'. This means the shader is in use / active.

Any geometry drawn will use the currently bound vertex/pixel shaders when drawing. There must be a vertex and pixel shader bound when drawing something - this isn't optional.

Because of this, the way shaders work in xen is you simply 'bind' them. Once bound, it stays bound - until a different shader is bound.

Effects in XNA have BeginEffect()/EndEffect(), BeginPass(), etc. These have nothing to do with how the hardware works internally, it's just a design requirement of Effects. If you do a Begin()/End() block with an effect, then the vertex and pixel shaders used by that effect will still be bound afterwards.

So, if you want to use a shader to draw something, Bind() it first!

  • I have created a cube (with vertices) and now I want to put texture on them.

To use a texture, you need a shader to display the texture first. (I just realised this is not covered by the turorials :)

In that shader file, you need to declare the texture. AND you need to declare a sampler for that texture.

For example (in a shader):

   texture2D CustomTexture;

This declares the texture.

  sampler2D CustomTextureSampler = sampler_state
{
Texture = (CustomTexture);
};

This declares the sampler. Note the line 'Texture = CustomTexture'. This states that the sampler is reading from the texture declared above.

Then, in pixel shader, you can read the texture:

Given a texture coordinate input (eg, float2 texCoord0 : TEXCOORD0)

   float4 textureSample = tex2D(CustomTextureSampler, texCoord0);

Note that the texture is 'sampled' through the texture sampler.

Now, in your C# code, the Shader class generated for you (by the plugin - see tutorial 3) will now have a Texture2D CustomTexture property, and a TextureSamplerState CustomTextureSampler property. You can modify these as you like.

Setting the normals and binormals is just like setting texture coordinates. Add a 'normal' to your vertex structure, add a 'binormal' as well (You may also want a tangent). Set the values up in your vertex data arrays, and the values should copy over fine.

eg:

struct MyVertex
{

   Vector3 position, normal, binormal;

   Vector2 texCoord0;
}

I hope that helps.

Nov 18, 2008 at 11:43 AM
Thank you for the great answer!
I meant to answer you much earlier with a follow up but never got the time to work on it and now we have shift of priorities.

Nov 18, 2008 at 9:23 PM
Edited Nov 18, 2008 at 9:44 PM
We had shift in priorities. Due to deadline looming near we decided to implement the game mechanics and AI before spend any time on physics and graphics.
So I want to make the game work with spheres, cubes and alike. I want to each of  these primitives to attach a small text window to display state info changes and debug info.
I am having some problems with making this work for unknown for some reason.

I first initialize the TextElementRect

//IInfo settings
            textRectangle = new Xen.Ex.Graphics2D.TextElementRect(new Vector2(150, 100));
            textRectangle.TextHorizontalAlignment = Xen.Ex.Graphics2D.TextHorizontalAlignment.Left;
            textRectangle.TextVerticalAlignment = Xen.Ex.Graphics2D.VerticalAlignment.Top;
            textRectangle.Colour = Color.Yellow;

Here is where I update the position of the TextElementRect instance:
           Vector3 scale;
            Quaternion rotation;
            Vector3 translate;
            worldMatrix.Decompose(out scale, out rotation, out translate);
 
            Vector2 pos = new Vector2(Engine.SCREEN_WIDTH / 2, Engine.SCREEN_HEIGHT / 2);
            Vector3 differenceFromCameraPosition = Engine.Camera.Position - translate;
            pos.X += differenceFromCameraPosition.X;
            pos.Y += differenceFromCameraPosition.Y - 100;
 
            textRectangle.Position = pos;


Here is how I draw it:
            state.PushWorldMatrix(ref worldMatrix);
 
            if (sphere.CullTest(state))
            {
                shader.Bind(state);
 
                sphere.Draw(state);
 
                state.PopWorldMatrix();
 
                state.PushWorldTranslateMultiply(new Vector3(textRectangle.Position,0));
 
                textRectangle.Draw(state);
            }
 
            state.PopWorldMatrix();
The position of the TextElementRect seems valid but it does not get drawn.
When I tried without setting the position it works. Then I tried adding to the position vector
by user input. It worked! But when I try to set the position straight with assignment it does not work.
Simply doesn't draw it.

Any hints and clues will be greatly appreciated!

Coordinator
Nov 18, 2008 at 10:04 PM

Hi. The Position of a text element (and any other element) directly effects where it is drawn (so you do not need to be setting the world matrix before you draw it).

Further, the Position is realitive to the alignment of the element (which you do not appear to be changing). For text, this defaults to the Top Left, so the top left is treated as 0,0. You probably want it to be Bottom Left. Because the position is realtive to the alignment (think of it as an offset) then when aligned to the top, a positive position on the Y axis, will move it up off screen.

Nov 18, 2008 at 11:18 PM
Thank you for the prompt answer! You are great man!

Worked like a charm!

Another question. I want to make the TextElementRect background color different so it can be seen as text box.
How would you recommend me to do so?

One more (sorry). I am having difficulty in devising mathematical solution to the main problem.
How to move the text on the screen (pixel wise) compared to the movement in 3d space of an object?
I started moving the text box with the same translate that the object has but they obviously do not map due to scale.
Then I used to multiply with the distance of the camera to the object   (I move objects only in x,y plane so Z to camera is the same for all objects).
This does not work either good although alleviates the problem.


Thank you very much for your answers!
Coordinator
Nov 18, 2008 at 11:38 PM

Hi. Setting a background colour is easy :-) but it's not quite what you might think.

Instead of using a TextElementRect, use a SolidColourElement. Use this in exactly the same way (just remember to set it's size).

Now, the fun bit, create the TextElementRect, and Add() it to the SolidColourElement. Elements can be added in a tree, so the text will become a child of the colour rect. You can either give it the same size as the parent, or be tricky and give it a size of 0,0 and set the horizontal and vertical scaling to FillToParentPlusSize. :-)

Currently there is no 'project' or 'unproject' ability in xen. This is something I've thought about once or twice, and is certainly something that needs to be in xen. So currently you cannot easily take a 3D coordinate, and convert it to a 2D screen coordinate.

When I do implement this, the code that does it will look something like this:

http://pastebin.com/m5c0a11db

(this should work correctly, as this is pretty much exactly what happens on the graphics card)

Nov 20, 2008 at 12:21 AM
Worked perfectly!
Follow up questions:
1. On line #17, is the W component of world position scale and if so,
why do we raise it on -1 power? To reverse the scale?

2. On lines #21 and #22 Why do we multiply X and Y with the reversed W component?
Do we get the coordinate in projection space ? (0,0) is in the middle of the screen ?
(-1,-1) , (1,1) are the corners ?

Thank you for the great answers! You are really helping out.

I have ordered 1000 pages book about real time rendering, I hope this process will be explained in detail there,
the translation between spaces.
Coordinator
Nov 20, 2008 at 11:55 PM
Edited Nov 20, 2008 at 11:56 PM

Hey. That's just a little bit of shotcut.

After a vertex is multiplied by the world*view*projection matrix (Although I multiply by both matrices separately, and just get the world position), it is then 'normalised to w'. In other words, it's divided by W.

The float4( ... ,1.0f) bit is because it's a homogenous 4x4 matrix: http://alumnus.caltech.edu/~woody/docs/3dmatrix.html

So really, the result is:

float4 result = mul(position,worldviewprojection);

float3 projected = result.xyz / result.w;

This is so things further away are smaller (size is inverse of distance).

xy then become the position in screen space (in -1,1 range, as you mention), and the z value is the 0-1 range value that is stored in the depth buffer.

Nov 21, 2008 at 5:58 PM
Edited Nov 21, 2008 at 6:18 PM
Thank you very much. It is much clear to me now.

I am sorry to be a bother but I have problems importing model data.

I have done one by one everything in chapter10 tutorial but I get this error.

On another topic:
Can XEN work with FBX files also?
How can I initialize mouse cursor?
Or should I make my own and just draw it each time depending X and Y of the mouse?


Microsoft.Xna.Framework.Content.ContentLoadException was unhandled
  Message="Error loading \"testcube\". File contains Microsoft.Xna.Framework.Graphics.Model but trying to load as Xen.Ex.Graphics.Content.ModelData."
  Source="Microsoft.Xna.Framework"
  StackTrace:
       at Microsoft.Xna.Framework.Content.ContentReader.InvokeReader[T](ContentTypeReader reader, Object existingInstance)
       at Microsoft.Xna.Framework.Content.ContentReader.ReadObjectInternal[T](Object existingInstance)
       at Microsoft.Xna.Framework.Content.ContentReader.ReadObject[T]()
       at Microsoft.Xna.Framework.Content.ContentReader.ReadAsset[T]()
       at Microsoft.Xna.Framework.Content.ContentManager.ReadAsset[T](String assetName, Action`1 recordDisposableObject)
       at Microsoft.Xna.Framework.Content.ContentManager.Load[T](String assetName)
       at NanobotProto.Object.Cell.LoadContent(ContentRegister content, DrawState state, ContentManager manager) in C:\Documents and Settings\Evgeni Petrov\My Documents\Visual Studio 2008\Projects\Temp\NanobotProto\NanobotProto\Object\Cell.cs:line 130
       at Xen.ContentRegister.Add(IContentOwner owner) in c:\Documents and Settings\Evgeni Petrov\My Documents\Visual Studio 2008\Projects\NanoBot\xen 1.3a\xen\src\Xen\Content.cs:line 144
       at NanoBot.Engine.Initialise() in C:\Documents and Settings\Evgeni Petrov\My Documents\Visual Studio 2008\Projects\Temp\NanobotProto\NanobotProto\Engine.cs:line 39
       at Xen.XNAGame.Initialize() in c:\Documents and Settings\Evgeni Petrov\My Documents\Visual Studio 2008\Projects\NanoBot\xen 1.3a\xen\src\Xen\Application.cs:line 84
       at Microsoft.Xna.Framework.Game.Run()
       at Xen.Application.Run() in c:\Documents and Settings\Evgeni Petrov\My Documents\Visual Studio 2008\Projects\NanoBot\xen 1.3a\xen\src\Xen\Application.cs:line 626
       at NanobotProto.Program.Main(String[] args) in C:\Documents and Settings\Evgeni Petrov\My Documents\Visual Studio 2008\Projects\Temp\NanobotProto\NanobotProto\Program.cs:line 15
  InnerException:
Coordinator
Nov 21, 2008 at 8:28 PM

You need to set rhe content processor for the .fbx file to 'Xen - Model' in the file properties

And mouse state is in UpdateState.MouseState. If you wantto show a custom cursor, you will need to do this manually (windows forms or draw-it-yourself)

Nov 21, 2008 at 8:31 PM
Edited Nov 22, 2008 at 9:20 AM
Thank you very much!

I am trying to start my default cursor like you would do with Game class from XNA.

 this.IsMouseVisible = true;

How can I do this in XEN ? If I can because from your last post I didn't understand if you support default mouse or not.
Nov 22, 2008 at 10:53 AM
Edited Nov 22, 2008 at 10:54 AM
Hi Zammy.

What you looking for is InputMapper.MouseVisible property. I suggest you to override InitialisePlayerInput in your Application class, for example:

protected override void InitialisePlayerInput(Xen.Input.PlayerInputCollection playerInput)
{
         if (playerInput[PlayerIndex.One].ControlInput == Xen.Input.ControlInput.KeyboardMouse)
         {
                  playerInput[PlayerIndex.One].InputMapper.MouseVisible = true;
         }
}
Nov 22, 2008 at 11:11 AM
Thank you!

I was trying exactlly that, overriding InitialisePlayerInput,
I did set playerInput[PlayerIndex.One].ControlInput == Xen.Input.ControlInput.KeyboardMouse,
but never checked ControlInput. :(

I did my mouse with a TexturedElement but couldn't get the AlphaBlending to work but now its fine.

Cheers,
Evgeni
Coordinator
Nov 26, 2008 at 10:18 AM

Hey.

Just so you know, 1.4 is out now. It has 'ProjectToScreen' and 'ProjectFromScreen' in the DrawState. These should work just as expected (I hope :-)

Nov 26, 2008 at 10:27 AM
You are great! I did my own implementation on UnProject :D which works great but probably is not efficient.

Thank you again!
Nov 26, 2008 at 10:29 PM
Edited Nov 26, 2008 at 11:22 PM
scrap that.... i fixed it... i am retarded

well... I have another problem...

I do everything the same but this time i try to draw it with .Draw() inside a :IDraw object.

this is my draw method:

            state.PushWorldMatrix(ref worldMatrix);

            if (CullTest(state))
            {
                UpdateInfo(state); // must update after the world matrix of the object is pushed

                shader.Bind(state);

                model.Draw(state);
            }

            state.PopWorldMatrix();


            colorElement.Draw(state);

            parameter.Draw(state);
// my TexturedElement

hmm.... why I cannot draw it like that ? Does it need to be inside DrawTarget?


Coordinator
Nov 26, 2008 at 10:42 PM

Hi.

This works fine for me.

Are you assigning curstor.Texture?

Coordinator
Nov 26, 2008 at 10:43 PM
OK then :-)
Coordinator
Nov 26, 2008 at 11:08 PM

What exactly is going wrong?

When is it not drawing correctly?

The Element classes are all quite robust, in that they setup a lot of their own parametres, such as cameras, render states, etc. So if something is going wrong, it's probably not with the element.

Also, I don't know enough about what you are doing, but I'd expect you want 'if (model.CullTest(state))'

Nov 26, 2008 at 11:30 PM
That is what actually happens underneath. For the culling.

I do not get anything drawn. I have no idea why.

I do everything the same way.

ok... here is the whole code: http://pastebin.com/m58a9ac34

I have highlighted relevant code.
Coordinator
Nov 26, 2008 at 11:43 PM

Be aware that a drawTarget will call CullTest() before it calls draw, so you may be culling unexpectadly.

Ok, the first thing that comes to mind is that you are setting the vertical alignment of the element to Top. The Position value is the position from the alignment. When using Top, 0,0 will be the top left corner, 0, -100 will be down 100 from the top left. 0, +100 will be up 100 from the top left (ie, off the top of the screen).

Nov 27, 2008 at 12:07 AM
You were completely right.
Sorry for making you debug my code :(
Nov 27, 2008 at 1:32 PM
Hey again.

I am going to be drawing a circle as parameter for my game objects. This is going to be like their "eyes". They know only what is inside that parameter.
I want this to be drawn on the screen. So I am using the TexturedElement but it uses a .png file that must be scaled depending on the radius of the parameter.
That creates a nasty pixelization on the edge of the circle. Is there a better way to do it? Any hints would be great. I want consistent 2px thich circle independent of
radius.

Also how can I change the color of the drawing? SpriteBatch when drawn I can select to Color, that could be useful for me not to make 2-3 textures with just different color.

Thank you


Coordinator
Nov 28, 2008 at 8:06 AM
Edited Nov 29, 2008 at 7:33 AM

You would have to either write a shader that generates the circle for you (possibly not as easy as it sounds). Basically it would work out the distance from the centre, and within a certain range it would return a certain colour (and return transparent everywhere else I guess).

Or you could generate your own circular geometry, and draw it yourself. This is possibly the easier option. You can implement the Element class to make your own, this class simply requires you fill in the Draw method, the SetShader method and a property that returns the size in pixels of the element. Or you could draw it yourself through your own object. The Element class will make sure a 2D camera is setup, setup the world matrix, etc.

The only Element type that you can set the colour is the SolidColourElement and the SpriteElement. SolidColourElement isn't all that useful :-) SpriteElement is designed to render lots of sprites (basically, very similar to SpriteBatch). They use Shader instancing or proper hardware instancing depending on the sprite count. This makes them fast for loads of sprites, but rather overkill and inefficient for very small numbers. (The TextElement / TextElementRect both internally have a single SpriteElement child).

Nov 29, 2008 at 2:20 AM
Hey, some update. I implemented creating of a texture with a circle in it. Here is where I read it from: http://cs.unc.edu/~mcmillan/comp136/Lecture7/circle.html
Do you think I need to create a shader for that? Could be a good exercise but kinda waste of time.
Anyway :)
Nov 29, 2008 at 1:19 PM
Edited Nov 29, 2008 at 7:32 PM
Short question: I want to use a GameService, how should I access it in a component that implements IUpdate ?

I was thinking of creating a static property in my main application class so I can access it. Is there a better way?

Another short one (sorry) : Would you advise on using XNA game components or create my own with XEN interfaces?

Coordinator
Nov 29, 2008 at 8:37 PM

You can access services like so:

state.Application.Services

I do not support the use of GameComponents. That doesn't mean you can't use them, I just have never tested, now will I fix problems they introduce.

There is no way to predict what a GameComponent is going to do / change / break.

Jan 18, 2009 at 7:37 PM
Hello from me again.

I want to draw bounding spheres. Can this be included in Xen 1.5?
If not shall I just create a drawing sphere with the same size and position?

Evgeni
Coordinator
Jan 18, 2009 at 8:06 PM
Edited Jan 19, 2009 at 9:56 PM

Hey. The easiest option would be creating spheres and drawing them yourself.

Although, if you are feeling adventurous, you could create a post-culler, which draws a sphere for whenever a CullTest succeeds :-)
You'd do this with a class that implements ICullPrimitive, and use state.PushPostCuller(). Basically, a post culler is an extra culler that runs after the primary on screen culler (a pre-culler runs before it). You'd need to be careful though, you wouldn't be able to draw the sphere/cube immediately, you'd need to buffer them and draw them later. CullTest() only has an ICuller passed in, and you could easily mess up whatever was currently rendering.

Jan 19, 2009 at 3:11 PM
I am using this for calculating bounding sphere : http://pastebin.com/m59609913

The sphere does not get calculate very properly. Where do you think I might have not implement it right?

Thank you
Coordinator
Jan 19, 2009 at 10:12 PM
Edited Jan 19, 2009 at 10:14 PM
If you look in the ModelInstance class, it uses bounding boxes to do culling (for the model instance itself, through to the model parts as well). ModelInstance does very aggressive cull testing.
The static bounds stored in the model data are bounding boxes for the geometry, (it's stored for both the entire model, each model part and piece of geometry). There is also animation specific bounding box modifiers stored in each animation (these are not actual bounding boxes, just offsets for the min/max - for example the tiny model's animations all offset the model on the Y axis by quite a bit).

As for your code, the only thing I can see wrong is that you are calculating centerPoint wrong, as it should be the average of the min/max, (max + min)/2, but you are using (max - min)/2

Coordinator
Jan 20, 2009 at 3:38 AM
I've actually thought of a way to visualize cull tests which would be very simple.
I'll have a think, because it may be really easy to implement too (basically, use a draw modifier that pushes a post culler in the BeginDraw() to detect all the performed cull tests, then pops it and draws them all in EndDraw()).
Jan 20, 2009 at 4:22 PM
So, from what I have read, and you have told me, when loading a model bounding figures are automatically build.

Is GeometryBounds the class that represents this information in XEN? (as bounding spheres in normal XNA? )

Is GeometryBounds the class used for Culling? (check if the object is in the viewing frustrum?)

Can I use the different GeomentryBounds for collision? (I mostly need BoundingSpheres)
I assume I can create BoundingSphere with radius and radius center that comes with it.
(Slight suggestion, it will be really nice if there is more metadata, it would really help newbies like me.)

Also I see they are read only(the radius and radius center). Is the Transform method going to be able to change them? (more of a c# question I guess)

Thank you very much for your continual support.

Evgeni



Coordinator
Jan 22, 2009 at 11:37 AM
Yes, the GeometryBounds structure stores both bounding box (min,max) and bounding sphere (centre + radius).
These are computed by the model importer (which is why they are readonly).

The ModelData, MeshData and GeometryData classes all have StaticBounds members (which is the GeometryBounds for when the model is static and not animating).
So the StaticBounds for the MeshData will be the bounds that encloses all the GeometryData bounds.

Further, there is the AnimationStaticBoundsOffset, which is an array in each that stores how an animation (with a weighting of 1) will offset the static bounds.

The Transform() method in the GeometryBounds structure is actually used during content compile generation of the animation bounds, it just happens to be public. The bounds are always in model world space (they are axis aligned to the model, the Transform method converts a rotated bounds into model axis aligned bounds).

So I wouldn't use that to transform your bounds, as they are in model space, use the CullTest methods once the model world matrix has been set by your code.

Jan 24, 2009 at 10:13 AM
Edited Jan 24, 2009 at 10:14 AM
Ok, I am doing soft-body physics.

So I will load BoundingSpheres tru XML file that is created by the artist.
I will extract vertices and indices.
Calculate which vertice is part of which bounding sphere.
I will also calculate edges as I need them for physics and collision(i think)

I will need to manually transform the bounding spheres each time the model is transformed.
Once I have collision in some boundign sphere I will do narrow search only with the vertices and edges inside the bounding sphere that has collided.

How can I extract vertices and indeces from XEN model? and set them back when transformed.



Coordinator
Jan 24, 2009 at 10:31 AM
Edited Jan 24, 2009 at 10:34 AM

Short answer is you can't easily extract vertices from a model in either xen or XNA.

When converting an input model (eg, .X model) the content pipeline gives you a raw byte array for the vertex data, and the vertex elements for a vertex declaration. The only way to extract positions from the model is working out the offset, stride and type for the position value via the vertex declaration data, and then calculating and coping those raw bytes for each vertex, and converting to floats (using Xen.Ex.BitCast). This sort of thing is tedious, error prone and slow.
And even if you did do this, xen does not provide public access to the original vertex data used by a vertex buffer (because in a most cases the vertex buffer only keeps a temporary reference to this data).
Of course, there is nothing stopping you modifying the GeometryData ContentLoader constructor so it keeps a reference to the raw byte[] and declaration data when it loads. However I wouldn't recommend it for the very reason the vertex buffer keeps a temporary copy.

I'd suggest to you that per-triangle collision detection is far too accurate for what I assume you desire, and will be very inefficient - especially for soft body physics, which usually don't require such precision. I feel performance will be terrible, especially if you plan to run on the xbox as well. The 'tiny' model is rather low detail, and it alone is 7,000 triangles. It may not sound all that much, but it represents a lot of data.
If you are trying to use a model for your world geometry, then I'd suggest you will need something more suited to the task and your game.

Otherwise I'd rather suggest you do something with the per-bone bounds data the model stores, as demonstrated in tutorial 12. This still gives a good representation of the model, and is much simpler.

Jan 24, 2009 at 11:18 AM
So rather than use vertices for soft body physics.
Rather create a good representation of the object with bones.
Connect the bones with springs (as I intended to do with vertices) and when physics manipulates the bone. (after some collision for example)
Move the vertices that are rigged with that bone?
The bone will move the bones connected with springs to it. And those bones in turn will transform the vertices rigged to that bone.
This sounds and good?

Sorry for being so retarded but this whole job is really frustrating. Getting the puzzle together is becoming much more difficult than expected.

Evgeni
Coordinator
Jan 24, 2009 at 9:25 PM

Yes that would be a good way to go about it. You can extract the bounding spheres for each bone using the data demonstrated in tutorial 12 (the tut uses cubes, as spheres are almost always bigger).

There isn't any supported method for manual bone manipulation, but if you read this post here, it covers how to go about modifying the bones. Basically, search for the line:
modelData.skeleton.TransformHierarchy(transformedBones);
in Xen.Ex.Graphics.AnimationController, and replace the bones there. You will need to add some members to that class to store your bone position overrides, but that shouldn't be too hard. The only catch (which I mention in the post above) is that bones are transforms relative to the default pose of the model, so when in the default pose, the bones are all Identity (so it would be a matter of multiplying your bone matrices with the inverse of the world space bone matrices of the default pose).

Good luck, as you are discovering, making games is hard :-) but it is rewarding, so stick with it. Let me know if there is anything specific in xen that is causing you major headaches.

Jan 24, 2009 at 9:35 PM
Thank you for the continual support.
I will take a look at what you suggested tomorrow. I am done for today.

I didnt know a lot of basic stuff for 3D graphics and that is really hindering me.
The good part is that I am slowly gaining the information, through trail and error or
through articles or through you and some other people.

I am starting to understand this. I hope someday I will be competent enough to help you with XEN.
Jan 29, 2009 at 5:13 PM
Hey, some update.

I manage to implement soft-body physics on particles. And is working pretty well when I am drawing just vertices.
What I want to do is to write a content pipeline project to load it into my Mesh/Model classes.
I am looking at this sample http://creators.xna.com/en-US/sample/custommodelclass
I understand what is going on. The problem is that I see they use two different objects for "design time" and "run time".

In short will I be able to write my own content pipeline extension so I can load models into
your implementation of Vertice buffers and Indices.
It seems that this is going to be possible but if you give me some hints maybe that will save me unnecessary headaches.

Evgeni
Coordinator
Jan 29, 2009 at 8:58 PM

Hi. I'm not sure what you are trying to do, that requires content pipeline use?
I admit I didn't really build the xen importer with extended classes in mind... However you can just copy the entire project and make your own variation.

You will probably have the same problems as I mentioned before, as the vertex data the XNA .x / .fbx importers give you is just a raw byte array - and there is no way around this. Although they are in Vertices<> classes, they use a special case varation, and they are actually Vertices<byte> instances under the hood. As there is no structure that represents the data format (as it's dependant on the exported model).

If you could give me an idea of exactly what you are trying to do I can probably help

Jan 30, 2009 at 12:16 PM
I want to convert from
            public VertexDeclaration VertexDeclaration;
            public VertexBuffer VertexBuffer;
            public IndexBuffer IndexBuffer;

to XEN representation of  vertice and indices bufferes.
        IVertices verticesBuffer;
        VertexPositionNormal[] vertices;

        IIndices indicesBuffer;
        uint[] indices;




Coordinator
Jan 30, 2009 at 8:45 PM

I'll be honest and say it would be tricky to do. You should avoid it if possible.
It's not a xen thing, it's how the content pipeline works.
The best idea would be to let the model still use the byte[] data, but pull the position/normal data out when the model data is loaded (so you can manually access the data yourself)

In the GeometryData class, there is a line that looks like this:

this.vertices = Vertices<byte>.CreateRawDataVertices(data, vertexElements);

'vertexElements' is the elements of the vertex declaration provided by the content pipeline, and 'data' is the raw byte[] data also provided. There is no guarantee on how this data is formatted.

You will need to know the stride for each vertex in the byte[] data (ie, the number of bytes each vertex takes up). VertexElementAttribute.CalculateVertexStride() will tell you this. The length of the array divided by the stride will tell you the number of vertices.

You will need to create your own VertexPositionNormal[] array, and then scan the vertexElements data, and find each element that matches position/normal (eg, usage=POSITION, type=float3, index=0).
Each matching VertexElement will tell you the byte offset of the element (probably 0 for position). Given the stride of the vertex, and the base offset, you will know the starting byte for each bit of data in each vertex.
Assuming the data type matches (ie, it's float3) you can then read 12 bytes, each four will be a single float value. You can use Xen.Ex.BitCast to convert these bytes into float values (assign Byte0 to Byte3 and then read the Single value). Combine them, and you have a Vector3. Repeat for each vertex.

Do this for both Position and Normal, and pulling the data out, and you should have your vertices.

Hope that helps.

Jan 31, 2009 at 10:40 AM
I am missing something here.
"when the model data is loaded"
Do you mean in the game project? Or in the content pipeline project?
Coordinator
Jan 31, 2009 at 9:52 PM

I meant in the GeometryData class, where the vertex buffer is created.

Feb 2, 2009 at 10:42 AM
I managed to do it.

Used BitConverter from .NET.

             int partCount = input.ReadInt32();
            for (int i = 0; i < partCount; i++)
            {
                // Simple data types like integers can be read directly.
                int TriangleCount = input.ReadInt32();
                int VertexCount = input.ReadInt32();
                int VertexStride = input.ReadInt32();

                VertexDeclaration vertexDeclaration = input.ReadObject<VertexDeclaration>();
                VertexBuffer vertexBuffer = input.ReadObject<VertexBuffer>();
                IndexBuffer indexBuffer = input.ReadObject<IndexBuffer>();

                byte[] verticesByteArray = new byte[vertexBuffer.SizeInBytes];
                vertexBuffer.GetData<byte>(verticesByteArray);
 
                byte[] indicesByteArray = new byte[indexBuffer.SizeInBytes];
                indexBuffer.GetData<byte>(indicesByteArray);

                var vertices = new VertexPositionNormal[VertexCount];
                short[] indices ;//= new short[indexBuffer.SizeInBytes];

                //VertexElement[] vertexEF = modelPart.VertexDeclaration.GetVertexElements();
                //VertexPositionNormal.VertexElements = vertexEF;

                for (int index = 0, vertexIndex = 0; index < verticesByteArray.Length; index += 24, vertexIndex++)
                {
                    vertices[vertexIndex] = new VertexPositionNormal();
                    vertices[vertexIndex].Position = HelperClass.byteToVector3(verticesByteArray, index);
                    vertices[vertexIndex].Normal = HelperClass.byteToVector3(verticesByteArray, index + 12);
                }
                indices = HelperClass.byteArrayToShortArray(indicesByteArray);
                //input.ReadSharedResource<Effect>(delegate(Effect value)
                //{
                //    modelPart.Effect = value;
                //});
                Meshes.Add(new NB_Mesh(vertices,indices));
            }
Feb 7, 2009 at 2:51 PM
Hello again :)

I want to use AABB which is represented as BoundingBox in XNA.
I was wondering how to calculate new AABB when I have the world matrix. (AABB should be in world space)

Should I loop through all MeshData -> GemetryData  -> StaticBounds.
Transforming the StaticBounds with WorldMatrix and then finding which is the furthest away point in each direction of the axis?
I saw that I do not have straight access to the vertices position so I guess this is an alternative I can use (should be faster actually)

I am just not sure if  my logic is correct. Was trying to draw it but I cannot persuade myself.

Thank you in advance.

Coordinator
Feb 7, 2009 at 9:37 PM

GeometryBounds.Transform(Matrix) will do exactly this. (Yes, I know, it's not properly documented). It transforms the bounds given the matrix, and then computes the new axis aligned bounds.

:-)

Feb 9, 2009 at 6:46 PM
  GeometryBounds bounds1 = entity1.drawingProperties.model.ModelData.StaticBounds.Transform
                                                        (ref entity1.drawingProperties.WorldMatrix);


When transferred the radius of the GeometryBounds does not change. Scaling has no effect.

Is this a bug? If it is not why is it working light that?

Have you thought of adding a collision test to these classes? (BoundingBox and BoundingSphere)
Coordinator
Feb 24, 2009 at 10:49 AM
Sorry I haven't replied for 2 weeks. It's been a combination of many factors have meant I've been totally swamped, and somehow I didn't get a notification email you'd made the post. If I'd seen the email I'd have replied right away.

You have probably figured it out, but yes, you are correct that the radius does not get scaled. It assumes the matrix isn't a scaling matrix (in general, I assume this too through out most of the model code).
If you still want to change it, this can be done. In the Transform method, the Radius / RadiusCentre is assigned right at the end. Change this to:

            result.radius = (Minimum - Maximum).Length() * 0.5f;
result.radiusCentre = (Minimum + Maximum) * 0.5f;

And it *should* work OK. however I'll need to test this tomorrow.
I've been hard at work on 1.5, and I can tell you it'll be out in the next couple of days. I'll make sure I test this before then though.

Thanks :-) And sorry for the slow reply. I wasn't ignoring you or anything, it just slipped through.

Feb 24, 2009 at 12:43 PM
Yeah, i did it no problem.

Bad news is our project went into the river. (Bulgarian expression.)
It seems that is very hard to motivate college students :(

I want to thank you for the continuous support!
I learnt a lot and I will check out what is going on with XEN.

I wish you all the best. Maybe I can join development once I learn a little bit more about 3d programming.

Evgeni
Coordinator
Feb 25, 2009 at 10:13 AM

Sorry to hear your project went south, it's always difficult managing people - especially when there isn't any money involved and everyone is running on inspiration.

Trust me, I know what it's like, it's not an easy thing to watch happen - but you'll learn a lot from it, and hopefully be able to approach the next project with a more experienced eye and be able to spot the trouble brewing sooner.

Thank you very much for keeping in contact and sharing the problems/experiences you had.
It's a fun and challenging project, but most of all it really helps keep me motivated if I know others out there are enjoying and appreciating what I'm making :-)

Best of luck,
- Graham.