Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Sunday, 27 April 2014

Avoid Photon OnDestroy Warnings

I like my code to compile and run without errors.  The Photon Unity Networking (PUN) code did not.

When exiting scenes I would get the following errors for each instantiated object in the level:

OnDestroy for PhotonView View (0)1001 on CharacterPlaceholder(Clone)  but GO is still in instantiatedObjects. instantiationId: 1001. Use PhotonNetwork.Destroy().

Failed to 'network-remove' GameObject because it's null.


I searched the Internet and Exit Games forums but found little help that actually solved the problem. I found plenty of other people reporting the same issue.



I tried reading the PUN documentation but that was unhelpful as were any of the samples that I tried so I experimented.



I now have a work round which avoids the warnings and errors.



/// Tidies up before exit from the scene.
/// Attempts to destroy network objects correctly.
/// Pauses the messages while the scene changes.
private static void TidyUpBeforeExit()
{
  // Destroy any photonView game objects.
  PhotonView[] views = 
          GameObject.FindObjectsOfType<photonview>();

  // Whichever client exits first cannot 
  // destroy the objects owned by
  // another client.
  foreach (PhotonView view in views)
  {
    GameObject obj = view.gameObject;

    if (view.isMine)
    {
      // Clients can destroy their 
      // own instantiated objects
      PhotonNetwork.Destroy (obj);
    }
    else
    {
      // Clients cannot destroy objects 
      // instantiated by other clients.
      // This avoids the error by 
      // removing the instantiated 
      // object before the network view 
      // is destroyed
      if (PhotonNetwork.
            networkingPeer.
            instantiatedObjects.
            ContainsKey(view.instantiationId))
      {
        PhotonNetwork.
            networkingPeer.
            instantiatedObjects.
            Remove (view.instantiationId);
      }
    }
  }

  // By pausing and starting the 
  // messages manually I can start
  // any client or server in any 
  // order and all spawn messages
  // are retained.
  PhotonNetwork.SetSendingEnabled(0, false);
  PhotonNetwork.isMessageQueueRunning = false;
}



I simply include that method before any scene change.

Friday, 18 April 2014

Unity Gizmos

I've been using Unity 3D for months now and I somehow missed Gizmos as a concept.  I had seen the camera and speaker icons in the editor view but I think I had just assumed they were built in symbols used for built in objects and I had a blind spot towards them.

I now know better.  You can easily create your own icons which can be included in the scene.  I started using them when I wanted to make spawn points visible in the scene.



It is very easy to attach your icon to any object in a scene and that icon displays over the object.




That works well if you want to mark otherwise invisible points in your scene.  An example of this might be waypoints for AI controlled characters.

I prefer to create the Gizmos in code.  This adds them to the Gizmos list in the game view.



Creating the Icon

This can be done in any image editor and just needs whatever shape you want with a transparent background.

The image can be any size if you intend to use the default automatic scaling method.  For good quality I use anything between 512 and 1024 pixels high or wide images.  If you don't use the automatic scaling the image in the 3D scene, at those sizes, is quite small.

I used Inkscape to create the following image.



The important bit to know before you can use the image in your code is that it must be in the special Gizmos folder in Unity.

There can only be one Gizmos folder and it must be in the root of the Assets folder.



If you try to put your icon anywhere else, it will not work as a Gizmo in code.

Using the Icon for Your Object

Well if you can write any Unity code this is the simplest possible.  Just add the following in the code for your object or create a small script with this in.



/// http://docs.unity3d.com/
///        Documentation/ScriptReference/Gizmos.html
void OnDrawGizmos()
{
    // The icon image must be in the 
    // special folder called 'Gizmos'
    // There can only be one Gizmos 
    // folder in the root of Assets.
    Gizmos.DrawIcon (transform.position, 
                     "PersonIcon.png", 
                     true);
}



That's it, you now have a Gizmo shown wherever you position that object.


Saturday, 8 February 2014

Unity Reflection

I'm still learning about Unity and how to code for it.  Today I have found out that the OnGUI() method is deliberately called twice every frame.

http://answers.unity3d.com/questions/551274/why-is-ongui-called-significantly-more-than-update.html

For the most part this is not noticed but I was putting some home made mouse over methods within the OnGUI() method and getting double key press results.



That led me on to find out how Unity calls the MonoBehaviour methods, like Awake(), Start(), Update() and OnGUI().  Apparently Unity finds them using reflection rather than any form of interface or inheritance.

That behaviour leads to an unexpected coding style compared to vanilla C# coding.

You can define those methods any way you like.  They can be public, private or protected and virtual or not.  Unity will still behave as intended.

It feels odd but just works.

I'm getting the hang of creating components rather than joining everything together in one big mass of a project.

I am surprised how much work is involved in getting a menu system with mouse, keyboard and gamepad input working but I am hopeful I will make up this time when it comes to creating the game levels.

Sunday, 15 December 2013

Unity Code Naming Conventions

I did a quick bit of searching to find out what naming conventions were used.  It turns out that there isn't really one.

http://forum.unity3d.com/threads/135617-C-naming-conventions-for-Unity
http://answers.unity3d.com/questions/10571/where-are-the-rules-of-capitalization-documented.html

Unity supports three programming languages.  I'll ignore Boo because I know nothing about it and there are few samples.   Most of Unity's older code base is in UnityScript.  That has a very similar syntax to JavaScript.  In the UnityScript code base the only convention is that class and function names are in PascalCase and variables are in camelCase starting with a lowercase letter.

C# appears to becoming very popular with Unity developers, if not the dominant language but as the syntax is similar most people can mix and match if needed.

As C# is a Microsoft language many people have adopted the Microsoft guidelines for the use of case when  working in Unity.  I also prefer those naming conventions for case, they are:
PascalCase for public and protected properties and fields and camelCase for private properties and fields with PascalCase for all methods independent of if they are private, public or static etc.

The case is only significant for public or protected elements so that non-case sensitive languages can always reliably access them:

public Method(parameter)
protected Method(parameter)
private Method(parameter)
public Property
protected Property
private property
public Field
protected Field
private field

Some people like to use an underscore in front of _camelCase for private fields but that is their personal preference and appears to go against the recommendations in some of Microsoft's guidelines.  Again, that is only significant for public fields, what you use privately is just for readability of the code.


Saturday, 21 September 2013

Muzzle Flash

I've just been asked a question by way of a comment to this blog.  It's easier to reply by way of a new post.  I also haven't had anything to update on the blog for a while so this does two jobs in one.

State of Play

I haven't had anything to say for a while because at the moment my code is broken.  By that I mean I'm in the middle of changing something fundamental and it won't compile, let alone run.

I don't like it when the code is in this state.  I prefer to make small changes and at the end of every day the code compiles and I can test it.  For the last few weeks it has been a mess.

I am in the process of separating the client processes from the server processes and adding all the messages to communicate between the two.

I am concentrating on just the messages to get to a state where I can compile and run the game again but just to spawn a character in to the world, the state of every part of the world needs to be sent from the server to the client and the message to say what and where to spawn.

There's been a fair bit of design and redesign but now it's mainly a lot of typing.  I'm nearly there but not quite.

The Question

As mentioned, this post is to specifically answer a question.

"I've been working on a project in which you've helped me out a lot and now I'm at point at which I'm experimenting with particles. I've seen the muzzle flash screenshots on your blog and wanted to ask how did you go about positioning the exact spot to your weapon for the muzzle flash effect."
It was asked by 49ers94 from the Xbox Live developer forums.



It refers not only to the muzzle flash shown in a previous post, but to the start of the projectile particle effects shown in several of the screen shots.

The answer is simple.  I store the relative position of the muzzle in relation to the origin of the weapon.  That position is transformed by the direction the weapon is aimed in to calculate the position of the muzzle at any point in time.



 /// 
 /// Get the muzzle location in world space. 
 /// Grenades will return the hand position because the offset is zero.
 /// 
 public Vector3 MuzzleLocation()
 {
     // Vector3 MuzzleOffset - relative to the weapon origin
     // Matrix WorldPosition - position and rotation of the weapon model
     return Vector3.Transform(MuzzleOffset, WorldPosition);
 }


The above code is within the weapon model wrapper class that I use.  The weapon is already moved by whichever bone the weapon is attached to.

If you calculate that relative muzzle offset position manually for each weapon, that is all you should need to do.

One note on the particle effect.  The muzzle moves quickly as the character does but to make a nice effect the flash is not instantaneous.  I found that if the particle effect stayed still for its duration it looked odd when the weapon moved away from the still visible flash. 

The solution I used was to have very short duration particles and create new particles at the new position of the muzzle each frame.  This is not how a real flash would happen but this is what I found looked best.

Coding my own Tools

I've taken it a bit further to make it easier to create and edit more weapons.  I included a visual method to adjust the muzzle position in to the model viewer that I use for my game.



To make my life even easier I create all my weapons facing the same way and at the same scale.  I have not created all my own models but I take the model in to Blender, change its position and scale and output the model to FBX for use in my model viewer and in my game.



I save the relative muzzle position in to a text file for each weapon which is loaded in the content pipeline.

I think that covers everything on that topic.  Back to coding my client server architecture...  After an all day breakfast that is.

Sunday, 30 June 2013

Quaternion Axes

It's been a while since I last posted so before I get in to the topic of this post I'll mention what I've been up to as it has some relevance.

I have been working on adding network game play.  It did not take me long to realise that the way I originally did the physics in the game, that works for single player and split screen, does not work for a network client server based game!

My mistakes were that I used variable time step with a lot of relatively simple maths to ensure all movement was smooth and I used a single state for working out what the character was doing. I have now learnt that I need to keep a history of the movement and states of the entities and use the state at a point in time to best approximate where all the characters are in relation to each other and what they were doing at that same point in the past.

I have nearly finished making those changes so at least the single player game works with a history of states.  In the process I changed the way the movement physics was calculated.  Probably not essential but I came across better ways of doing things while I was looking in to networked physics.

I ended up using more quaternions than I had previously.  I still convert to matrices in several places to get some results but where possible I have tried to leave the quaternions as quaternions and use quaternion maths to get the results.  Just in case it was not obvious, I am not very familiar with quaternion maths.  I think I now get it but basically I look up formulae on the Internet and convert them to C# code to get the results I need.

The XNA Matrix structure has methods to get the Forward, Right and Up axes vectors from the matrix.  The Quaternion structure does not!  With a bit of research I found some C++ code that nearly got the axes directly from a quaternion and with a minor change and some testing I ended up with:



/// 
/// Returns the forward vector from a quaternion orientation.
/// 
public static Vector3 Forward(Quaternion q)
{
    return new Vector3(
      -2 * (q.X * q.Z + q.W * q.Y),
      -2 * (q.Y * q.Z - q.W * q.X),
      -1 + 2 * (q.X * q.X + q.Y * q.Y));
}
/// 
/// Returns the up vector from a quaternion orientation.
/// 
public static Vector3 Up(Quaternion q)
{
    return new Vector3(
      2 * (q.X * q.Y - q.W * q.Z),
      1 - 2 * (q.X * q.X + q.Z * q.Z),
      2 * (q.Y * q.Z + q.W * q.X));
}
/// 
/// Returns the right vector from a quaternion orientation.
/// 
public static Vector3 Right(Quaternion q)
{
    return new Vector3(
      1 - 2 * (q.Y * q.Y + q.Z * q.Z),
      2 * (q.X * q.Y + q.W * q.Z),
      2 * (q.X * q.Z - q.W * q.Y));
}


I am sure any professional developers will understand the importance of testing.  I may not be a professional but from experience I know I cannot trust my own typing or other people's sample code or maths.  To ensure the results are as intended I have validated the code above using versions of the following method, one for each axis.  I am not sure if this is 'Unit Testing' but it is my interpretation.



/// 
/// Check that the result of the quaternion elements is facing where expected.
/// The class containing the methods is called MoreMaths
/// 
public static void ValidateQuarternionForward()
{
    const float acceptable = 0.0009f;
    System.Diagnostics.Debug.WriteLine(
      "\n== Start Test ===============================================");
    System.Diagnostics.Debug.WriteLine(
      "== MoreMaths.ValidateQuaternionForward() =====================");

    // List of values to test
    Vector3[] positions = new Vector3[] 
    { 
        new Vector3(10, 20, 15),
        new Vector3(15, -5, 12),
        new Vector3(10, 20, -12),
        new Vector3(-10, 20, 15),
        new Vector3(2, 1, 0),
    };

    Vector3[] facing = new Vector3[] 
    { 
        new Vector3(10, 9, 20),
        new Vector3(25, -5, 12),
        new Vector3(10, 17, -19),
        new Vector3(-12, 20, 15),
        new Vector3(2, 1, 10),
    };

    int countTotal = 0;
    int countFails = 0;

    foreach (Vector3 location in positions)
    {
        foreach (Vector3 target in facing)
        {
            countTotal++;

            Matrix orient = 
              Matrix.CreateLookAt(location, target, Vector3.Up);
            Quaternion face = 
              Quaternion.CreateFromRotationMatrix(orient);
            face.Normalize();
            orient = Matrix.CreateFromQuaternion(face);
            Vector3 item = MoreMaths.Forward(face);

            Vector3 net = Vector3.Subtract(orient.Forward, item);

            string result = "Pass | ";
            float length = net.Length();
            if (length > acceptable ||
                float.IsNaN(length))
            {
                result = "FAIL | ";
                countFails++;
            }
            System.Diagnostics.Debug.WriteLine(
                result + "Forward" +
                " Result M: " + orient.Forward.ToString() +
                " Result Q: " + item.ToString() +
                " Difference M-Q: " + net.ToString()
                );
        }
    }


    System.Diagnostics.Debug.WriteLine(
      "Total Count: " + countTotal + 
      " | Failed Count: " + 
      countFails.ToString());

    if (countFails < 1)
    {
        System.Diagnostics.Debug.WriteLine("PASS");
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("FAIL");
    }
    System.Diagnostics.Debug.WriteLine(
      "== End ======================================================\n");
}


There is significantly more code to check the results so the above just shows validating the forward vector but it should be obvious where to change that to do the Up and Right axes vectors.


    Matrix orient = 
      Matrix.CreateLookAt(location, Vector3.Forward, target);
    Quaternion face = 
      Quaternion.CreateFromRotationMatrix(orient);
    face.Normalize();
    orient = Matrix.CreateFromQuaternion(face);
    Vector3 item = MoreMaths.Up(face);


I have many bits of maths and other methods that I need to ensure produce the results I expect, so I have similar debug code that I can run as stand alone methods to test the result of sections of code.

I hope the above is useful to some of you.

I have a little bit more to do to get the AI to use the newly added history of states and then I can get on with creating the server side code.

Thursday, 7 March 2013

View Occlusion

Since the play testing a few weeks ago I have been busy but I have not got a great deal to show for it yet.

My main task is trying to improve the draw performance so I can add a bit more detail to the levels and counter some of the additions I made based on the suggestions from the play testing.

I already do the typical view frustum culling and restrict the far plane range so I am only left with the more complex things to try.  Pretty much that is some form of pre-calculation of what is in view.

From the reading I have done Binary Space Partitioning (BSP) is not appropriate to the type of exterior vistas I would like to have in the game.  Therefore I have been concentrating on Occlusion Volumes (View or Visibility Cells).  My understanding being that these are areas of the map that if you are inside that area the models and meshes in view have been pre-calculated and therefore exclude meshes that are hidden by other meshes.  Both Unity and the Unreal Engine have variations of this that can be enabled depending on if it is appropriate for the map.


My map already uses a grid for storing, triangles and other information so adding additional heights to set the boundaries of the Occlusion Volume is trivial.  The tricky task has been calculating the mesh occlusion information.

I tried to calculate the view using the GPU.  I wrote a shader that stored an index for each model and returned that in the render target.  By drawing the view in sufficient directions from various points in each Occlusion Volume I would get a fairly accurate chance of knowing what was not in view and could therefore be ignored and not drawn in game.

I wrote all the code to do the calculations using the GPU but now for the problem.  Based on my initial trials it would take 72 hours to calculate the information for the entire usable area of the map!  I decided that was too long to run every time I made a tiny change to any game level!

I was also not confident that the result from the render target was completely accurate because my tests showed that if I put a float value in, the float I got out was close but not identical when rendered!

For my next trick I am attempting to use the grid and simply ray cast between cells.  I have not finished coding this but in the process I have used the Bresenham Line Algorithm.


The algorithm was originally intended to plot a line on early printers in the '60's.  I have come across it before but as it does not include every possible cell that a line could pass through it was no good for my impact calculations.  However for view occlusion I need something that is fast and where a few false positives for grid squares in view will not be harmful to the overall result.

It's only a tiny bit of code but I decided to put my C# XNA versions on CodePlex.  The important bit is that one of the variations I've included gives the result in order from the start to the finish point.  If it is of interest you can view and download it from there.

Saturday, 13 October 2012

MipMaps and Textures

I've been tidying up and improving my code.  Mainly to get my level map files in to a single file and to use the content pipeline to load the maps in to the editor rather than having two sets of loading code.

In the process I have worked out how to create a texture in the content pipeline.

As I am now loading everything in the Content Pipeline I will no longer be using the code that creates MipMaps at run time.  Rather than forget how I did this, I thought I'd add the code here to remind me.

I won't go in to detail but a MipMap is simply a half size version of the main image stored in the same file. Typically several levels of ever decreasing images are stored in the same file.  They are used so that textures displayed at a distance look less pixelated.



If the above image did not use MipMaps then the distance would look grainy.

MipMaps At Run Time

This bit of code generates MipMaps at run time:


/// Create mipmaps for a texture
/// See: http://xboxforums.create.msdn.com/forums/p/60738/377862.aspx
/// Make sure this is only called from the main thread or 
/// when drawing is not already happening.
public static void GenerateMipMaps(
  GraphicsDevice graphicsDevice, 
  SpriteBatch spriteBatch, 
  ref Texture2D inOutImage)
{
  RenderTarget2D target = 
    new RenderTarget2D(
      graphicsDevice, 
      inOutImage.Width, 
      inOutImage.Height, 
      true, 
      SurfaceFormat.Color, 
      DepthFormat.None);
  graphicsDevice.SetRenderTarget(target);
  graphicsDevice.Clear(Color.Black);
  spriteBatch.Begin();
  spriteBatch.Draw(inOutImage, Vector2.Zero, Color.White);
  spriteBatch.End();
  graphicsDevice.SetRenderTarget(null);
  inOutImage.Dispose();
  inOutImage = (Texture2D)target;
}


Textures In The Pipeline

The second bit of code creates images from a byte array in a content processor using the XNA Content Pipeline:


/// Create the texture image from the 
/// Color byte array, Red, Green, Blue, Alpha.
private Texture2DContent BuildTexture(
  byte[] bytes, 
  int sizeWide, 
  string uniqueAssetName)
{
    PixelBitmapContent<Color> bitmap = 
      new PixelBitmapContent<Color>(sizeWide, sizeWide);
    bitmap.SetPixelData(bytes);

    Texture2DContent texture = new Texture2DContent();
    texture.Name = uniqueAssetName;
    texture.Identity = new ContentIdentity();
    texture.Mipmaps.Add(bitmap);
    texture.GenerateMipmaps(true);
    return texture;
}

When I was looking I found similar samples hard to find.  I hope the bits of code may be useful to others.

MipMaps In The Pipeline

The following is how I now create the mipmaps in the content pipeline while loading an image:



///
/// Load and convert an image to the desired format.
/// Returns the image suitable to use as the texture on the Landscape.
///
private Texture2DContent BuildLayerImage(
    ContentProcessorContext context, 
    string filepath)
{
    ExternalReference layerRef = 
        new ExternalReference(filepath);
    
    // Mipmaps required to avoid speckling effects and to avoid moiray patterns.
    // Premultipled alpha required so that the texture layers fade together. 
    OpaqueDataDictionary processorParams = new OpaqueDataDictionary();
    processorParams["ColorKeyColor"] = new Color(255, 0, 255, 255);
    processorParams["ColorKeyEnabled"] = false;
    processorParams["TextureFormat"] = TextureProcessorOutputFormat.DxtCompressed;
    processorParams["GenerateMipmaps"] = true;
    processorParams["ResizeToPowerOfTwo"] = false;
    processorParams["PremultiplyAlpha"] = true;

    // Texture2DContent does not have a default processor.  
    // Use TextureContent and cast to Texture2DContent
    // A processor is required to use the parameters specified.
    return (Texture2DContent)context.BuildAndLoadAsset(
            layerRef, 
            typeof(TextureProcessor).Name, 
            processorParams, 
            null);
}



That code can be called from within the processor using something similar to:


string filepath = Path.Combine(directory, filename);
Texture2DContent LayerImage = BuildLayerImage(context, filepath);


The above was worked out from the following forum and blog posts:
http://xboxforums.create.msdn.com/forums/p/44185/263136.aspx
http://blogs.msdn.com/b/shawnhar/archive/2009/09/14/texture-filtering-mipmaps.aspx

It also helps to know what the parameters are.  You can look them up from the xml file generated by the content pipeline:
Content/obj/x86/Debug/ContentPipeline.xml

The following being extracted from that:


<Importer>TextureImporter</Importer>
<Processor>TextureProcessor</Processor>
<Parameters>
    <Data Key="ColorKeyColor" Type="Framework:Color">FFFF00FF</Data>
    <Data Key="ColorKeyEnabled" Type="bool">true</Data>
    <Data Key="TextureFormat" Type="Processors:TextureProcessorOutputFormat">DxtCompressed</Data>
    <Data Key="GenerateMipmaps" Type="bool">true</Data>
    <Data Key="ResizeToPowerOfTwo" Type="bool">false</Data>
    <Data Key="PremultiplyAlpha" Type="bool">true</Data>
</Parameters>

Already a Texture in the Pipeline

If you want to chain from one processor to another or do more than one thing to a texture you can use the ContentProcessorContext.Convert method to run another processor on the same object.  In the following example the input is an existing texture loaded elsewhere in the pipeline:


TextureContent output = 
    context.Convert<TextureContent, TextureContent>(
        input, 
        typeof(TextureProcessor).Name, 
        processorParams);


If you want to just add the mipmaps to an existing TextureContent image, as shown in the bitmap example earlier in this post, you can call the following method:

input.GenerateMipmaps( true );

The pipeline code is a bit harder to understand but is probably more useful.

===

Here's a discussion thread I found recently about mipmap coding in general:
http://xboxforums.create.msdn.com/forums/t/111550.aspx
And that came from here:
http://xboxforums.create.msdn.com/forums/p/111606/667162.aspx#667162

JCB 23 Sept 2013.

Friday, 13 July 2012

Performance Solved

I have just had the oddest result by fixing one problem I have solved another.  As my wife just pointed out normally it works the other way round.  I normally solve one problem and create two other problems!  Not this time. :-)



To monitor performance while I play the game I use some graphs to avoid creating garbage.  These I display at the sides of the screen to show me memory allocations and CPU usage.  The memory bar goes up and eventually I can see garbage being collected with the momentary slow down on the Xbox.



On the other side I have a performance monitor that measures the time that hardware thread one Update and Draw methods take to complete and a third bar that measures the time taken for the Update that runs on hardware thread four.  These are my primary methods.  The graph is in milliseconds (ms) up to 17 and the bar changes colour to red when any result exceeds 16ms (one frame). 


For a long time I have known that looking in some directions causes a noticeable slowdown and the third bar shows red and off the top of the chart!  Visually the screen would stutter because the position of the view was not being updated quickly enough!  It was probably as annoying as the glitch caused by garbage collection.

As I had run out of things to try to get rid of my remaining garbage I decided it was time that I needed to deal with the performance related hiccup to make it feel nicer to play.

After a bit of fiddling I decided I could not guess where the problem was I needed some way to measure it.  I created myself a simple timer.








    ///  

    /// A static timer which displays the duration of a method in the trace output. 

    /// This is NOT thread safe and cannot be nested. 

    ///  

    public class MethodTimer 
        public static System.Diagnostics.Stopwatch Clock = new Stopwatch(); 
        public static TimeSpan StartTime = TimeSpan.Zero; 
 
        ///  

        /// Mark the starting time to measure from. 

        /// This also starts the timer if it is not already running. 

        ///  

        [Conditional("DEBUG")] 
        public static void Start() 
            if (!Clock.IsRunning) 
                Clock.Start(); 
            StartTime = Clock.Elapsed; 
 
        ///  

        /// Output to the trace window if the duration measured is greater than that specified. 

        ///  

        [Conditional("DEBUG")] 
        public static void Stop(string logName, TimeSpan logDurationOver) 
            if (Clock.IsRunning) 
                TimeSpan duration = Clock.Elapsed; 
                duration -= StartTime; 
                if (duration > logDurationOver) 
                    System.Diagnostics.Debug.WriteLine("Method: " + logName + " took " + duration.TotalMilliseconds.ToString() + " milliseconds!"); 
                return
            System.Diagnostics.Debug.WriteLine("The clock was not running when the Stop method was called!"); 
 




I put it either side of a method and get it to log a result if the time that method takes is longer than I expect.

I was surprised how quickly I got it down to one method causing my problem.  I won't go in to detail about the specific method.  It just simply attempted to do far to much every frame to get more accuracy than I needed.  I produced a much quicker but less accurate version.

Now for the great news.  When I tested that on the Xbox not only had my performance problem completely gone but so had ALL of my memory allocations, no garbage collection!  Two in one.

It's not entirely true that all my memory allocations have gone, but as long as you don't make any new sounds (XACT) or respawn there are none and the tiny allocations that do happen from those methods take a very long time before they would trigger the garbage collection :-)

==

Downloads:
'Performance Tools' including the graphs mentioned above:
http://code.google.com/p/xna-game-menu/downloads/list

Update: 27 July 2012
I have just come across an article written a few years ago  suggesting the same method as above:
http://blogs.msdn.com/b/shawnhar/archive/2009/07/07/profiling-with-stopwatch.aspx

Tuesday, 10 April 2012

GPU Particles Tool

I have done some additions to Diabolical:The Shooter but there is not much that I can easily show yet.  The additions are a few more animations but they need a bit of adjustment before they are ready to show.  These are the actions for changing weapon, reloading, melee and throwing grenades that needed to be merged in to whatever other animation was playing at the time.

The throwing grenades needed some additional work to line up the point at which the grenade leaves the hand with the moment when the particle effect starts to show the grenade in motion in a nice arc.

I was pleased with that and it leads me on to what else I have been working on...  A tool to help create particle effects.  If you are not a game developer you may not be familiar with what Particle Effects are.  This is really a technique for producing things like smoke and explosions, usually using lots of copies of the same image shown many times in different positions.

Combining that in different ways can produce some very interesting and realistic visual effects.




For performance I have elected to use particle effects that are mainly calculated by the GPU, the graphics card, rather than the CPU of the computer or in this case the Xbox 360.

The disadvantage of using the GPU is that the effects cannot be changed once they have started.  They rely entirely on mathematical formulae setup in advance.  The advantage is that they have less of an impact on performance of the rest of the game.


There are several CPU particle engines available with editors to help create the effects but I struggled to find even one tool to help design GPU particle effects... So I created one and put it on CodePlex:
https://gpuparticles.codeplex.com/

It's nothing grand but will do the job for me and I hope a few others may find it useful.

Thursday, 23 February 2012

Update On Another Thread

For some time I have been considering putting the Update processing on a separate thread to the Draw processing.  I had assumed it was difficult to synchronise all the values from one thread to another so I had put it off. 

I have several sections of distinct code, including the Artificial Intelligence (AI) and the Storage which already run on their own threads.  On the Xbox this allows me to specify which processor core they run on and most importantly allows tasks to run in parallel without degrading the performance of the other threads.


#if XBOX
  Thread.CurrentThread.SetProcessorAffinity(
                                     new int[] { 4 });
#endif



The part of the game I am working on is adding non-line of sight weapons.  The trouble is this dramatically increased the number of collision calculations I needed.  Even with only a handful of projectiles on the screen at once the Xbox started to drop a couple of frames.

I considered multi-threading the projectile collision calculations but the design got complicated.  At the same time I have been peer reviewing End Of Days: Infected vs Mercs.  A fun first person shooter which has many elements in common with my game.  Kevin, the developer of that game, was happy to chat about the design.  He said the best performance boost was to have the Update on a separate thread to the Draw.  Thanks Kevin and for the triangle code.

That was enough to make me look further and I found several postings commenting that it was not too difficult and it definitely gave the desired increase in speed.

I had plenty of experience with my other multi-threaded code to know what I needed to look out for.  I had standard code I use to launch and control the thread so I got under way.



private void StartUpdateThread()
{
  // Avoid duplicate threads running.
  if (!isUpdateThreadActive)
  {
    isUpdateThreadActive = true;
    killThreads = false;
    Thread threadUpdate = 
                    new Thread(ProcessUpdateThread);
    // Set to background so that when the foreground 
    // thread dies the background one dies as well
    threadUpdate.IsBackground = true;
    threadUpdate.Start();
  }
}

// Runs on another hardware thread on the Xbox. 
private void ProcessUpdateThread()
{
#if XBOX
  Thread.CurrentThread.SetProcessorAffinity(
                                     new int[] { 4 });
#endif
  updateTime = new GameSelfTimer();
  updateRandom = new Random();
  // Wait a moment for everything to catch up
  Thread.Sleep(5);
  while (!killThreads)
  {
    if (readyToUpdate && !readyToDraw)
    {
      readyToUpdate = false;
      updateTime.Update();
      ProcessUpdate(updateTime);
      readyToDraw = true;
    }
  }
  isUpdateThreadActive = false;
}


The above is the code I use throughout my game for launching and running the threads.

GameTime

I have mentioned elsewhere about the trouble with getting the standard XNA GameTime class on another thread so the first job was to completely replace GameTime throughout the entire code.

I just use my own timer based on a StopWatch.  My timer class has the same properties as GameTime to minimise the code changes.  It took an hour to carefully replace every occurrence and then test while it was still a single thread.

Synchronisation and Buffers

I swapped over and tested without any value being buffered from one thread to the other just simple synchronisation so the update thread only runs when something worth updating has changed.

It worked and showed a dramatic speed improvement but as expected the models on the screen stuttered because they were using incomplete values which were being calculated out of sync by the Update thread.

What did surprise me was how few values are changed and then shared between the Update and Draw threads:


  • View matrix calculated from the player camera position
  • Projection matrix calculated occasionally when the weapon sight zooms in
  • World position of every model
  • Skin transform matrix array for animations

I simply buffer those and use a boolean variable to indicate when changes are ready to update the buffers.  There may be a couple of others I find in time but the above have smoothed the display.



// From the main thread
public virtual void UpdateThreadBuffers()
{
  lock (lockPosition)
  {
    WorldPositionDraw = worldPositionBuffer;
  }
}


I use a base class for all models which mean that I only had to add the Update buffers method in a very few places.

The tricky bit was making sure I called it in the correct place for all instances.  That did not take as long as I expected.  Especially as static models don't need any changes after they are positioned.



// From the main thread.
protected void UpdateThreadBuffers()
{
  if (readyToDraw)
  {
    gameManager.Shading.UpdateThreadBuffers();
    for (int i = 0; i < Controllers.Count; i++)
    {
      Controllers[i].UpdateThreadBuffers();
    }
    PortableItems.UpdateDroppedThreadBuffers();
    // Always the last thing so update will run again
    readyToDraw = false;
  }
}


I also use 3D moving and animated models on some menus and option screens so I had to make changes outside of the main game to keep those screens compatible.

Job done.  Loads more processing capacity for the extra collision calculations I need, good frame rate and it should make future changes much easier.

Sunday, 11 December 2011

GameTime in another Thread

I run all the AI in Diabolical: The Shooter in a separate thread.  On the Xbox this is a hardware thread.  While working on the Behaviour Tree that I am currently in the process of implementing I found I needed to keep track of time.

The time is used to avoid tasks taking too long and making the Bot look daft.  It did not take me long to realise that getting the main thread GameTime in to another thread is not that easy.  In fact the following post from the XNA forums convinced me that I should not try: http://xboxforums.create.msdn.com/forums/t/10587.aspx

In the post Shawn Hargreaves suggests using a Stopwatch.  As Shawn wrote a large chunk of the XNA framework I have a lot of respect for his suggestions and taking that advice usually saves me a lot of work.  So without any hesitation that is what I did. 

I need to pass the time round to lots of behaviours.  The Stopwatch is a class so I could pass that round easily.  It's results are TimeSpan's which are structures so not as fast for passing as a parameter.  I would have liked some of the convenience of the GameTime class however it was unclear from the documentation if it included its own timer so I decided to write my own wrapper for a Stopwatch.

As it turned out all I needed was the following:


// Use a stopwatch to keep track of 
// the time for other threads
public class ThreadTimer
{
    private Stopwatch threadTime;

    // Create and start the timer.
    public ThreadTimer()
    {
        threadTime = Stopwatch.StartNew();
    }
    // The time since the timer was started
    public TimeSpan CurrentTime
    {
        get { return threadTime.Elapsed; }
    }
    // Calculate the future time after a number of 
    // seconds has been added to the current time.
    public TimeSpan EndTimeAfter(float howManySeconds)
    {
        return CurrentTime + 
               TimeSpan.FromSeconds(howManySeconds);
    }
}


I start that class whenever the new AI thread starts:


private void ProcessBehaviourUpdatesThread()
{
#if XBOX
    // First move on to the desired 
    // hardware thread
    int[] cpu = new int[1];
    cpu[0] = 5;
    Thread.CurrentThread.SetProcessorAffinity(cpu);
#endif
    // Each thread needs it's own random
    random = new Random();
    // Use the time to prevent run away behaviour
    threadTime = new ThreadTimer();
    // Keep the thread processing requests
    while (!KillThreads)
    {
        UpdateBehaviour();
        // Allow for anything else that runs 
        // on this hardware thread to get a chance.
        Thread.Sleep(
               GameSettings.botLoopSleepMilliSeconds);
    }
    IsBehaviourThreadActive = false;
}


That 'threadTime' is then passed to the Update() method of each behaviour. 

While mentioning threads I also pass the Random class as well.  That is another thing that is awkward with threads.  For some reason each thread must have its own Random.  I pass the reference to that in the Update() as well.



I'm please with how my Behaviour Tree is coming along.  At the moment it is untested but already it is more flexible and neater code than the State Machine I was using before.  The main code is done and now I am adding the individual behaviour classes.  I'll probably go in to more detail when I have it tested.

Wednesday, 6 July 2011

Exporting Animated Models From Blender To XNA

If you want to develop a 3D game you will probably spend as much time creating the content as writing code. I am not an artist but I have found that Blender is a fully featured 3D editor that with a few weeks practice I was able to create models that I could use with XNA. The pipeline to get animated models from Blender to XNA needs to be followed closely but once understood is as easy as any other tool.

XNA and Blender are still being developed, improved and updated. Changes to both platforms have affected the methods required to have a successful pipeline. Follow the specific instructions for the XNA and Blender versions you are using.

Instructions for creating models that can be exported to XNA

Getting models to look right when they are imported in to XNA can cause a lot of confusion.  Like many things it is not difficult when you know how. 

There are several techniques that look fine from within Blender but which either have to be avoided or adhered to if you want to use that model in XNA.
This is a summary of the most common things that catch people out:
  • All the model objects (meshes) and the armature must be centred at the same location, ideally zero (X = 0.0, Y = 0.0, Z = 0.0 in the Object properties.) Set the locations to zero in Object mode and make all changes in EDIT mode.
  • All the model objects must have a scale of 1.0 (one.) Set all the scales to 1.0 in Object mode then do all changes in EDIT mode.
  • The model objects must not use rotation. Set all the rotations to 0.0 in Object mode then do all changes in EDIT mode.
  • Every vertex must be weight painted or added manually to a bone vertex group. Any loan vertex will cause an error when importing in to XNA. To check you have bone weights for all vertices pull the model about in POSE mode. Any un-weighted points will be left behind when posing the armature.
  • The XNA model class only supports UV wrapped textures. Blender's shading only work in Blender not in XNA. 
  • The FBX importer only support keyframe animations from Blender Actions and will not work with Blender's curves.
  • In XNA set the 'Content Processor' for the FBX model to 'SkinnedModelProcessor' or whatever your processor name is - this is the most common oversight.

To explain in more detail:

(Update Dec.2012 for Blender 2.6) The quick way to do this without changing the appearance of the model is to use the Apply menu in Object mode.  Select the object (mesh) and use CTRL+A to bring up a small menu and then L to move the location of the origin to zero, R to fix the rotation to where it is and S to fix the scale.

As a rule of thumb, once you have set all the Blender objects properties to a location and rotation of zero and a scale of one all the modelling will be done in Blender's EDIT mode.



Blender is easiest to use if models are created with up in the Z direction. XNA's default is that models use Y as the up direction! From trial and error I have found it is easier to rotate the model when imported in to XNA rather than trying to work in Blender the wrong way up! Animations do not rotate very well in Blender, usually resulting in a mess!   Using the rotation options in Blender's FBX exporter always results in a mess!



I have an XNA project with a content pipeline animation processor that includes a method for rotating 3D models while they are loaded including rotating their animations. Its only a few lines of code inserted at the correct point. 


public static void RotateAll(NodeContent node, 
                             float degX, 
                             float degY, 
                             float degZ)
{
  Matrix rotate = Matrix.Identity *
    Matrix.CreateRotationX(MathHelper.ToRadians(degX)) *
    Matrix.CreateRotationY(MathHelper.ToRadians(degY)) *
    Matrix.CreateRotationZ(MathHelper.ToRadians(degZ));
  MeshHelper.TransformScene(node, rotate);
}
  

Use a rotation of X = 90, Y = 0, Z = 180 to rotate from Blender to XNA during the pipeline processing. Download that project source code using a Subversion client to see how its done: http://code.google.com/p/3d-model-prep/

You can download just the XNA Skinned Model Processor with corrected rotation from:
http://code.google.com/p/3d-model-prep/downloads/list


There is one last thing to watch out for.  Poorly finished models with orphan vertices or edges are likely to cause errors or warnings during the import in to XNA.  This is a common result of preparing a model to be game ready especially when reducing the numbers of faces a model uses to improve performance.  I have a separate post on finding missing edges: http://blog.diabolicalgame.co.uk/2011/07/vertex-information-missing.html
This is not so important with the latest Blender FBX exporter because I have made that ignore lone vertices.


Setting up the animations


There are some prerequisites for creating animations and I have put those in another post:
http://blog.diabolicalgame.co.uk/2011/07/before-animating-with-blender.html



Exporting FBX Files

In versions of Blender prior to 2.59 the standard FBX export script that ships with Blender is NOT suitable for XNA. If you want to use XNA 4 please upgrade to at least 2.6x of Blender.  There are some older instructions at the end if you are still using XNA 3.

From Blender 2.59 onwards the official FBX exporter supports XNA.

Blender 2.59 and 2.6+ to XNA 4.0

To work with XNA you must be using a version of Blender greater than 2.59.  At the time of updating this page 2.60a is the latest stable version of Blender. 

The official Autodesk FBX exporter included with that version supports XNA.  The export script has general documentation on the Blender Wiki:

The above image shows the typical setting for use with XNA.  It is necessary to change the default settings when working with animations.  The default works for non-animated models but the rotation breaks animations.  The default options also include more information in the file than XNA can use.

As a quick way to export XNA compatible files there is a tick box that sets all the required options:


It is mainly the 'XNA Rotate Animation Hack' and the Path mode: 'Strip Path' that are needed.  This stops any rotation of the model and requires that all texture files are stored in the same folder as the FBX file.

The 'XNA Strict Options' is just a quick way to set the essential XNA options.  One tick and all the settings work.  You can still adjust some of the settings but it prevents you accidentally changing a necessary option.

Individual Animations
The Autodesk FBX importer shipped with XNA 4.0 introduced the limitation that only one animation can be loaded from an FBX file. The updated version with the Windows Phone 7.1 SDK tried to fix this but included a bug so the number of frames in all animations was the same as the first take!  

The Blender script not only has an option to output in a compatible format for XNA but also has an option to output 'All Actions' or if that is not selected, to output just the currently selected animation. 



Just having one animation in each FBX file is the solution that works best with the current (November 2011) version of XNA.





In POSE mode use the 'Action Editor' to select the animation to export.


Then export and make sure the option for 'All Actions' is off.



==



Blender 2.49b to XNA 3.1 or older [Archive]

At the time of writing the last version of the old series of Blender is 2.49b.  In order to use older versions of XNA you will probably need to use the older series of Blender but make sure it is version 2.49b. Earlier versions have issues. Specifically 2.49a has a fault preventing scripts from running! (Nov.2010)
Essential script
As mentioned above the standard FBX exporter will not work with XNA it is essential to use the following script or a variant of it:
http://wiki.blender.org/index.php/Extensions:2.4/Py/Scripts/Export/FBX-XNA
This script is NOT shipped with Blender and must be downloaded and installed.

Download an XNA 3.1 compatible exporter from:
http://www.discoverthat.co.uk/games/blenderscripts/export_fbx_for_xna_v122a.py
or
http://www.triplebgames.com/export_fbx__for_xna.py

Copy the script in to the Blender script folder.  In Windows Blender 2.49b scripts are stored in:
%USERPROFILE%\AppData\[Roaming]\Blender Foundation\Blender\.blender\scripts

Installation of Blender 2.4 Python scripts
The scripting language used by Blender is Python. In the older versions of Blender up to and including 2.49b you'll need to download and install the full version of the Python scripting language 'Python' to use these scripts. You must install the matching version for the version of Blender you have. It tells you in the console Window when you start Blender. For example, Blender 2.48 required version 2.5 of Python (the sub version is not critical so version 2.5.2 and version 2.5.4 both work but version 2.6 would not.) Get from Python.org.

==



Blender 2.56 to 2.58 [Archive]

These early 2.5x versions shipped with a separate compatible exporter.  I strongly recommend using the newer 2.59 version but the instructions for the older version are still on the Blender Wiki: