using UnityEngine;
using System.Collections;
public class LOD : MonoBehaviour
{
//distances where LOD transitions occur.
public float[] lodLevels = new float[] { 1000f, 800f, 600f, 400f, 200f, 100f, 50f, 10f };
//These are the builtin LOD values for Unity shaders.
int[] shaderLOD = new int[] { 600, 500, 400, 300, 250, 200, 150, 100 };
void Start ()
{
StartCoroutine ("UpdateLOD");
}
void SetLOD (int LOD)
{
foreach (var i in renderer.sharedMaterials) {
i.shader.maximumLOD = shaderLOD[LOD];
}
}
IEnumerator UpdateLOD ()
{
var period = Random.value;
var cam = Camera.main.transform;
float[] levels = new float[lodLevels.Length];
int i = 0;
foreach (var level in lodLevels) {
levels[i++] = level * level;
}
while (true) {
var distance = (transform.position - cam.position).sqrMagnitude;
var LOD = levels.Length - 1;
foreach (var level in levels) {
if (distance > level) {
SetLOD (LOD);
break;
}
LOD--;
}
// make LOD checking non deterministic. avoids stampeding LOD calls?
yield return new WaitForSeconds (period);
}
}
}
Saturday, October 30, 2010
A Unity Shader LOD Script.
Dubious Value of the Social Network.
I've been slowly extricating myself from various social networks for a while now. I've found I get a lot more things done.
I do like to stay on the bleeding edge of technology, in front of the game, so to speak. Being disconnected has not hurt this at all, in my opinion. I've not lost any business opportunities, friends or missed out on some new, important, game-changing tech...
I think the only things I'm missing out on are the latest LOL-cat or some other random funny waste of time. Or some random interesting but ultimately worthless blog post.
The above image is an advert targeting software developers, it is not a paid advert I have place on this site. It's message is clear.
What are social networks good for? Exploitation and making money. They're great for selling unmitigated garbage to the masses, where you watch them gulp it down in micro-payment sized portions and then beg for some more. If you have a product to sell, use the social networks. If you want to achieve things, leave them far behind, or exploit them for what they are.
I do like to stay on the bleeding edge of technology, in front of the game, so to speak. Being disconnected has not hurt this at all, in my opinion. I've not lost any business opportunities, friends or missed out on some new, important, game-changing tech...
I think the only things I'm missing out on are the latest LOL-cat or some other random funny waste of time. Or some random interesting but ultimately worthless blog post.
The above image is an advert targeting software developers, it is not a paid advert I have place on this site. It's message is clear.
What are social networks good for? Exploitation and making money. They're great for selling unmitigated garbage to the masses, where you watch them gulp it down in micro-payment sized portions and then beg for some more. If you have a product to sell, use the social networks. If you want to achieve things, leave them far behind, or exploit them for what they are.
Friday, October 29, 2010
Generic Manager Component
We've found ourselves using this pattern across a number of projects.
Eg, you may have a MusicMixer component which will continue to play music across Application.LoadLevel calls. Instead of creating the MusicMixer in every scene, (or in one scene and marking it with DontDestryOnLoad) you can access it via:
using UnityEngine;It is used to create components which persist across level loads, without needing to create GameObjects to hold those components in the editor. It solves the problem where you may need to load levels in a specific order to make sure your persistent game objects are available in the level you wish to test.
using System.Collections;
public class Manager : MonoBehaviour {
static public T Instance<T>() where T : Component {
T component;
var g = GameObject.Find("/" + typeof(T).ToString());
if(g == null) {
g = new GameObject(typeof(T).ToString());
component = g.AddComponent<T>();
DontDestroyOnLoad(g);
} else {
component = g.GetComponent<T>();
}
return component;
}
}
Eg, you may have a MusicMixer component which will continue to play music across Application.LoadLevel calls. Instead of creating the MusicMixer in every scene, (or in one scene and marking it with DontDestryOnLoad) you can access it via:
Manager.Instance<MusicMixer>();And if it does not exist in the level already, it will be created and returned, and also used across subsequent references to the MusicMixer.
Unity3D Mesh Combining Tip
You don't need to use the CombineChildren component anymore. It appears that anything marked as static is now automatically batched.
Excellent.
Excellent.
Monday, October 25, 2010
Generic Thread Safe RingQueue in C#
using System;
using System.Threading;
public class RingQueue
{
private int size;
private int read = 0;
private int write = 0;
private int count = 0;
private T[] objects;
private AutoResetEvent addEvent;
private AutoResetEvent popEvent;
public RingQueue (int size)
{
addEvent = new AutoResetEvent (false);
popEvent = new AutoResetEvent (false);
this.size = size;
objects = new T[size + 1];
}
public bool Empty {
get {
lock (this) {
return (read == write) && (count == 0);
}
}
}
public bool Full {
get {
lock (this) {
return (read == write) && (count > 0);
}
}
}
public void Add (T item)
{
lock (popEvent) {
if (Full) {
popEvent.WaitOne ();
}
objects[write] = item;
count++;
write = (write + 1) % size;
addEvent.Set ();
}
}
public T Pop ()
{
lock (addEvent) {
if (Empty) {
addEvent.WaitOne ();
}
T item = objects[read];
count--;
read = (read + 1) % size;
popEvent.Set ();
return item;
}
}
}
Saturday, October 23, 2010
Proposed Shader for Unity3D
I want to build an fairly high level shader. Here are initial thoughts on features or passes the shader should have.
0. Vertex Colours (RGB)
1. Color Map (RGB Color, A Illumination)
2. Normal Map
3. Specular Map (RGB Color, A Shininess)
5. Environment Cube Map
The specular map is used for environment mapping, in that the Alpha channel shows which parts of the model will be shiny, and therefore reflect the environment. The RGB channels in the specular map are used to tint the colour of the reflection. The reflected texture should follow the distortions created by the normal map.
Vertex colours are used to tint the model, and will be used for fake ambient lighting effects.
Fallback Shader
The shader should fallback to using passes 0,1,2 and 3, Then fallback to 0,1 and 2 and finally fallback to 0 and 1 as quality is reduced.
0. Vertex Colours (RGB)
1. Color Map (RGB Color, A Illumination)
2. Normal Map
3. Specular Map (RGB Color, A Shininess)
5. Environment Cube Map
The specular map is used for environment mapping, in that the Alpha channel shows which parts of the model will be shiny, and therefore reflect the environment. The RGB channels in the specular map are used to tint the colour of the reflection. The reflected texture should follow the distortions created by the normal map.
Vertex colours are used to tint the model, and will be used for fake ambient lighting effects.
Fallback Shader
The shader should fallback to using passes 0,1,2 and 3, Then fallback to 0,1 and 2 and finally fallback to 0 and 1 as quality is reduced.
Thursday, October 21, 2010
RMS in Perth - A Summary.
I recently attended a talk by Richard Stallman, at the Hyatt Hotel in Perth.
A highlight of the night was when fellow Python Enthusiast Brad (from Rockethands) was stopped by Stallman as he arrived late to the talk.
You can read an excellent summary over here.
The best part of the talk was question time. Hearing Stallman adeptly defend his views was quite inspiring.
A highlight of the night was when fellow Python Enthusiast Brad (from Rockethands) was stopped by Stallman as he arrived late to the talk.
You can read an excellent summary over here.
The best part of the talk was question time. Hearing Stallman adeptly defend his views was quite inspiring.
Wednesday, October 20, 2010
Be an Indie Game Developer in 9 Steps.
- Make sure you have more ideas than talent.
- Hate the big publishers and anything mainstream.
- Join mailing lists with other Indie developers.
- Blog and write about awesome games you will make one day.
- Whine about scarcity of funding and lack of government handouts.
- When you eventually make "something", whine about the lack of sales.
- Whine about about the App Store being full of shovel-ware.
- Watch other developers make money. Call them sell-outs. They don't deserve the "Indie" badge.
- Rinse and Repeat.
Tuesday, October 19, 2010
RMS
Went and saw RMS speak tonight.
Does RMS ever get tired of playing Saint IGNUcius? Imagine telling the same joke for decades; surely it eventually gets a bit stale.
Does RMS ever get tired of playing Saint IGNUcius? Imagine telling the same joke for decades; surely it eventually gets a bit stale.
Monday, October 18, 2010
Custom Coroutines in Unity3D.
I had a whim today. In my Python green threading framework (Fibra), it is possible to run a section of code inside the green thread function in another OS level thread. This lets you do fun things like break out of the main thread when waiting for IO, or doing something that might block the rest of the green threads.
In Unity3D-speak, a green thread is called a Coroutine. After doing some rather ugly things with threads today, I figured things could be much cleaner if I could simply execute certain parts of a Coroutine outside the Unity3D main loop. It is possible, and I've done it. Here is the code! :-)
This is the test MonoBehaviour script. Notice that it inherits from Fibra, and uses StartGreenThread to execute methods that look like real Unity3D Coroutines. Inside the Coroutine, a FiBranch instance is yielded, which is the signal for the scheduler to run the next section of the Coroutine in the thread pool.
This is the Fibra class, which implements the green threading magic.
The above class uses a double dispatch mechanism, which makes it a piece of cake to add your own custom schedule instructions. Simply inherit from FInstruction, and write your own Execute method. Return true if you want the green thread to be rescheduled, or false if you don't.
In Unity3D-speak, a green thread is called a Coroutine. After doing some rather ugly things with threads today, I figured things could be much cleaner if I could simply execute certain parts of a Coroutine outside the Unity3D main loop. It is possible, and I've done it. Here is the code! :-)
This is the test MonoBehaviour script. Notice that it inherits from Fibra, and uses StartGreenThread to execute methods that look like real Unity3D Coroutines. Inside the Coroutine, a FiBranch instance is yielded, which is the signal for the scheduler to run the next section of the Coroutine in the thread pool.
using UnityEngine;
using System.Collections;
using System.Threading;
public class FibraTest : Fibra {
public IEnumerator Busy() {
Debug.Log("Before Continue.");
yield return new FiContinue();
Debug.Log("After Continue.");
yield return new FiContinue();
Debug.Log("Finished.");
yield return new FiSleep(3);
Debug.Log("Ok really finished. Well with this CPU anyway:" + Thread.CurrentThread.ManagedThreadId.ToString());
yield return new FiBranch();
Debug.Log("I'm in another thread:" + Thread.CurrentThread.ManagedThreadId.ToString());
Thread.Sleep(1000);
yield return new FiContinue();
Debug.Log("Done:" + Thread.CurrentThread.ManagedThreadId.ToString());
}
// Use this for initialization
void Start () {
StartGreenThread("Busy");
}
// Update is called once per frame
public new void Update () {
base.Update();
}
}
This is the Fibra class, which implements the green threading magic.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public abstract class FInstruction
{
public abstract bool Execute (Fibra scheduler, IEnumerator task);
}
public class FiContinue : FInstruction
{
public override bool Execute (Fibra scheduler, IEnumerator task)
{
return true;
}
}
public class FiBranch : FInstruction
{
public override bool Execute (Fibra scheduler, IEnumerator task)
{
ThreadPool.QueueUserWorkItem(delegate(object state) {
bool removeTask = false;
try {
if (task.MoveNext ()) {
var fi = task.Current as FInstruction;
removeTask = !fi.Execute (scheduler, task);
} else
removeTask = true;
} catch(Exception e) {
// Do something in here!
}
if(!removeTask) {
scheduler.StartGreenThread(task);
}
});
return false;
}
}
public class FiSleep : FInstruction
{
float seconds;
public FiSleep (float seconds)
{
this.seconds = seconds;
}
IEnumerator Sleep (Fibra scheduler, IEnumerator task)
{
yield return new WaitForSeconds (seconds);
scheduler.StartGreenThread (task);
}
public override bool Execute (Fibra scheduler, IEnumerator task)
{
scheduler.StartCoroutine (Sleep (scheduler, task));
return false;
}
}
public class Fibra : MonoBehaviour
{
static List<IEnumerator> tasks = new List<IEnumerator> ();
static Dictionary<string, IEnumerator> names = new Dictionary<string, IEnumerator> ();
public void StartGreenThread (string taskName, params object[] args)
{
var method = this.GetType ().GetMethod (taskName);
if (args.Length == 0)
args = null;
var task = method.Invoke (this, args) as IEnumerator;
names.Add (taskName, task);
StartGreenThread (task);
}
public void StopGreenThread (string taskName)
{
var task = names[taskName];
Fibra.tasks.Remove (task);
names.Remove (taskName);
}
public void StartGreenThread (IEnumerator task)
{
lock(Fibra.tasks) {
Fibra.tasks.Add (task);
}
}
public void Update ()
{
for (int i = 0; i < Fibra.tasks.Count; i++) {
bool removeTask = false;
var task = tasks[i];
if (task.MoveNext ()) {
var fi = task.Current as FInstruction;
removeTask = !fi.Execute (this, task);
} else
removeTask = true;
if (removeTask)
tasks.RemoveAt (i--);
}
}
}
The above class uses a double dispatch mechanism, which makes it a piece of cake to add your own custom schedule instructions. Simply inherit from FInstruction, and write your own Execute method. Return true if you want the green thread to be rescheduled, or false if you don't.
Thursday, October 07, 2010
ZeroConf Ubuntu Server Setup
Situation: You have a development server (Running the Ubuntu Server OS), an OSX work station, and one network cable.
Task: Enable networking between the two via a network cable so that development can commence!
Action:
1. Plug cable in, notice that network is non existent.
2. Install needed software on server.
3. Modify /etc/network/interface file. Change or add a section like this:
4. Restart networking.
5. Ping yourserver.local from your workstation.
Response: Voila, networking is now working.
Task: Enable networking between the two via a network cable so that development can commence!
Action:
1. Plug cable in, notice that network is non existent.
2. Install needed software on server.
sudo apt-get install avahi-daemon avahi-autoipd
3. Modify /etc/network/interface file. Change or add a section like this:
auto eth0(The ipv4ll is the magic bit.)
iface eth0 inet ipv4ll
4. Restart networking.
sudo /etc/init.d/networking restart
5. Ping yourserver.local from your workstation.
Response: Voila, networking is now working.
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...