import csv open("output.tsv", "w").write("\n".join("\t".join(e.strip() for e in i) for i in csv.reader(open("input.csv"))))
Monday, December 12, 2011
Convert CSV to TSV
Wednesday, November 30, 2011
Unity3D available on Linux!
While exploring the build API for Unity3D today, I came across this...
Yup, that's a BuildTarget enum for Linux! I haven't tried it yet, so it may throw an exception if I try to use it... but I'm guessing this means official Linux support is imminent?
Tuesday, November 22, 2011
Unity3D GC Spikes
If you've been working with Unity3D for a while, you've probably noticed when the garbage collector kicks in, your frame rate suffers, very badly.
I've spent some considerable time trying to eliminate these hiccups from my AI code, with no success. I ended up reducing the problem to a simple project which loads and runs 1000 coroutines forever, which do nothing except yield 0. This is the result in my profiler.
Those nasty spikes are where the GC kicks in and performance plummets. It's particularly nasty on iOS. The question is, how to fix? I have no idea. This project only runs coroutines which do nothing. No allocations, instantiations or anything else. Yet, the GC still kicks in very frequently. Too frequently. If _anyone_ has a solution for this, I'd love to hear it. I'm worried the problem is too fundamental to Unity3D to fix in any way... Try for yourself if you like. spiker.unitypackage Update: After running this same test and profiling the iOS and Desktop builds, the GC spikes disappear completely. The less I have learnt, is don't rely on profiling in the Editor!
Those nasty spikes are where the GC kicks in and performance plummets. It's particularly nasty on iOS. The question is, how to fix? I have no idea. This project only runs coroutines which do nothing. No allocations, instantiations or anything else. Yet, the GC still kicks in very frequently. Too frequently. If _anyone_ has a solution for this, I'd love to hear it. I'm worried the problem is too fundamental to Unity3D to fix in any way... Try for yourself if you like. spiker.unitypackage Update: After running this same test and profiling the iOS and Desktop builds, the GC spikes disappear completely. The less I have learnt, is don't rely on profiling in the Editor!
Star Hammering in Two Days
In two days, I get to buy this game. I've been waiting quite some time to play this. You should buy it too, then we can all beg the developer for a MMO expansion together! :-)
Wednesday, October 26, 2011
1000 Space Ships...
What do 1000 AI controlled spaceships look like? This!
These ships are using physics to propel themselves around, with an AI controlling each one. The AI Tool is React, and it works on iOS too! This shot is taken on an iPad 2, with a mere 100 ships in flight!
Tuesday, October 11, 2011
Monday, August 29, 2011
Sunday, August 28, 2011
Saturday, August 27, 2011
Friday, August 26, 2011
Thursday, August 25, 2011
Heap Queue in C#
A minimal re-implementation of the Python heapq module.
public class HeapQ<T> where T : IComparable { List<T> items; public HeapQ () { items = new List<T> (); } public bool Empty { get { return items.Count == 0; } } public T First { get { if (items.Count > 1) { return items[0]; } return items[items.Count - 1]; } } public void Push (T item) { items.Add (item); SiftDown (0, items.Count - 1); } public T Pop () { T item; var last = items[items.Count - 1]; items.RemoveAt (items.Count - 1); if (items.Count > 0) { item = items[0]; items[0] = last; SiftUp (0); } else { item = last; } return item; } void SiftDown (int startpos, int pos) { var newitem = items[pos]; while (pos > startpos) { var parentpos = (pos - 1) >> 1; var parent = items[parentpos]; if (parent.CompareTo (newitem) <= 0) break; items[pos] = parent; pos = parentpos; } items[pos] = newitem; } void SiftUp (int pos) { var endpos = items.Count; var startpos = pos; var newitem = items[pos]; var childpos = 2 * pos + 1; while (childpos < endpos) { var rightpos = childpos + 1; if (rightpos < endpos && items[rightpos].CompareTo (items[childpos]) <= 0) childpos = rightpos; items[pos] = items[childpos]; pos = childpos; childpos = 2 * pos + 1; } items[pos] = newitem; SiftDown (startpos, pos); } }
Friday, August 05, 2011
Thing's I like about Mac.
Unity3D 3.4 Enhancements
I enjoy modifying cars, so that they exceed their stock limitations. When you've fixed all the easy stuff on a vehicle, you move onto the fine tuning, which might only yield you one or two percent performance increase per modification. The latest version of Unity contains some very fine fixes, which are starting to make it run like a well tuned rapid development machine!
C# Script files now get the correct name when you first add them to the project. The ritual of "Create Script, Open, Rename, Drop onto Game Object" is gone forever! Now you only need to create the script, and Unity gives the class the right name automagically.
The second great fix is that you can now create a prefab simply by dragging an object from your scene hierarchy straight into the project view. No more tedious Create Prefab, Drop object Onto Prefab, Rename Prefab. It is just... drag... and drop!
C# Script files now get the correct name when you first add them to the project. The ritual of "Create Script, Open, Rename, Drop onto Game Object" is gone forever! Now you only need to create the script, and Unity gives the class the right name automagically.
The second great fix is that you can now create a prefab simply by dragging an object from your scene hierarchy straight into the project view. No more tedious Create Prefab, Drop object Onto Prefab, Rename Prefab. It is just... drag... and drop!
Thursday, July 28, 2011
Unity3D Locomotion Update
I didn't see this mentioned anywhere, but it appears that the Unity3D Locomotion System has had an update. It's great to see this project is not being neglected!
Wednesday, July 27, 2011
Thoughts on Unity3D -> Allegorithmic Integration
Unity3D 3.4 includes new integration with Allegorithmic and their Substance engine.
What does this give you? Simply, you have a new material type which you can import and use in Unity. If you want to create these materials yourself, you'll need to purchase other tools to do that for you, Unity doesn't do that.
You can also purchase a bunch of materials from the Unity Asset Store. But don't be fooled by the screenshots, you won't get nice bumpy objects just by slapping a Substance onto them. To make that a reality, Unity3D will need to support displacement shaders. Until then substances are really just highly configurable textures.
What does this give you? Simply, you have a new material type which you can import and use in Unity. If you want to create these materials yourself, you'll need to purchase other tools to do that for you, Unity doesn't do that.
You can also purchase a bunch of materials from the Unity Asset Store. But don't be fooled by the screenshots, you won't get nice bumpy objects just by slapping a Substance onto them. To make that a reality, Unity3D will need to support displacement shaders. Until then substances are really just highly configurable textures.
Tuesday, July 26, 2011
Monday, July 25, 2011
Monday, July 04, 2011
Spatial Hash in Javascript, for 2D.
var SpatialHash = function(cellSize) {
this.idx = {};
this.cellSize = cellSize;
}
SpatialHash.prototype.insert = function(x, y, obj) {
var cell = [];
var keys = this.keys(x,y);
for(var i in keys) {
var key = keys[i];
if(key in this.idx) {
cell = this.idx[key];
} else {
this.idx[key] = cell;
}
if(cell.indexOf(obj) == -1)
cell.push(obj);
}
}
SpatialHash.prototype.query = function(x, y) {
var key = this.key(x, y);
if(this.idx[key] != undefined)
return this.idx[key];
return [];
}
SpatialHash.prototype.keys = function (x, y) {
var o = this.cellSize / 2;
return [this.key(x-o, y+0),
this.key(x-0, y+0),
this.key(x+o, y+0),
this.key(x-o, y+o),
this.key(x-0, y+o),
this.key(x+o, y+o),
this.key(x-o, y-o),
this.key(x-0, y-o),
this.key(x+o, y-o)];
}
SpatialHash.prototype.key = function(x, y) {
var cellSize = this.cellSize;
x = Math.floor(x/cellSize)*cellSize;
y = Math.floor(y/cellSize)*cellSize;
return x.toString() + ":" + y.toString();
}
Friday, June 24, 2011
Racing Games on the iPad
I've just played Sega All Stars Racing on my iPad.
Great fun, but it uses tilt controls to control the steering of the vehicle. This works great, until I've been playing for 3 minutes and my shoulders start to ache.
People that are building racing games for iDevices obviously have not payed any attention to the lessons learned from Gorilla Arm Syndrome.
Great fun, but it uses tilt controls to control the steering of the vehicle. This works great, until I've been playing for 3 minutes and my shoulders start to ache.
People that are building racing games for iDevices obviously have not payed any attention to the lessons learned from Gorilla Arm Syndrome.
Saturday, June 18, 2011
I tried Battlestar Galactica Online..
... they sent me my password in clear text.
Instant, mega-fail. Now I need to change all my game related passwords.
Thanks for that.
Instant, mega-fail. Now I need to change all my game related passwords.
Thanks for that.
Tuesday, June 14, 2011
EVE Online, initial perspective.
First of all, I'm starting to enjoy the learning curve. Bute there are a few things that are annoying.
1. Clipping through planets.
2. Clipping through stars.
3. Clipping through wrecks.
4. Clipping through stations.
Amazing that this happens in such a... er... 'AAA' title?
1. Clipping through planets.
2. Clipping through stars.
3. Clipping through wrecks.
4. Clipping through stations.
Amazing that this happens in such a... er... 'AAA' title?
Friday, June 10, 2011
Friday, June 03, 2011
Saturday, May 28, 2011
Simple SVG.
So simple, it is silly. SillySVG
var svg = new SVG();
svg.circle().attr({r:20,stroke:"black",fill:"none"}).transform.translate(100,100);
Sunday, May 22, 2011
Fun and Games in Boston
After three days of heavy fog, two days of bleary jet lag and one day of the lurgy, the sun came out today. So far I've met with quite a few interesting characters. Alex Schwartz of "Smuggle^H^H^H^H^H^Hnuggle Truck" fame, Ned Batchelder (an altogether nice chap) and today I had the good fortune to have lunch with Glyph Lefkowitz and Jp Calderone who assured me that Apple is not the Evil Empire we might think it is, and that PyPy is the future, as long as we can get build times down.
I'll be home in three days, and I'm super-keen to get back into some coding, and maybe have a crack at breathing life into some of my old projects. Oh, and start compiling PyPy trunk. :-)
I'll be home in three days, and I'm super-keen to get back into some coding, and maybe have a crack at breathing life into some of my old projects. Oh, and start compiling PyPy trunk. :-)
Thursday, May 12, 2011
Python Hackers in Boston
I'm in Boston MA next week, looking to hire some awesome Python hackers to help open a new game development studio. We use Python for our game server, and Unity3D/C# for the game client. It is an amazing project with an existing international team based in Perth, Western Australia.
If you're interested, in Boston and want to chat, drop me an email at simonwittber@differentmethods.com and we can arrange a time and place.
If you're interested, in Boston and want to chat, drop me an email at simonwittber@differentmethods.com and we can arrange a time and place.
Wednesday, May 11, 2011
Monday, May 09, 2011
Adding Methods without Inheritance
Did you know that C# will let you add methods to objects, without needing to write new sub-classes? I didn't until today. The following snippet adds a new method to generic list instances, called Shuffle, which randomises the items in the list.
Is this possible in Python? I think it is, but i need to experiment with some code first... stay tuned.
Update:
Of course you can do this in Python, but it won't work on built in types.
static class ExtensionMethods {
public static void Shuffle(this IList list)
{
var rand = new System.Random();
int n = list.Count;
while (n > 1) {
n--;
int k = rand.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
Is this possible in Python? I think it is, but i need to experiment with some code first... stay tuned.
Update:
Of course you can do this in Python, but it won't work on built in types.
>>> import random
>>>
>>> x = range(10)
>>> def shuffle(self):
... random.shuffle(self)
...
>>> list.shuffle = shuffle
Traceback (most recent call last):
File "", line 1, in
TypeError: can't set attributes of built-in/extension type 'list'
>>> class List(list): pass
...
>>> n = List(x)
>>> List.shuffle = shuffle
>>> n.shuffle()
>>> n
[5, 3, 7, 4, 2, 9, 1, 6, 0, 8]
>>>
Thursday, May 05, 2011
Model-Off, Next Week.
Next week in the Different Methods office, we're having a model-off.
What is a model-off? Well, we all love our respective modelling software. Except Lisa, I think she just tolerates Cheetah 3D :-). Anyhow, we're going to all tackle the same model, and see who produces the best quality model, balanced with the time spent to build it. No texturing required, just polygons!
Simon - Wings3D
Stephen - Maya
Nicholas - 3D Studio
Lisa - Cheetah3D
Which package will reign supreme? Stay tuned for the results! We'll probably release a Unity web player showing the results.
What is a model-off? Well, we all love our respective modelling software. Except Lisa, I think she just tolerates Cheetah 3D :-). Anyhow, we're going to all tackle the same model, and see who produces the best quality model, balanced with the time spent to build it. No texturing required, just polygons!
Simon - Wings3D
Stephen - Maya
Nicholas - 3D Studio
Lisa - Cheetah3D
Which package will reign supreme? Stay tuned for the results! We'll probably release a Unity web player showing the results.
Wednesday, May 04, 2011
Friday, April 29, 2011
Markov Name Generator
I use something like this to generate names for stars and planets in my procedural universe game thingo.
You can seed it with any data you like to generate any sort of name. Eg:
Gives this output:
import random
class Markov(object):
def __init__(self, samples, order, minLength):
self.order = order
self.minLength = minLength
self.chains = {}
self.used = []
self.samples = [i.strip().upper() for i in samples if len(i) > order]
for word in self.samples:
for letter in xrange(len(word)-order):
token = word[letter:letter+order]
entries = self.chains.setdefault(token, list())
entries.append(word[letter + order])
def next(self):
s = "";
while True:
n = random.choice(self.samples)
i = random.randint(0, len(n) - self.order)
s = n[i:i+self.order]
while len(s) < len(n):
i = random.randint(0, len(s) - self.order)
token = s[i:i+self.order]
if token not in self.chains:
break
s += random.choice(self.chains[token])
s = s[0] + s[1:].lower()
if not (s in self.samples or s in self.used or len(s) < self.minLength):
break
self.used.append(s);
return s;
def reset(self):
self.used.Clear()
You can seed it with any data you like to generate any sort of name. Eg:
starnames = """
Achernar Alpha Eridani \
Achird Eta Cassiopeiae \
Acrab Beta Scorpii \
Acrux Alpha Crucis \
Acubens Alpha Cancri \
Adhafera Zeta Leonis \
Adhara Epsilon Canis Majoris \
Ain Epsilon Tauri \
Aladfar Eta Lyrae \
Alamak Gamma Andromedae \
Alathfar Mu Lyrae \
Alaraph Beta Virginis \
Albaldah Pi Sagittarii \
""".split(" ")
m = Markov(starnames, 2, 6)
for i in xrange(10):
print m.next()
Gives this output:
Siolphh
Hafere
Ammaam
Ammaka
Ittatartar
Chieri
Scooor
Araineaa
Feriisda
Achuih
New Procedural Planet Generator Released.
The procedural planet package has been updated to version 1.4, and you can see the new demo here.
It features better city light control, better water control, a sun shader, many more planet texture ramps and a nice skybox cubemap.
The package is still pending release on the Unity Asset store, and should be available in a few days.
It features better city light control, better water control, a sun shader, many more planet texture ramps and a nice skybox cubemap.
The package is still pending release on the Unity Asset store, and should be available in a few days.
Wednesday, April 27, 2011
7 Bit Integer compression, in Python.
def decode7bit(bytes):
bytes = list(bytes)
value = 0
shift = 0
while True:
byteval = ord(bytes.pop(0))
if(byteval & 128) == 0: break
value |= ((byteval & 0x7F) << shift)
shift += 7
return (value | (byteval << shift))
def encode7bit(value):
temp = value
bytes = ""
while temp >= 128:
bytes += chr(0x000000FF & (temp | 0x80))
temp >>= 7
bytes += chr(temp)
return bytes
x = encode7bit(345)
print decode7bit(x)
Public and Private in Python?
I've just finished refactoring an awful C# class. I had been delaying the job for a while because I didn't want to do it.
Then, while staring at the code, I realised I could simply delete all the private methods and fields, leaving the public interface intact, and then re-implement the class in a much cleaner way. Great idea! I finished the job in a few hours, with a brand new class that doesn't give me a headache.
This is the first time I've actually seen a real value in having private and public scope for methods and variables. It makes refactoring much safer and easier! So... why don't we have them in Python?
Then, while staring at the code, I realised I could simply delete all the private methods and fields, leaving the public interface intact, and then re-implement the class in a much cleaner way. Great idea! I finished the job in a few hours, with a brand new class that doesn't give me a headache.
This is the first time I've actually seen a real value in having private and public scope for methods and variables. It makes refactoring much safer and easier! So... why don't we have them in Python?
Saturday, April 23, 2011
Encryption between Python and C#
I do a lot of work in restricted environments, where I still need to secure internet traffic. I chose to use the RC4 algorithm because it is simple to implement and relatively fast. It is actually easy enough that a simple programmer like myself could write matching Python and C# implementations!
RC4 is also a stream cipher, which means you don't need to worry about breaking your cleartext into blocks, padding them out... and other related pain.
If you do use RC4, you should be aware that it has some vulnerabilities.
Python:
C#:
RC4 is also a stream cipher, which means you don't need to worry about breaking your cleartext into blocks, padding them out... and other related pain.
If you do use RC4, you should be aware that it has some vulnerabilities.
Python:
def RC4(data, key):
x = 0
s = range(256)
for i in range(256):
x = (x + s[i] + ord(key[i % len(key)])) % 256
s[i], s[x] = s[x], s[i]
x = y = 0
out = ""
for c in data:
x = (x + 1) % 256
y = (y + s[x]) % 256
s[x], s[y] = s[y], s[x]
out += chr(ord(c) ^ s[(s[x] + s[y]) % 256])
return out
C#:
using System;
public class RC4
{
static public void Cipher (ref byte[] bytes, string skey)
{
var key = System.Text.ASCIIEncoding.ASCII.GetBytes(skey);
byte[] s = new byte[256];
byte[] k = new byte[256];
byte temp;
int i, j;
for (i = 0; i < 256; i++) {
s[i] = (byte)i;
k[i] = key[i % key.GetLength (0)];
}
j = 0;
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
i = j = 0;
for (int x = 0; x < bytes.GetLength (0); x++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
int t = (s[i] + s[j]) % 256;
bytes[x] ^= s[t];
}
}
}
Thursday, April 21, 2011
Russians.
My favourite quote from a user bio on freelancer.com.
It is sayd: "if problem is easy then your local programmers can solve it; if problem is difficult then you should hire programmers from India; but if your problem is impossible to solve you must hire Russian."
It is sayd: "if problem is easy then your local programmers can solve it; if problem is difficult then you should hire programmers from India; but if your problem is impossible to solve you must hire Russian."
Sunday, April 17, 2011
Sweet Python Syntax
I've been writing Python code for quite a while, yet sometimes I still get surprised by some neat undiscovered feature. This is what I found today. The neat part is where the tuple is unpacked inplace in the for statement.
I could be wrong, but I vaguely recall trying this once, and it not working. Now it does!
things = {}
things[1] = (2,3)
things[2] = (4,5)
for id, (A, B) in things.items():
print id, A, B
I could be wrong, but I vaguely recall trying this once, and it not working. Now it does!
Friday, April 15, 2011
Tuesday, April 12, 2011
Weather Geeks...
Can you tell me if the chart on this page is correct? If so, how to they get the data for the more ancient measurements? I'd like to use this data in a Python script I'm tinkering with...
Update:Evidence in the comments suggest this site is not trustworthy. There is better information linked in the comments, including this interesting graph.
Update:Evidence in the comments suggest this site is not trustworthy. There is better information linked in the comments, including this interesting graph.
Monday, April 11, 2011
AI for Unity3D
I'm about to release a tool called React. It implements behaviour trees for Unity3D.
Here is the obligatory screencast. I hope this is as easy to use as I think it is! It makes the designer specify what actions and conditions are available on the game object, before the programmer implements them.
The first step is to create a React Graph using the React Editor. The graph consists of selectors, sequences, actions, conditions and many other different node types. This graph is serialized into an asset so that it can be used by multiple game objects.
The second step is generating the C# script. This is as simple as clicking the generate button. The generated file contains stubs for the actions and conditions used in the behaviour tree. The body of these stubs is then filled in with appropriate code, and voila, you have an intelligent object.
It should be fully baked any day now, stay tuned!
Update: Now available on the asset store.
Here is the obligatory screencast. I hope this is as easy to use as I think it is! It makes the designer specify what actions and conditions are available on the game object, before the programmer implements them.
The first step is to create a React Graph using the React Editor. The graph consists of selectors, sequences, actions, conditions and many other different node types. This graph is serialized into an asset so that it can be used by multiple game objects.
The second step is generating the C# script. This is as simple as clicking the generate button. The generated file contains stubs for the actions and conditions used in the behaviour tree. The body of these stubs is then filled in with appropriate code, and voila, you have an intelligent object.
It should be fully baked any day now, stay tuned!
Update: Now available on the asset store.
Friday, April 08, 2011
Pyramid vs NodeJS vs Gevent
Summary: NodeJS wins.
Test Program
Gevent Code
Pyramid Code
NodeJS Code
Gevent Results
Pyramid Results
NodeJS Results
Test Program
ab -n 10000 -c 5 http://localhost/
Gevent Code
from gevent import wsgi
class WebServer(object):
def application(self, environ, start_response):
start_response("200 OK", [])
return ["Hello world!"]
if __name__ == "__main__":
app = WebServer()
wsgi.WSGIServer(('', 8888), app.application, backlog=1024).serve_forever()
Pyramid Code
from pyramid.config import Configurator
from pyramid.response import Response
from paste.httpserver import serve
def hello_world(request):
return Response('Hello world!')
if __name__ == '__main__':
config = Configurator()
config.add_view(hello_world)
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')
NodeJS Code
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
Gevent Results
Time taken for tests: 3.255 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Requests per second: 3072.53
Pyramid Results
Concurrency Level: 5
Time taken for tests: 14.650 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Requests per second: 682.57
NodeJS Results
Concurrency Level: 5
Time taken for tests: 2.953 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Requests per second: 3386.80
Tuesday, April 05, 2011
The perks of working on games...
You get to make really cool stuff.
These models were built by Nic, our new hire. The shader on the ships is a custom specular / bumped / reflective / illuminated beast, and the skybox is generated by our Spacebox tool.
Friday, April 01, 2011
Wednesday, March 30, 2011
Google Analytics and Unity3D
We've just released an extension which enables your Unity3D game to post data off to Google Analytics.
It's called Analytics, funnily enough.
Friday, March 25, 2011
Unity3D and Linux.
It can be done, didn't you know? In fact, the smart folks at UT have already done it.
I hope this makes the leap from prototype to production.
I hope this makes the leap from prototype to production.
Tuesday, March 22, 2011
You cannot trust HTTP.
Our current project uses HTTP to communicate with the game server. Part of our code requires some custom metadata to be sent with the HTTP headers down to the client.
Did you know you cannot rely on custom headers being delivered to your HTTP client? I didn't. It turns out some firewalls will only allow a whitelisted set of headers through to their clients, which I imagine will break many different web applications. To get around this, we've had to munge the metadata into the HTTP body, and pass things around with query strings, turning something that was looking rather elegant, into a total abuse of HTTP.
Sad face.
Did you know you cannot rely on custom headers being delivered to your HTTP client? I didn't. It turns out some firewalls will only allow a whitelisted set of headers through to their clients, which I imagine will break many different web applications. To get around this, we've had to munge the metadata into the HTTP body, and pass things around with query strings, turning something that was looking rather elegant, into a total abuse of HTTP.
Sad face.
Thursday, March 10, 2011
Wednesday, March 09, 2011
Planet Atmospherics.
My planets can now have procedural animated atmospheres. This is not simple UV animation. The clouds form, twirl and evaporate over the planet surface! This will be available as a free update on the Unity asset store.
Tuesday, March 08, 2011
Procedural Texturing of Planets.
Unity3D doesn't support volume textures. This makes procedural texturing of models using object or world space (instead of UV coords) very hard.
After much banging of head on keyboard, I think I've succeeded in using a 2D noise texture to fake 3D noise, and create a reasonable looking planet texture. Next step, atmosphere.
Friday, March 04, 2011
Unity3D will run in the Flash Player.
What the title says. This is a rather epic advance for Unity. Yes, the previous statement is an understatment.
Connect Unity3D to Google Spreadsheets.
I've just uploaded a package to the Unity Asset store, which allows you to easily source and cache data, in a secure manner, from a Google Spreadsheet!.
It is called GlobalData, and allows you to have truly global data across your game instances. You could use it to provide item stats, character stats or any kind of tabular data to your game, and you can even modify your core data after the game has been released.
It caches data locally, so your players won't require a constant internet connection to play.
It is called GlobalData, and allows you to have truly global data across your game instances. You could use it to provide item stats, character stats or any kind of tabular data to your game, and you can even modify your core data after the game has been released.
It caches data locally, so your players won't require a constant internet connection to play.
Thursday, March 03, 2011
SSL and Unity3D
I've just committed code to support HTTPS with UnityWeb, as well as a disk cache system. Hooray.
Tuesday, March 01, 2011
Apple Extortion
A Macbook Pro in the US will cost me $3899 USD.
A Macbook Pro in Australia will cost me $4709 AUD.
How many AUD will $3900 USD buy me?
$3835 Australian Dollars. I get to pay $1k more just because I live in Australia. This is just wrong, especially when you consider we are so much closer to China, where all Apple stuff is built.
A Macbook Pro in Australia will cost me $4709 AUD.
How many AUD will $3900 USD buy me?
$3835 Australian Dollars. I get to pay $1k more just because I live in Australia. This is just wrong, especially when you consider we are so much closer to China, where all Apple stuff is built.
Wednesday, February 23, 2011
Asset Store Update
We've got two new releases on the Unity Asset Store.
Future City Pack by our new hire (awesome stuff) and BundleLoader, a script to take the pain out of downloading and caching asset bundles. BundleLoader is free, because it saves so much pain, it can only make the world a happier place. :-)
Future City Pack by our new hire (awesome stuff) and BundleLoader, a script to take the pain out of downloading and caching asset bundles. BundleLoader is free, because it saves so much pain, it can only make the world a happier place. :-)
Saturday, February 19, 2011
Unity3D supports Sony Xperia Play
Yes it is true, Unity3D will support the Xperia Play. I know this will make many developers quite happy.
Sunday, February 13, 2011
Planet Shader V3.
This shader is much better than my previous efforts.
It has specular mapping, bump mapping and a fake atmospheric scattering effect, based on rim lighting. To get the partial crescent glow, I calculate the rim lighting based on the view direction plus a small component of the light direction. All in a single pass!
This shader will be available in the Unity Asset Store in version 1.5 of my Spacebox Extension.
Saturday, February 12, 2011
Spacebox Released!
Spacebox is a procedural content generator for space environments. The good news is, it is now available on the Unity Asset Store!
You can try out out a demo on the web over here.
Spacebox generates seamless cube maps which you can use as a Skybox material in Unity3D. You can customise any number of star and nebulae layers with different textures and colours to produce a unique space environment.
Labels:
Games,
Spacecraft,
Unity3D
Thursday, February 10, 2011
Camera.layerCullDistances Tip.
This is a Unity3D tip.
The Camera.layerCullDistances variable is an array of floats that allow you to have a custom farClipDistance per layer.
Something that is not mentioned in the docs, however, is that the culling distance cannot be greater than your Camera.farClipPlane value. If it is, it will be clamped down to this value.
The Camera.layerCullDistances variable is an array of floats that allow you to have a custom farClipDistance per layer.
Something that is not mentioned in the docs, however, is that the culling distance cannot be greater than your Camera.farClipPlane value. If it is, it will be clamped down to this value.
Tuesday, February 08, 2011
Ripple Shader
Thank to Adrian Boeing I was inspired this morning to hack together a ripple shader for Unity3D. Thanks for the math Adrian. You can see the animated effect here.
Shader "DM/Ripple Shader" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_Scale ("Scale", Range(0.5,500.0)) = 3.0
_Speed ("Speed", Range(-50,50.0)) = 1.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Cull Off
CGPROGRAM
#pragma surface surf Lambert
#include "UnityCG.cginc"
half4 _Color;
half _Scale;
half _Speed;
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half2 uv = (IN.uv_MainTex - 0.5) * _Scale;
half r = sqrt (uv.x*uv.x + uv.y*uv.y);
half z = sin (r+_Time[1]*_Speed) / r;
o.Albedo = _Color.rgb * tex2D (_MainTex, IN.uv_MainTex+z).rgb;
o.Alpha = _Color.a;
o.Normal = (z, z, z);
}
ENDCG
}
FallBack "Diffuse"
}
Uniform Points On a Sphere
As promised, here is my code for creating a uniform set of points on a sphere.
using UnityEngine;
using System.Collections.Generic;
public class PointsOnSphere : MonoBehaviour {
public GameObject prefab;
public int count = 10;
public float size = 20;
[ContextMenu("Create Points")]
void Create () {
var points = UniformPointsOnSphere(count, size);
for(var i=0; i<count; i++) {
var g = Instantiate(prefab, transform.position+points[i], Quaternion.identity) as GameObject;
g.transform.parent = transform;
}
}
Vector3[] UniformPointsOnSphere(float N, float scale) {
var points = new List<Vector3>();
var i = Mathf.PI * (3 - Mathf.Sqrt(5));
var o = 2 / N;
for(var k=0; k<N; k++) {
var y = k * o - 1 + (o / 2);
var r = Mathf.Sqrt(1 - y*y);
var phi = k * i;
points.Add(new Vector3(Mathf.Cos(phi)*r, y, Mathf.Sin(phi)*r) * scale);
}
return points.ToArray();
}
}
Monday, February 07, 2011
Per Vertex Ambient Occlusion
If you want to bake ambient occlusion into your mesh, here is one way to do it.
This script modifies models on import if it has a filename that ends with "-AO". You can adjust the samples parameter to change the quality / time ratio. I find 1000 samples takes a few seconds, but still provides a good quality.
If you want to use the baked ambient occlusion colours, you need to use a shader that blends these colours in with your material colours. This is a shader I use to visualize vertex colours only.
If you combine this calculated colour, with existing vertex colours on your mesh, you can get quite nice results. The image below uses no lighting, no textures and is very cheap to render. It has 700 vertices.
If you can afford the extra vertices, you can get even better results. The below screenshot shows the same model with 3000 vertices.
There is a problem with the ambient occlusion calculation. I simply use random points on a sphere when creating the samples. This is not ideal, as the set of points are not uniformly distributed on the sphere. This is fairly easy to do, and I'll show how to do this in a later post. Stay tuned!
This script modifies models on import if it has a filename that ends with "-AO". You can adjust the samples parameter to change the quality / time ratio. I find 1000 samples takes a few seconds, but still provides a good quality.
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
class AddVertexAO : AssetPostprocessor
{
int samples = 1000;
void OnPostprocessModel (GameObject go)
{
if (go.name.EndsWith ("-AO")) {
AddAO (go);
}
}
void AddAO (GameObject go)
{
var mf = go.GetComponent<MeshFilter> ();
mf.sharedMesh.Optimize ();
var co = go.GetComponent<MeshCollider> ();
var destoryCollider = co == null;
if (co == null)
go.AddComponent<MeshCollider> ();
var mesh = mf.sharedMesh;
var normals = mesh.normals;
var vertices = mesh.vertices;
var rotations = new Vector3[samples];
var radius = Mathf.Max(mesh.bounds.size.x, mesh.bounds.size.y, mesh.bounds.size.z);
for (var i = 0; i < samples; i++) {
rotations[i] = go.transform.position + (Random.onUnitSphere*radius);
}
var nVertices = new List<Vector3>();
var nColors = new List<Color>();
var nNormals = new List<Vector3>();
var nTriangles = new List<int>();
var index = 0;
foreach (var i in mesh.triangles) {
var n = normals[i];
var v = vertices[i];
var c = Color.white;
var hits = 0f;
foreach(var s in rotations) {
if(Physics.Linecast(s, go.transform.position+v)) {
hits += (1f/samples);
} else {
hits -= (1f/samples);
}
}
c *= (1-hits);
nVertices.Add(v);
nNormals.Add(n);
nColors.Add(c);
nTriangles.Add(index);
index += 1;
}
mesh.vertices = nVertices.ToArray();
mesh.colors = nColors.ToArray();
mesh.normals = nNormals.ToArray();
mesh.triangles = nTriangles.ToArray();
mesh.Optimize();
}
}
If you want to use the baked ambient occlusion colours, you need to use a shader that blends these colours in with your material colours. This is a shader I use to visualize vertex colours only.
Shader "DM/Vertex Coloured" {
Properties {
_Color ("Main Color", Color) = (0.5,0.5,0.5,1)
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf None
float4 _Color;
struct Input {
float4 color : COLOR;
};
half4 LightingNone (SurfaceOutput s, half3 lightDir, half atten) {
half4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
void surf (Input IN, inout SurfaceOutput o) {
half4 c = _Color * IN.color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
Fallback "Diffuse"
}
If you combine this calculated colour, with existing vertex colours on your mesh, you can get quite nice results. The image below uses no lighting, no textures and is very cheap to render. It has 700 vertices.
If you can afford the extra vertices, you can get even better results. The below screenshot shows the same model with 3000 vertices.
There is a problem with the ambient occlusion calculation. I simply use random points on a sphere when creating the samples. This is not ideal, as the set of points are not uniformly distributed on the sphere. This is fairly easy to do, and I'll show how to do this in a later post. Stay tuned!
Friday, February 04, 2011
Tip when using self lit materials.
Thursday, February 03, 2011
Tuesday, February 01, 2011
A 3D Skybox
A 3D skybox sits between your game world and the 2D skybox texture commonly used as a background for your scene.
Why do you need it?
It allows you to have 3D scenery in your background, which the player cannot interact with, yet is still effected by lighting, can use shaders and provide a much higher level of detail than the 2D skybox. This is how I do it in Unity3D.
Why do you need it?
It allows you to have 3D scenery in your background, which the player cannot interact with, yet is still effected by lighting, can use shaders and provide a much higher level of detail than the 2D skybox. This is how I do it in Unity3D.
using UnityEngine;I build my 3D skybox as a child of an empty game object which has the above component attached. I build my skybox at a 1/32 scale, and in the component, I set the level scale to 32. This means that when I hit the play button, the 3D skybox is scaled up and moved out the extremities of my game level.
using System.Collections;
public class Skybox3D : MonoBehaviour {
public float levelScale = 32;
Camera skyCam;
void Start () {
var min = Vector3.zero;
var max = Vector3.zero;
foreach(Transform i in transform) {
i.gameObject.layer = gameObject.layer;
if(i.renderer == null) continue;
var bmax = i.renderer.bounds.max;
var bmin = i.renderer.bounds.min;
min.x = Mathf.Min(min.x, bmin.x);
min.y = Mathf.Min(min.y, bmin.y);
min.z = Mathf.Min(min.z, bmin.z);
max.x = Mathf.Max(max.x, bmax.x);
max.y = Mathf.Max(max.y, bmax.y);
max.z = Mathf.Max(max.z, bmax.z);
}
float absMax;
if(min.sqrMagnitude > max.sqrMagnitude)
absMax = min.magnitude * levelScale * 1.5f;
else
absMax = max.magnitude * levelScale * 1.5f;
transform.localScale = Vector3.one * levelScale;
skyCam = new GameObject("Sky Camera", typeof(Camera)).camera;
skyCam.transform.parent = Camera.main.transform;
skyCam.nearClipPlane = absMax / 3;
skyCam.farClipPlane = absMax;
skyCam.cullingMask = 1 << gameObject.layer;
skyCam.depth = Camera.main.depth - 1;
Camera.main.cullingMask ^= 1 << gameObject.layer;
if(Camera.main.clearFlags != CameraClearFlags.Depth) {
Debug.LogWarning("The main camera must have clear flags set to depth only.");
}
}
}
Subscribe to:
Posts (Atom)
Popular Posts
-
These are the robots I've been working on for the last 12 months. They each weigh about 11 tonnes and have a 17 meter reach. The control...
-
This hard-to-see screenshot is a Generic Node Graph Editing framework I'm building. I'm hoping it can be used for any kind of node...
-
So, you've created a car prefab using WheelCollider components, and now you can apply a motorTorque to make the whole thing move along. ...
-
MiddleMan: A Pub/Sub and Request/Response server in Go. This is my first Go project. It is a rewrite of an existing Python server, based o...
-
Why would I ask that question? Python 3 has been available for some time now, yet uptake is slow. There aren't a whole lot of packages i...
-
It is about 8 degrees C this morning. So cold, especially when last week we had high twenties. To help solve the problem, a friend suggeste...
-
After my last post, I decided to benchmark the scaling properties of Stackless, Kamaelia, Fibra using the same hackysack algorithm. Left axi...
-
I'm now using bzr instead of svn. I'm pushing my repositories to: http://exactlysimilar.org/bzr/ I'm also auto publishing docume...
-
Possibly slightly more correct lighting. The rim light is now only applied in the direction of the sun, rather than being purely based on vi...
-
I've just read a newspaper article (courtesy of Kranzky ) from WA Business News documenting the malfeasance, gross negligence and misc...