Unity Tip: Don’t Use Public to Show Fields in the Unity Editor

If you want to see a variable appear in the Unity editor, you don’t need to make it public. You can use [SerializeField] / @SerializeField to do this and keep your variable private.

//UnityScript
@SerializeField
private var _myPrivateString = "You can see this in the Unity Editor";
//C#
[SerializeField]
private string _myPrivateString = "You can also see this in the Unity Editor";

SerializeField is also important if you’re encapsulating properties in scripts… Properties don’t appear in the Unity editor by default, but if you’re using custom editors, you’ll soon slip on this problem…

//C#
private bool _hiddenValueA = false;
[SerializeField]
private bool _hiddenValueB = false;

//_hiddenValueA IS NOT serialised so when you press play it resets!
public bool valueA
{
    get{return _hiddenValueA;}
    set{_hiddenValueA = value;}
}

//_hiddenValueB IS serialised so when you press play it is saved.
public bool valueB
{
    get{return _hiddenValueB;}
    set{_hiddenValueB = value;}
}

Generating Low Detail Models in BuildR

buildrlowdetail

I’ll admit that I just had a really geeky weekend. I spent most of it coding away and I thought I should share what I’ve learnt. My mini weekend project was rebuilding the low detail model generator in BuildR. It was working fine but for what it does, however it was a little too slow and I felt I should spend some time working out why.

The output needed to be a low poly, single textured version of the high poly model that BuildR outputs. Generating the simplified mesh is super simple. Turning facades into planes and stripping some detail from the roof brought the polycount from 3813 down to 875 in the Paris example above. It was transforming the facade details and textures into a single atlased image that proved time-consuming.

The whole generation process clocked in at about 8000 milliseconds on Saturday morning. This was a little too long, even for doing things in the Unity3D editor. Right now I’ve got it down to 600 without cutting the quality significantly. There is definitely some more research I can do in this area (use RenderTextures maybe?) to reduce it further and 600ms is still far too high for this to be used at runtime.

The key to the problem lay in the powerful function in Texture2D called PackTextures. For most things, this is an awesome, magic function – you just throw your textures in and a single packed texture comes out. Simple right? To do this, PackTextures requires a set of Texture2Ds. That means that BuildR needed to create a new Texture2D object and call Apply for each facade. However, with the large textures that BuildR deals with, these are not only very expensive operations but take up a massive memory footprint.

I figured one way to avoid this would be to use a single Color32 array throughout the whole procedure and use one Texture2D object and Apply call at the end. To do that I needed to build a custom texture packer and texture resize function which I previously allowed Texture2D to handle.

The process I ended up with felt a little backwards at first, but it seemed like the best way. The first thing BuildR now does is build the roof mesh. From this mesh generation, BuildR extracts which textures are used and the world dimensions they occupy so it can atlas an appropriately sized version. The data goes straight into the custom texture packer along with basic facade data.

texturepack

The texture packer actually only generates bounding rectangles for all the textures and does no actual image manipulation  It sorts the textures by width, stacking texture bounds on top of one another. If they don’t fit, they are added to the right creating a new column. There is also no limit at this stage to the size, but the overall dimensions are kept within a square shape as the output would be a power of two.

Once all the rectangle bounds are generated, the whole thing is scaled down to the nearest power of two size and BuildR begins generating facade textures. This involves filling the main colour array with values based on the texture bounds that the texture packer generates.

BuildR needs to resize textures so that they fit the output image size. I ended up implementing a nearest neighbour algorithm to tackle this. This simple algorithm down samples the image into a smaller size giving BuildR reasonable results. I feel there is a lot more research that could be done here, but this ends up being a fairly expensive operation.

blacklines

At this point it’s worth mentioning a problem with using Texture2D.PackTextures padding. You can specify an amount of padding in this function, but the colour of the background is black. The buildings end up with some nasty black lines along some of the facade edges (as above) and it is only worse with lower mipmaps. To solve this, facades need to have their own padding that reflects the edges of the textures.

I’ve attached the RectanglePack.cs class but I’ll do a separate blog post on texture resizing algorithms.

TL:DR – By dumping multiple instances of Texture2D, calls to Apply, performance is dramatically improved. This necessitated dumping a couple of useful Texture2D functions Resize and PackTextures.

BuildR Building Generator is available on the Unity3D Asset Store

Finding out if a Texture is Readable when Editor Scripting for Unity3D

There is a really simple way to find out if a Texture2D is readable when you’re doing an editor script. It took me longer than I expected so I thought I’d blog about it so others might find it easier in the future…

Texture2D myTexture2D;
string texturePath = AssetDatabase.GetAssetPath(myTexture2D);
TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath);
if(textureImporter.isReadable)
{
	//have some fun!
}

It’s pretty simple and something you really need to know if you want to mess with the textures inside the Unity3D editor.

BuildR – released onto the Unity3D Asset Store

BuildR - on the Unity3D Asset StoreToday I released my second product on the Unity3D Asset Store. It’s very much based off the work I have been doing on Redacted though it’s pursuing a different direction (realistic external rather than abstract/internal building generation). With BuildR you can create external building models within the Unity3D IDE without a 3D modeling program. I’ve worked hard to create a simple system that gives the user as much control over the building as I could imagine. At the moment you can export your model into the OBJ format although I’m working on an FBX export option too (a little trickier as I’m having to reverse engineer the file format – fun!).
I’m releasing it as a beta and at a reduced price to begin with. I’m not sure how many bugs people will find as there is only so much testing a few people can do. I also feel like there might be additions to the workflow as some people will want it to use BuildR in ways I have not yet imagined. At the moment it’s not really set up to run at runtime, there’s little support to link into other code or is it ready for full procedural generation. I’m confident this will all be included in the future though. As the codebase matures and more features make it to the release, I will increase the price.
I’d like to give a big thanks Sergio, Aidan, Jerome who very kindly had a go on some of the early alpha/beta releases and weeded out some bugs, smoothed some edges and made it a better product.

Get it here on the Unity3D Asset Store
Check out the main website for more details

Simple Concave 2D Triangulator for Unity

When making BuildR, I came across the need for a triangulation algorithm. I’ve not really looked into this much in the past apart from playing with Delaunay triangulation on previous projects. Searching Unity and the web there are many resources – but nothing that actually worked for me in my use case.

  • simple polygon – no holes or line intersections
  • concave – so I can’t rely on any convex hull knowledge
  • only in 2D

One of the first stops was the Triangulator on the Unify Wiki. This looked great but it didn’t work for me, I’m not sure why as it seams to work for everyone else. I stumbled upon this article however and got the idea that I could just write my own one from scratch – which I did! Yay.

EarClipper.cs
Vector2z.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EarClipTriangle
{
	public Vector2z a;
	public Vector2z b;
	public Vector2z c;
	public Rect bounds;
	
	public EarClipTriangle(Vector2z a, Vector2z b, Vector2z c)
	{
		bounds = new Rect(a.x,a.z,0,0);
		Vector2z[] points = new Vector2z[]{a,b,c};
		for(int i=1; i<3; i++)
		{
			if(bounds.xMin < points[i].x)
				bounds.xMin = points[i].x;
			if(bounds.xMax < points[i].x)
				bounds.xMax = points[i].x;
			if(bounds.yMin < points[i].z)
				bounds.yMin = points[i].z;
			if(bounds.yMax < points[i].z)
				bounds.yMax = points[i].z;
		}
	}
}

public class EarClipper 
{

	public static int[] Triangulate( Vector2z[] points)
	{
		int numberOfPoints = points.Length;
		List<int> usePoints = new List<int>();
		for(int p=0; p<numberOfPoints; p++)
			usePoints.Add(p);
		int numberOfUsablePoints = usePoints.Count;
		List<int> indices = new List<int>();
		
        if (numberOfPoints < 3)
            return indices.ToArray();
		
		int it = 100;
		while(numberOfUsablePoints > 3)
		{
			for(int i=0; i<numberOfUsablePoints; i++)
			{
				int a,b,c;
				
				a=usePoints[i];
				
				if(i>=numberOfUsablePoints-1)
					b=usePoints[0];
				else
					b=usePoints[i+1];
				
				if(i>=numberOfUsablePoints-2)
					c=usePoints[(i+2)-numberOfUsablePoints];
				else
					c=usePoints[i+2];
				
				Vector2 pA = points[b].vector2;
				Vector2 pB = points[a].vector2;
				Vector2 pC = points[c].vector2;
				
				float dA = Vector2.Distance(pA,pB);
				float dB = Vector2.Distance(pB,pC);
				float dC = Vector2.Distance(pC,pA);
				
				float angle = Mathf.Acos((Mathf.Pow(dB,2)-Mathf.Pow(dA,2)-Mathf.Pow(dC,2))/(2*dA*dC))*Mathf.Rad2Deg * Mathf.Sign(Sign(points[a],points[b],points[c]));
				if(angle < 0)
				{
					continue;//angle is not reflex
				}
				
				bool freeOfIntersections = true;
				for(int p=0; p<numberOfUsablePoints; p++)
				{
					int pu = usePoints[p];
					if(pu==a || pu==b || pu==c)
						continue;
					
					if(IntersectsTriangle2(points[a],points[b],points[c],points[pu]))
					{
						freeOfIntersections=false;
						break;
					}
				}
				
				if(freeOfIntersections)
				{
					indices.Add(a);
					indices.Add(b);
					indices.Add(c);
					usePoints.Remove(b);
					it=100;
					numberOfUsablePoints = usePoints.Count;
					i--;
					break;
				}
			}
			it--;
			if(it<0)
				break;
		}
		
		indices.Add(usePoints[0]);
		indices.Add(usePoints[1]);
		indices.Add(usePoints[2]);
		indices.Reverse();
		
		return indices.ToArray();
	}
	
	private static bool IntersectsTriangle(Vector2z A, Vector2z B, Vector2z C, Vector2z P)
	{
		bool b1, b2, b3;

		b1 = Sign(P, A, B) < 0.0f;
		b2 = Sign(P, B, C) < 0.0f;
		b3 = Sign(P, C, A) < 0.0f;
		
		return ((b1 == b2) && (b2 == b3));
	}
	
	private static float Sign(Vector2z p1, Vector2z p2, Vector2z p3)
	{
		return (p1.x - p3.x) * (p2.z - p3.z) - (p2.x - p3.x) * (p1.z - p3.z);
	}
					
	private static bool IntersectsTriangle2(Vector2z A, Vector2z B, Vector2z C, Vector2z P)
	{
			float planeAB = (A.x-P.x)*(B.y-P.y)-(B.x-P.x)*(A.y-P.y);
			float planeBC = (B.x-P.x)*(C.y-P.y)-(C.x - P.x)*(B.y-P.y);
			float planeCA = (C.x-P.x)*(A.y-P.y)-(A.x - P.x)*(C.y-P.y);
			return Sign(planeAB)==Sign(planeBC) && Sign(planeBC)==Sign(planeCA);
	}
	
	private static int Sign(float n) 
	{
		return (int)(Mathf.Abs(n)/n);
	}
}

// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.