Archive for the ‘ coding ’ Category

How to split animations via script in Unity3D Editor

If you’ve purchased a set of 3D models (let’s say, a pack of zombie models) that come with an animation list, then you know what a pain it is to sit and add each animation name/start/end frame in the editor.  It’s not always necessary, but in this particular occasion, I had to do it for each model.

Thanks to someone over at Automation Systems Group, I was able to use one of their scripts ( with a slight edit for an error due to legacy code ) in the editor to add the animation clips via a text file.

The code below explains everything essentially, including how to format the txt file:

 

// FbxAnimListPostprocessor.cs : Use an external text file to import a list of

// splitted animations for FBX 3D models.
//
// Put this script in your "Assets/Editor" directory. When Importing or
// Reimporting a FBX file, the script will search a text file with the
// same name and the ".txt" extension.
// File format: one line per animation clip "firstFrame-lastFrame loopFlag animationName"
// The keyworks "loop" or "noloop" are optional.
// Example:
// 0-50 loop Move forward
// 100-190 die

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Text.RegularExpressions;
using System;

public class FbxAnimListPostprocessor : AssetPostprocessor
{
 public void OnPreprocessModel()
 {
 if (Path.GetExtension(assetPath).ToLower() == ".fbx"
 && !assetPath.Contains("@"))
 {
 try
 {
 // Remove 6 chars because dataPath and assetPath both contain "assets" directory
 string fileAnim = Application.dataPath + Path.ChangeExtension(assetPath, ".txt").Substring(6);
 StreamReader file = new StreamReader(fileAnim);

 string sAnimList = file.ReadToEnd();
 file.Close();

 if (EditorUtility.DisplayDialog("FBX Animation Import from file",
 fileAnim, "Import", "Cancel"))
 {
 System.Collections.ArrayList List = new ArrayList();
 ParseAnimFile(sAnimList, ref List);

 ModelImporter modelImporter = assetImporter as ModelImporter;
 modelImporter.clipAnimations = (ModelImporterClipAnimation[])
 List.ToArray(typeof(ModelImporterClipAnimation));

 EditorUtility.DisplayDialog("Imported animations",
 "Number of imported clips: "
 + modelImporter.clipAnimations.GetLength(0).ToString(), "OK");
 }
 }
 catch {}
 // (Exception e) { EditorUtility.DisplayDialog("Imported animations", e.Message, "OK"); }
 }
 }

 void ParseAnimFile(string sAnimList, ref System.Collections.ArrayList List)
 {
 Regex regexString = new Regex(" *(?<firstFrame>[0-9]+) *- *(?<lastFrame>[0-9]+) *(?<loop>(loop|noloop| )) *(?<name>[^\r^\n]*[^\r^\n^ ])",
 RegexOptions.Compiled | RegexOptions.ExplicitCapture);

 Match match = regexString.Match(sAnimList, 0);
 while (match.Success)
 {
 ModelImporterClipAnimation clip = new ModelImporterClipAnimation();

 if (match.Groups["firstFrame"].Success)
 {
 clip.firstFrame = System.Convert.ToInt32(match.Groups["firstFrame"].Value, 10);
 }
 if (match.Groups["lastFrame"].Success)
 {
 clip.lastFrame = System.Convert.ToInt32(match.Groups["lastFrame"].Value, 10);
 }
 if (match.Groups["loop"].Success)
 {
 clip.loop = match.Groups["loop"].Value == "loop";
 }
 if (match.Groups["name"].Success)
 {
 clip.name = match.Groups["name"].Value;
 }

 List.Add(clip);

 match = regexString.Match(sAnimList, match.Index + match.Length);
 }
 }
}
Advertisements

Fish GL Released

Fish GL Tank

Fish GL Tank

Well for the past 2 months I’ve been tucked away working on my first official WebGL project – FishGL (www.fishGL.com, www.fishgl/mobile for mobile)!  The Internet Explorer team wanted to create a graphics showcase with the classic “fish bowl” theme and enlisted ThinkPixelLab.com to create the experience along with Scott Wetterschneider as the 3D artist.

The Fish Tank has many interactive features and elements that bring and rich experience to not only the desktop, but to touch devices as well.  In fact, you’ll have the most fun with the Fish Tank if you’re on a touch device since it has features that allow you to pan and zoom around the room, tap the glass, feed the fish and even SWIM with the fish!  There’s also a couple of nice easter-eggs for those of you who like to explore.

Some features include:

  • Swim in tank (click diver mask on panel)
  • Add fish to the tank with the fish dial
  • Set algae level with “last cleaned” slider
  • Tap the glass to scatter fish
  • Feed the fish by tapping the food jar
  • Turn the lights on and off with the light switch on the wall
  • Advanced panel gives you a TON of options for customizing the scene (hit the second dot at the top of the panel to switch to the advanced panel)
  • Real-time lighting from the sun and tank light as well as shadows (turn shadows on via the advanced panel)
  • Change clean/dirty water tint for in-tank swimming experience.  To see the change, change the amount of algae in the water while simming
  • Change color of light in the tank as well as its intensity, distance
  • Change the tank glass to your liking
  • Work with the realism of the gravel in the tank
  • … and so much more!

You can create a tank that matches your mood, room, computer, phone or whatever you like:

If you had told me 6 months ago that I would be working on a WebGL project, I would have laughed you of my office waving my Unity3D banner!  But God has been good and blessed me with some awesome people to work with at ThinkPixelLab.com – namely, Robby Ingebretsen and Joe Fillmore.  Super cool people, extremely talented in what they do and very patient!

If you’re interested in creating 3D WebGL content, I’d encourage you to look at the Three.js library – the api’s nomenclature and approach is right inline with other technologies like Unity3D, so getting up and running is very easy.

 

Creating Cube map / Environment map in Three.js with preloaded assets

[tweetmeme source=”neoRiley” only_single=false] All the Three.js samples I found were all using the same technique of just passing the image URL’s in an array to  ImageUtils.loadTextureCube() , and used whatever it returned as the necessary texture for a environment, reflection or refraction map.  Well, I’d written an AssetManager to preload all necessary assets for creating our scene, and when it came time to assemble the reflection map, I had to dig through the source code to see what ImageUtils.loadTextureCube() was actually producing and how.

In my scenario, I have a class that is called CubeMap and after passing it the image URL’s, it takes care of preparing what is to be preloaded with the AssetManager.  When the AssetManager has completed the preload, I then have access to CubeMap.texturesArray, which is an array of the preloaded images, and I can then put together the environment map texture I need:

// create a new THREE.Texture
var envMap = new THREE.Texture();

// After preloading your images, set the image property of your new texture to the array of images you preloaded
envMap.image = this.tankReflectionBox.texturesArray; // array of images = [];

// Set the mapping type
envMap.mapping = new THREE.CubeReflectionMapping();

// You have to set this to false, otherwise your images will be inverted on the Y axis
envMap.flipY = false;

// Mark as dirty, otherwise you won't see anything
envMap.needsUpdate = true;

Have a bandit day!

Error with Three.js shader – ERROR :GL_INVALID_OPERATION – fix

[tweetmeme source=”neoRiley” only_single=false] I was just in the process of trying to narrow down what does and doesn’t work in IE11 with Three.js’ shaders and ran into this error message while working with the normalmap shader:

ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 1

The fix is to simply call computeTangents() on your mesh’s geometry object, and bingo, we’re in business:

model.geometry.computeTangents();

Here’s the block for context:

var shader = THREE.ShaderLib[ "normalmap" ];</pre>
var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

uniforms[ "enableAO" ].value = false;
uniforms[ "enableDiffuse" ].value = true;
uniforms[ "enableSpecular" ].value = true;

uniforms[ "tDiffuse" ].value = fdo.colorMap;
uniforms[ "tNormal" ].value = fdo.normalMap;
uniforms[ "tSpecular" ].value = fdo.specularMap;

uniforms[ "diffuse" ].value.setHex( 0xFFFFFF );
uniforms[ "specular" ].value.setHex( 0xFFFFFF );
uniforms[ "ambient" ].value.setHex( 0x222222 );

uniforms[ "shininess" ].value = 10;
parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true };
mat = new THREE.ShaderMaterial( parameters );

model.geometry.computeTangents();
model.material = mat;

Singletons in Unity3D

[tweetmeme source=”neoRiley” only_single=false]Here are many different ways of doing singletons in Unity3D – 1) the usual way, 2) the “self contained” way and 3) the quick and dirty way 4) for you c# folks, the accessor way.

1. The Usual Way

The usual way is to have a static “GetInstance()” method on the class  that’s attached to a GameObject in the IDE, and check for an instance.  If it exists, pass it back.  If it doesn’t, return a Debug.LogWarning error about how they need to have a GameObject with the class attached to it.

public class MyClass
{
	private static MyClass instance;
	public static MyClass GetInstance()
	{
		if (!instance)
		{
			instance = GameObject.FindObjectOfType(typeof(MyClass));
			if (!instance)
				Debug.LogError("There needs to be one active MyClass script on a GameObject in your scene.");
		}

		return instance;
	}
}

2. The “self contained” way

At one point in the Trench Run game, I realized my scene was filled with quite a few GameObjects JUST for my classes. So, I developed the “self contained” singleton.  If it doesn’t find an instance, it creates its own GameObject, attaches the class instance to it via AddComponent() bingo, no need to create a GameObject in the IDE and clutter up your scene at design time.

public class Logger : MonoBehaviour
{
	private static Logger instance;
	private static GameObject container;
	public static Logger GetInstance()
	{
		if( !instance )
		{
			container = new GameObject();
			container.name = "Logger";
			instance = container.AddComponent(typeof(Logger)) as Logger;
		}
		return instance;
	}
}

3) The quick and dirty way

The quick and dirty way is simply that – setup a public static property for the instance, initialize in the Awake() method, attach to a GameObject at design time, done. In code, it’s a little more direct now with:

MyClass.instance.DoSomething();

The setup:

public class MyClass
{
	public static MyClass instance;
	public void Awake()
	{
		MyClass.instance = this;
	}
}

It’s been noted in ActionScript that accessing another method outside of the class you’re in is slower than accessing a property.  I have no idea if this is the case with Unity ( I seriously doubt it ), but with my optimization nightmares in Flash over the years, I’m usually doing #3.  Some habits just never go away (or paranoia for that matter)

Enjoy!

[**** UPDATED ****]

4. Accessor

The #1 and #2 examples above could benefit from using an accessor rather than a method – Thanks to Cliff Owen for the tip on this

public class MyClass
{
	private static MyClass _instance;
	public static MyClass Instance
	{
		get
		{
			if (!_instance)
			{
				_instance = GameObject.FindObjectOfType(typeof(MyClass));
				if (!_instance)
				{
					GameObject container = new GameObject();
					container.name = "MyClassContainer";
					_instance = container.AddComponent(typeof(MyClass)) as MyClass;
				}
			}

			return _instance;
		}
	}
}

Then, you’d just as simply as the quick and dirty way access it with:

MyClass.Instance.DoSomething();

Coming from ActionScript / UnityScript to c#

[tweetmeme source=”neoRiley” only_single=false]After writing iFly and Star Wars: Trench Run in UnityScript, I became painfully aware of the shortcomings associated with UnityScript.  Mainly that it has no decent event / delegate system to leverage.  Sure, you have event handler methods that exist in GameObject etc, but that’s a complete throw back to AS2/1 days.  I tried porting an old AS2 event dispatcher class to UnityScript (which I did successfully) but had pointed out to me by someone at Unity that it would be painfully slow.  He then suggested I consider c# and get involved with delegates.  He was right.

So, for a while now, I’ve been doing c# and loving it.  There were, however, some things that obviously caused me some discomfort and that’s why I’m writing this post.  I’ll be adding to it when ever I find new topics that apply.

First, here is a link that provides the majority of the “differences” between UnityScript and c# – I recommend this one as it really covers the basics very well.  I’ll be covering the not-so-obvious ones that made me scratch my head 😉

http://answers.unity3d.com/questions/5507/what-are-the-syntax-differences-in-c-and-javascript

Alright then, here’s the first thing to look out for:

Number = float

Coming from AS3, you’re used to Number, int, uint and for the most part, you get what they do.  When coming over to c#, there is no “Number” type.  Instead, use float.  Just think of it in the most simple terms:  “f”loat for “fraction”.  Meaning, if you know you’re number will be fractional (like 3.16) then give it a type of float:

float myScale = .5f;

Note the “f” at the end of the declaration (.5f) – that’s how you cast it as a float.  If you don’t, Unity compiler will give you an error.  Same goes for passing floats as arguments, make sure you include the “f” cast:

Vector3 pos = new Vector3(.1f, .05f, 2);  // you can add the "f" cast after a whole number if you like, but it's not necessary

If you’re doing some division or scaling math and you know the outcome *could* be fractional, both sides of the equation need to be floats or you’ll get a whole value in return.  Simple enough you might think, but I’ll bet you scratch your head at least one time on this one where you can’t figure out *WHY* it’s not calculating a remainder for you:

float i = 15f;
float j = 10f;
float value = i / j; // 1.5f

If you want to parse a string into a float or int:

int value = int.Parse(stringValue);
float value = float.Parse(stringValue);

If you want a whole number and an int from a float, use FloorToInt() – I mention this one simply because of how AS3 just doesn’t give a crap, but c# does:

int value = Mathf.FloorToInt(float n);

Event Dispatching

In AS3, everything extends EventDispatcher practically.   Everything can dispatch events, have listeners and everyone’s happy in their little event driven world.  Then you come over to Unity and realize, we’ve taken a step back into AS1/2 land. There are event handlers on GameObjects and if you declare them, then they will receive the calls – very very onEnterFrame type of stuff here.

So, given my history and experience with AS2, I naturally dusted off an old EventDispatcher class that we used to use back in the day.  Like I said above, I converted it, it worked, but was made to realize that in a performance setting, it’d be a pretty substantial bottle neck.  Still, if you’d like to see how it’s done, here you go ( now at least, I won’t feel like the time I spent on it was wasted )

EventDispatcher.js
ListenerObject.js

But now, the real deal in c# for creating an event and dispatching goes something like this:

Declare a delegate for the event. Note that I’ve created it outside the class declaration – this is so it’s available to any class:

public delegate void LoadComplete(float value);
public class MyClass
{
    //...
}

Now, create the event in MyClass:

public delegate void LoadComplete(float value);
public class MyClass
{
public event LoadComplete LoadCompleteEvent;
}

To add a listener, you add a new delegate instance with the handler to the LoadCompleteEvent event:

public delegate void LoadComplete(float value);
public class MyClass
{
public event LoadComplete LoadCompleteEvent;
    public void Start()
    {
        LoadCompleteEvent += new LoadComplete(HandleLoadComplete);
    }

    // note how the argument signature matches the delegate declaration
    private void HandleLoadComplete(float someValue)
    {
        // event handled here
    }
}

To send out the event, first check to make sure the event is not null (has listeners), then call it like a method:

public void DoSomething()
{
    if( LoadCompleteEvent != null ) LoadCompleteEvent(1.0f);
}

To remove a listener, just remove the handler from the event:

LoadCompleteEvent -= HandleLoadComplete;

Coroutines (replacement for setTimout, setInterval, Timer object)

In AS3, we’re used to setTimeout() or the Timer object to deal with waiting and looping stuff.  In the old days, we used onEnterFrame and I can still remember the arguments over which was better – setInterval or onEnterFrame.  It was a ridiculous argument, because in reality, it just depended on *what* you were doing when that even fired.  Please don’t leave comments regarding this tired and exhausted discussion which has zero relevance these days 😉

In UnityScript, you’ll be introduced to WaitForSeconds() which is really nice when coming from AS3.  In c#, however, you get a bit of a rude awakening. You begin to realize how much UnityScript lets you get away with.  Its insane.

So, here are the basics.

If you want to loop or wait a certain amount of time, you have to call a method that returns IEnumerator:

public IEnumerator DoMyBidding() {...};

Then, you have to have some sort of yield/return statement in this method or the compiler with barf all over your keyboard:

public IEnumerator DoMyBidding()
{
    yield return WaitForSeconds(1.5f);
    if( myConditionNotMet ) yield return null;  // this is how you just simply return out if you no longer wish to continue.
}

If you want to loop something:

public IEnumerator MonitorMe()
{
    while ( conditionNotMet )
    {
        // do something
        yield return WaitForSeconds(.025f);
    }
}

To call these methods, you have to use StartCoroutine():

public void Start()
{
    StartCoroutine( MonitorMe() );
}

Well, for now, that’ll get you started, and as I remember/think of things, I’ll come back and update this post with more tid-bits.  Enjoy!