Everyday 3D

Creative use of technology // A blog about 3D Flash and Actionscript by Bartek Drozdz

C# events and Unity3d

Did you know that C# has a built-in event system? And a very good one! It can be quite useful with Unity3D. Here's an example.

In order to respond to events dispatched by a GameObject you typically would create a script that extends MonoBehaviour and implement the methods you need. So if you want to react to the user hovering the object with the mouse you would create the OnMouseOver method. It would typically look something like this:

C#:
  1. void OnMouseOver () {
  2. renderer.material.color = Color.red;
  3. }

That works fine. But what if you want another object to be notified about that event? One way would be to keep a reference to that other object in your script and call it from within your method:

C#:
  1. public MyScript myScript;
  2. void OnMouseOver () {
  3. myScript.NotifyMouseOver();
  4. }

This also works fine, but you always need to keep a reference to the object you notify. Also, you can only notify this object, unless you keep more references to other object. This can quickly get messy.

Messages

Another solution would be to use SendMessage or SendMessageUpwards methods. While they seem to be the right tool for the job, these methods have several major flaws, and in my opinion you should completely avoid using them.

Their syntax is awkward to start with, and you need to pass method names as string literals - which is very error prone! Also, those methods work only within the object's transform hierarchy. You can invoke methods on scripts that are either attached to the same GameObject or to one of it ancestors.

Events

Fortunately there is a better way to solve this problem, and this is with the C# built in event system. I can't explain how the event system works in detail, but if you are interested on learning more on this topic, go and check the tutorial on MSDN.

Now, let's see how to use events in Unity3D. Consider this script:

C#:
  1. using UnityEngine;
  2. public class EventDispatcher : MonoBehaviour {
  3. public delegate void EventHandler(GameObject e);
  4. public event EventHandler MouseOver;
  5. void OnMouseOver () {
  6.     if (MouseOver != null)
  7.         MouseOver (this.gameObject);
  8. }
  9. }

Don't worry if you don't know exactly what it does. What's important is that once you attach it to a GameObject you can go to another script (any script in your project!) and if you have a reference to that object you can write something like this:

C#:
  1. private GameObject s;
  2. [...]
  3. s.GetComponent<EventDispatcher>().MouseOver += Listener;
  4. [...]
  5. void Listener(GameObject g) {
  6.    // g is being hovered, do something...
  7. }

This approach is more flexible than using messages, because it works with any script not only with those that are in the same transform hierarchy. If you keep a Singleton object that manages the state of the application, you could listen to events coming from any GameObject in it. Of course not only a GameObject can send events - any object can.

One of the consequences of such setup is that the same listening function can be used to respond to events coming from different objects. By passing a reference as argument you always know which object dispatched the event - this is what I do in the example.

References, controllers and MVC

In the first scenario above you needed to keep a reference to the listener in the object that sends the event, and I said it's not a good idea. In the version which uses the built-in events, it needs to be the other way around - you need a reference to the object that sends the event in the object that listens to it. How is it better, you might ask?

First of all, here, the sender doesn't know who is listening to the events is sends - and even how many listeners there are. All it does is to send the event and forget. In the first scenario above, imagine how cumbersome it would be to tell the sender to stop notifying the listener!

With the event system, it's the listener that has the responsibility to decide what events it listens to, when to start, and when to stop listening to them. Such object usually manages the state of the application or executes some game logic. To borrow the term from the MVC design pattern - it's the controller. That is why it's perfectly logical to give him such responsibility. In that way, using events creates more solid code.

Finally, I love the overloaded += operator used to add a listener, it's so clean! As you might have guessed by now, when you are done listening to the event you can just say:

C#:
  1. s.GetComponent<EventDispatcher>().MouseOver -= Listener;

Of course you can create a generic EventDispatcher class that implements all events that a GameObject can send - here's a version that implements a few of them already. By looking at the code, I'm sure you can figure out how to add others. However, beware of implementing OnGUI that way! (if you want to know why, read this post).

Unity3D training

Hands-on Unity3d, 21-22 Oct 2010

I'm proud to announce, that I will be running a 2 day training in London later this month. I will be teaching Unity3D, showing how to use the editor and how to work with various assets. I will be also giving an introduction to scripting in C# and hopefully we will be able to cover some features of the latest release of the editor.

Unity3D version 3 has been released only a few days ago. The new version is packed a tremendous amount of new and cool features. Great games & other projects are created with Unity3D every day, so there has never been a better moment to start learning it!

You can read all the details about the training on the LFPUG page, who is also the organizer of the session. Unfortunately, the tickets have been sold out. However, if you would like to learn some Unity3D, please contact me (bartek [at] everyday3d.com) or Tink (training [at] lfpug.com). We are pretty excited about the interest people are showing for this topic, so currently we are planning to run another session in London in November and there are still a few places left on the list.

I got a couple of requests to run such a training in other places, so hopefully I will be bringing some Unity3D goodness to other cities in Europe as well. I'm working out the details, and I'll keep you posted. If you would be interested in hosting a Unity3D training session in your city, please let me know!

Old school effects with shaders


Plasma


Rings


Canyon


Flower


The endless well

What are these?

While at FITC San Francisco I attended the session of Iñigo Quilez who is a demoscene veteran, currently working at Pixar. He showed us lots of interesting stuff he created with GLSL. He also showed examples of some more basic stuff like those above. These are very old school effects known to the demoscene artists since the dawn of civilization (that is the '90s). On Iñigo's site you can find a simple tutorial on how to create those effects, and it's not very difficult to port it to Unity3D using Cg. The cool thing is that all this different effects run on the same exact code, changing just a few settings.

Update Sept 17th 2010 Inigo also created a tool called ShaderToy, which allows you to play with the formulas in your browser (it must support WebGL).

As for the plasma effect, I initially saw it on mrdoob's blog and found this short tutorial which explains how to do it. Simple, and it looks nice!

TIP: Although they run pretty smoothly in the browser, the demos perform even smoother in fullscreen mode.

UPDATE It seems that the shaders do not work on OSX 10.6 (Snow Leopard) in Safari 5 and Chrome, but do work on Firefox. Some shaders might not work on certain GPUs, but in this case it's the same system, with the same graphic card and the only difference is the browser. This means that there might be a bug in the web player. If I have more news, I'll post an update, but you also can follow the discussion on the forum here.

In the meantime, if on OSX 10.6 please use Firefox (sorry).

Format journey

A few months ago, I had the pleasure to work with Luciano Foglia and Anrick Bregman on a visual experiment called Format Journey. The installation uses data - a series of images and a sound file - to modify the texture and the shape of a 3D object. Combined with a slight randomization it gives very nice and unpredictable results.

When we first talked about the project, the idea was to use either Flash or Processing, but I though that it's a good occasion to try Unity3D (of course... :) To achieve the desired visual effect I needed a shader system that's fast, flexible that and works with 3D. Unity's ShaderLab seemed like a good option.

The material on the shape is transparent and is composed of a blurred version of an image applied as regular texture and the image itself applied as reflection. The images change over time, and are animated by scrolling UVs.

All the data for the installation is loaded dynamically, the application itself is just composed of some scripts that make it run, so the file is only 55KB! It's controlled by an external configuration file that allows to define the source images and sounds. There are also quite a few other settings to tweak they way it works, ex. how transparent or how reflective the material should be.

One particular challenge was to make the shape react to the sound. To make this happen I needed to read the spectrum and Unity3D doesn't offer access to sound data on the code level. One possible solution was to write a plugin that does that, the downside however is that it wouldn't run in the web player.

I solved the problem by pre-processing the sound in a small Flash app. It dumps the spectrum data to a text file which is then loaded to Unity3D. When the application plays the sound file, it uses this data to check the values of the spectrum at any position in time. Simple, but does the job.

The installation is part of a project called Tango and Hawaii created by Anrick and Luciano. Be sure to check the live demo. It was originally presented at the Magdalena Festival in Maribor, Slovenia.

It was a new experience for me to work on an art piece was. It was very inspiring to see what Anrick and Luciano did with a tool I helped them to create. Thank you guys!

What can you do with Unity3d? FITC San Francisco

I'm happy to announce that I will be speaking at FITC San Francisco in August. I have been speaking at FITC events twice this year, and both times it was a fantastic experience. I'm looking forward for this one, and what really thrills me about it, is the amazing speaker lineup!

There are of course all the usual suspects like Joa, Ralph, Andre, Mario and Seb plus many more great speakers form the community - you don't want to miss any of them. Here's a few that particularly caught my attention:

Eugene Zatepyakin The Actionscript/Alchemy mage from Russia. You may know Eugene from his work on ASSURF which is this amazing image recognition library. I had the pleasure to meet Eugene in Antwerp last year and I can assure you that you won't regret attending his presentation.

Theo Watson At FITC Amsterdam 2009 Theo was speaking as a last minute replacement for another presenter who could not make it. It was a lucky coincidence for me, because I really loved what he was showing! Theo is a digital artist working with openFrameworks. In San Francisco he will be taking part in a panel together with Jer Thorp and Ben Fry, the creator of Processing. I'm sure it will be a very interesting discussion. Theo will also be giving a presentation on interactive storytelling toghether with Emily Gobeille.

Yoko Nakamura Yoko was doing kick-ass Flash stuff on Yugop while I was still learning how to use gotoAndPlay()! I can't wait to see the legend live.

And there's me. I feel almost insignificant in face of such great talents, but I will do my best to deliver a great presentation. I was speaking in Amsterdam and Toronto and I was happy to see a full house both times for which I only partly credit my amazing speaking talent... :) It's rather that Unity3D is such a hot topic right now. In San Francisco I will be giving a new, updated presentation entitled "What can you do with Unity3d?". I hope to see you there!

But wait, there's more... so take a look at the complete speakers list. If you live in California (or close to) this is an event not to miss. The super early bird tickets are only available until today (Friday, May 28th) so go grab them before it's too late!

Loading 3d models at runtime in Unity3d

IMPORTANT UPDATE! With Unity 3 there were some changes in the API and code described below doesn't work. Here's a new version, that works with Unity 3: obj (v1.2). Now, instead of creating a new object, attach the OBJ script to a game object and add the path to the .obj file in the inspector.

This post is an addition to the last series I wrote about dynamic content loading in Unity3D.

When building a dynamic application, every now and then you might need to load some 3d models at runtime. Either because there's a database with models you want to use or just because you want someone to update the models without rebuilding the project. I actually had this situation a few weeks ago. Surprisingly, this option does not come with Unity out of the box.

Asset bundles and resource folders

But first thing first. I said there's no ready-to-use way to load 3d models at runtime, but it's not 100% true. In fact, there are two options: asset bundles and resource folders. These methods are discussed in depth here.

They can both be useful in some cases, but they both have one fundamental drawback: in order to create them, someone needs to open the project in Unity, import the 3d models, create the bundles or resource folders and then export the whole thing again. To create an AssetBundle you need to run a script in the editor, while the Resource Folders... honestly, I failed to even make them work!

In brief, it's all too complicated for what I was looking for.

A straightforward solution

What I needed and wanted was easy and simple: to load a 3d object (geometry + some materials and textures) at runtime, using just a URL as parameter. The only solution seemed to write my own importer.

Basically, I had the choice between Collada and Wavefornt OBJ. I would choose OBJ any time of the day because it's a simple, concise plain-text format, while Collada is bloated and is XML-based.

It's not that I hate XML (although I'm not a big fan either) but in order to parse XML you need to include a pretty weighty DLL in your *.unity3d file, around 850Kb, which in this case (and in many others) defeats the purpose. Still, it's good to know that it possible, and there are situations when it's ok to use it. If you want to learn more about Unity3D and XML there's a awesome article on this topic by Paul Tondeur.

It turned out that while it's not rocket science to write an OBJ importer, it's not exactly banal either. I spent a few days coding it so I thought I'll share this with everyone - maybe someone will make good use of it.

Here's a package with the source code (v1.1) (or a version that works in Unity 3 (v 1.2)), along with a simple scene demonstrating how it works. In fact it couldn't be simpler. All you have to do is to create an instance of the OBJ class and start a coroutine to load the contents, like this:

C#:
  1. string path = "http://www.everyday3d/unity3d/obj/monkey.obj";
  2. OBJ obj = new OBJ();
  3. StartCoroutine(obj.Load(path));

Supported features

  • Vertex, normals and UV data
  • Multiple objects per file
  • Vertex groups and multiple materials per object
  • MTL files, diffuse and specular materials
  • Basic textures

And it's all at a cost of ~12Kb extra added to your final file!

Testing and the universality of OBJ format

In the 3D world the OBJ format is nearly universal - I think that every 3D editor in existence is able to export to this format. This also means that Wavefront files come in many different flavors.

I tested the code against models created with Blender and against common sense assumptions on how an OBJ file can be constructed. If it doesn't work with files exported from your editor send me the OBJ file, and if possible I'll update the code. It's released under the MIT license so feel free to use it in your projects, commercial or not.

That's it! I hope you'll find it useful!



  • FATC2011


  • FITC2011


  • FITC2010


  • FITC2010