Tuesday, 25 December 2012

Sci-Fi Alien Weapons

As usual with modelling it has taken me a about three weekends to create one model.

I drew the concept on the 10th of December and put the final touches to the finished weapon and added it to the game on Christmas Eve.



It's inspired by, in fact deliberately similar to, the alien style weapons pack I purchased from Garage Games



That set only includes 3 models and I needed an additional larger support weapon for the aliens.


I am getting the hang of 3D modelling and the basic untextured model only took a day.  What takes all the time is the UV unwrapping and then the texturing.

I always start by creating the Ambient Occlusion layer for my texture.



It does not help that I have to do some bits twice because I forget to set some parts of the model as smooth before creating the Ambient Occlusion (AO).


Without using the smooth option on parts of the model that are curved, the AO shading is banded instead of continuous.



I always like the model with the AO texture.  Shame I can't leave it that way.  I have seen a game where that was the style of the game.  It looked very good but not what I want for Diabolical: The Shooter.

If my artistic skills were better I would be able to create the texture quicker.  I have to put most of it togther from parts.  More like contruction than drawing.  I go through each part, as split by the UV unwrapping, and add details as separate components and blended in to the base colour.  Layer after layer after layer.



I am starting to learn some of the techniques but it takes me time.

For some reason it ended up grey but for this model I wanted it a more silver colour to match the others.  I used a bit of brightness but mainly I adjusted the gamma correction curve to get something more silver.



The in game lighting adds a bit more shine to the surfaces.



Merry Christmas to all.  25 Dec. 2012.

Thursday, 20 December 2012

Winform Map Editor

Last night I finished my side project of migrating the map editor from being a game screen to being a normal windows application (Winform.)  I've been doing this when I needed a break from 3D modelling. 


At the moment all I have attempted to do is move all the features I had before in to a separate project.  I did find a few minor bug fixes but it is basically the same.

The only major change was to the controls for moving about the map.  It now works more like a 3D modelling programme, in fact the rotate, zoom and move are very similar to Blender.  I have however retained first person keyboard controls for fine adjustments.

I am doing most of the modelling in Blender so the new controls are much more familiar when I bring the models in to the editor.

I have left space to the side and bottom of the main view window to put properties.  I have not coded anything to go there yet but in time I will add something useful.

The editor is still linked to the main game.  It shares some of the rendering code and all of the map loading code.  I compile the editor project in the same solution as the main game.  This means that the map files will always remain compatible.

I find it works well.  The only peculiarity I had was that the game view control from the Microsoft sample is external.  Exceptions thrown in the game view crash the control but the rest of the Winform app continues without error.  The view window goes white with a red cross in it!

I fixed that with a simple try and catch wrapped round my update and draw code:


/// 
/// Redraws the control in response 
/// to a WinForms paint message.
/// 
protected override void OnPaint(PaintEventArgs e)
{
    try
    {
        string beginDrawError = BeginDraw();

        if (string.IsNullOrEmpty(beginDrawError))
        {
            // Slow the game down to no more 
            // than 60 fps (16.667ms per frame)
            if (gameTime.ElapsedUpdateTime > 
                TimeSpan.FromMilliseconds(16))
            {
                // My own version of GameTime
                // based on a stopwatch.
                gameTime.Update();
                // Simulate the update loop in 
                // an XNA game.
                Update(gameTime);
                // Draw the control using the 
                // GraphicsDevice.
                Draw(gameTime);
                EndDraw();
            }
        }
        else
        {
            // If BeginDraw failed, show an error 
            // message using System.Drawing.
            PaintUsingSystemDrawing(e.Graphics, 
                                    beginDrawError);
        }
    }
    catch (Exception ex)
    {
        // Exceptions within external applications do 
        // not automatically break the parent form.
        // These lines trap the exception, display the 
        // error and break the parent code for debugging.
        System.Diagnostics.Debug.WriteLine(
            "Exception in Update or Draw: " + 
            ex.Message + " in " + ex.Source);
        System.Diagnostics.Debug.WriteLine(
            "Stack trace: " + ex.StackTrace);
        throw new Exception(ex.Message);
    }
}

The whole app now crashes and the exception is displayed to help debugging.

In addition to being able to position, models, triggers, waypoints and generate the navigation mesh used by Bots, I have loads of helper overlays within the editor.  Too many to list:


I nearly forgot.  There was a point to moving the editor out of the main game. 

Every time I tried to change the game I had to keep it compatible with the editor.  There was often lots of extra code just so the game remained fast and the editor had features.

When I started looking at adding in the networking code it just got too complicated to do what I wanted and retain compatibility.  That's what kicked off this little side project.

It's how I should have done it in the first place.

Sunday, 9 December 2012

One Line Of Code

I am sure that everyone has these days when coding.  This is just a quick note to remind people to keep on going no matter how bleak things appear!

I had been working away on the new weapons and effects and got round to testing everything on the Xbox.  I do this from time to time because the Xbox does not perform in the same way as the PC does.  Much to my surprise the performance was a disaster on the Xbox!

That was late yesterday and I was going out in the evening so I left it wondering how long it would take to find whatever it was I had done to cause a frame rate of just 9 frames per second!  It was perfect on the PC but the Xbox was unplayable!

I had thoughts of the level being too complicated and having to come up with some clever code to cull more efficiently, or that the texture files were too large, so I would have to reduce the quality.  I had quickly ruled out the particle effects because although they were pretty the code, quantity and textures sizes were unchanged to effects I had been using for years and the performance graphs did not change when they were on the screen.



I've been working in I.T. long enough to know that whatever you last changed is the most likely cause for whatever problem you are now investigating.  This morning I therefore thought through all the changes since the last time I had successfully tested on the Xbox...

I thought it was a fairly easy non-performance affecting change but I have completely re-written the Audio Manager to change from using XACT to using the SoundEffect classes.

Some quick commenting out and I very rapidly confirmed that somewhere in my conversion I had made a mistake.  To cut an hours searching down I found it.

Just one very short line of code:
nextSong = "";

I had an endless loop that would start playing the next waiting piece of background music every frame because I had not cleared the variable once it started playing!

I am a lot happier now and I can go back to creating assets and effects for the game.

Sunday, 2 December 2012

New Weapons New Effects

After having completed modelling the new alien sci-fi weapons and getting them in to the game I wanted to complete them with their own sounds and visual projectile effects.




I am pleased with the results.  The picture above is just one of them.  I have three weapons ready and two particle effects.  Two of the weapons share the same ammunition so the same effect.

The effects are created with particles and I use a tool I wrote for myself to help adjust the effect until I am happy with it.  I created the tool as open source so anyone can use it: https://gpuparticles.codeplex.com/

I find it takes a while to edit the 2D images used for the particles.  It's not that the particle textures need to be complicated it's just that it is difficult to visualise what they will look like in the effect until you try them.  There's a lot of back and forth getting things as I want them.

That's the texture from the other effect I have created.

Now for the sound effects.  I was able to find some public domain and creative common licenced sounds that are just right for the sci-fi sounding shots.  At the moment I have used them 'as is' but they need some minor adjustments.  The main change and my next task is to normalise all the volume levels so they are all the same volume relative to each other.

That's a job for next weekend I think.

Saturday, 24 November 2012

3D Modelling Takes Time

I haven't posted for over a month.  I didn't want you all to think I had given up.

I have been working away converting models for use in the game.  The first level overall layout is complete.  It needs some aesthetic improvements, mainly on the ground textures but it is getting there.

I got to a stage where I needed to add some weapon pickups so I need the weapon models.  I may have mentioned previously that finding pre-made models in a SciFi style is quite difficult.  I found these weapons for use in the Torque 3D engine by Garage Games.



The style is ideal for Diabolical but all the weapons have to be at the correct scale and orientation and the grips have to be in the right places to line up with the animations.  There are also some bits used by the Torque 3D engine that I do not need for my game engine.



It may not sound like a long task but making those few changes takes me several hours per weapon so with only a few hours available each weekend recently it has taken me a few weeks.  The limited time available has mainly been due to playing through Halo 4 :-)

Nearly there with these weapons then I need to add the particle effects and get them in the game.

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.

Sunday, 16 September 2012

Bake A Pose In Blender

Following on from my post the other day about importing in to Blender.  I need to change the bind pose to the T form so that all my animations start off from the same pose.


Repositioning the model can be done by posing the model using the armature.  The trouble is that the moment you try to edit the mesh it always reverts to the original rest pose position. 



I want to set the vertices in the posed position and for them to stay there.

I am sure I used to be able to move the model in pose mode and then apply that pose as the rest pose.  I tried that and tried searching Google but nothing worked.

I eventually found what I needed and it is very simple. 

Before doing anything save a separate copy of the file because you may want to go back and change your mind about the pose but the following removes the armature from the mesh.

Fixing the Pose

Pose the model in whatever form needed, swap back to Object mode and select the model not the armature and then simply press the button to apply the armature modifier.



Job done, the Object is now separated from the armature and remains in the pose it was last in when you edit it.


It is not always ideal to remove the armature but at least I can re-add an armature if necessary.

It's taken me most of the afternoon to work out how to do this but now I have run out of time.  Sunday dinner is ready and I am unlikely to have time to edit the pose in to the T-pose until next weekend!