Detecting Property Changes

My little rant generated some questions that it may be easier to clear up here than 140 characters at a time.

Sometimes you want to execute some functionality when changing the value of a property. The key word there is “changing”. In order to know if the property changed you must compare the new value to the current value. It looks something like this:

// some field in your class
int value;  

void SetValue(int newValue)
{
  if (value != newValue)
  {
    value = newValue;
    // do some stuff that you only want to do if the value changes
  }
}

Works great. I mean, why do extra work if some other code is setting a value to the same value?

But does it work with floating point? I mean, we’re never supposed to do equality comparisons with floating point right? But in this pattern that’s not what we’re really doing is it? We’re just concerned that the value changed. How we arrived at the value being passed in isn’t relevant. This method just cares that the value is different from the previous value.

And this was the source of my frustration in my previous post. I wanted to know that the value had changed, not that it was close. And in my mind at least, using an equality operator is the proper way to do that.

Here is the code behind Unity’s equality operator. Inequality is the same with the opposite sign.

// UnityEngine.Vector3
public static bool operator ==(Vector3 lhs, Vector3 rhs)
{
  return Vector3.SqrMagnitude(lhs - rhs) < 9.99999944E-11f;
}

That works great. It isn’t a bug. It is valuable and even necessary functionality when you’re dealing with floating point and vectors and such. I just believe it doesn’t belong in the operator that’s testing for equality, because close is not the same thing as equals. But maybe that’s just me.

Here is some of the code for the Equals method.

// UnityEngine.Vector3
public override bool Equals(object other)
{
  Vector3 vector = (Vector3)other;
  return this.x.Equals(vector.x) && this.y.Equals(vector.y) && this.z.Equals(vector.z);
}

That is not close, that is equal. And that is what I expect from my equality operators.

This has nothing to do with dealing with floating point rounding errors or the wisdom of comparing calculated floating point values or anything like that. It has to do with expected behavior. But perhaps my expectations are unreasonable and that makes me a clown.

Should Unity change it? Probably not at this point. Who knows what it would break.

And that’s all I have to say about that.

Unity Vector Comparison Rant

I recently ran into an interesting Unity feature that I didn’t know about previously. I kept having an agent get stuck in the same place for no apparent reason. I’ve spent two days trying to track down the problem and finally ran across this in the least expected place – a function written almost on day 1 of this project, over a year and a half ago.

Surprising Vector Comparison

 

I’m trying to set my x position to 32. Since I’m generating an event when the position changes I only want to change it if the value being passed is actually different. Looking at the various values in the debugger the position is indeed different. Comparing the previous and new x values directly indeed shows that they are not equal, but when comparing the vectors themselves they come out as equal!

I went to answers.unity3d.com to ask a question about it, but did due diligence first and searched for a similar problem and found a reference to vector equality operator documentation. The key verbiage is:

This will also return true for vectors that are really close to being equal.

All I can say is wtf?

Now, I understand why they did this – floating point rounding and precision and all that. But to put that functionality in an actual equality operator, which is supposed to be testing for equality, is not the proper way to handle that. It is surprising and unexpected behavior. Adding an Approximately method would have been a much better choice, like they did for floats in Mathf.Approximately.

need my vector value to change to the integer values. I expect the equality operator to actually check for equality. The fact that it does not cost me two days trying to find a bug that should not have existed.

End of rant. On the plus side, I now have a nice and robust code tracing system for more easily tracking down this sort of thing in the future. Silver linings and all that.

 

Create a GameObject Image Using Render Textures

On occasion when making a video game there is a need to display a texture that contains an image of a 3D game object. For example, to display in a toolbar, or chat message or something similar. These images could be created statically by your artist, but sometimes the image needs to change based on something happening in the game, or there is some other compelling reason where runtime creation is required.

Render Textures are a straightforward method for creating an image like this at runtime. I’ll spend the rest of this post describing how I do this sort of thing. I’m not going to do a step by step tutorial. I’ll mostly just describe the actual rendering part, and you can look at the code for the rest.

First, we set up a camera that will be used to render the object. I usually make it orthographic and fill with a solid background color, but you can really do anything you want. I also set up a single light. The camera and the light all get their own layer to work on, and the main game camera has its culling mask set to ignore that layer.

Here are the settings I usually use. Note the layer and and culling mask. Also, you’ll need to remove the Audio Listener or you get complaints from Unity about having multiples.

ObjectImageCameraProperties

To render the object, we first want to clone it. This lets us change the object’s properties at will without messing with the original.

GameObject gameObject =
  GameObject.Instantiate(prefab, position, rotation) as GameObject;
gameObject.transform.localScale = scale;

We instantiate the object at the desired position and rotation, then set the scale. These values need to be set so the object is positioned in front of the rendering camera. You can really do whatever you want here, even add multiple objects and lights and set up a whole scene.

Now we need to make sure the cloned object, and any children, are in the layer that the camera renders. So we set the layer by calling this function, passing in the cloned object.

void SetLayerRecursively(GameObject o, int layer)
{
    foreach (Transform t in o.GetComponentsInChildren<Transform>(true))
        t.gameObject.layer = layer;
}

Now we get to the fun part. We could create a render texture in the editor and assign it to the camera, but Unity provides a nice way to acquire a temporary render texture with code. I believe it was designed to simplify post processing effects, but it works equally well for our needs.

camera.targetTexture = RenderTexture.GetTemporary(128, 128, 16);

RenderTexture.GetTemporary allows us to acquire a temporary render texture from a pool maintained by Unity. Here, we’re asking for a small texture with a 16-bit depth buffer. You can check out the documentation for additional parameters and other information about how it works. It’s worth mentioning that if you ask for a format that isn’t supported the texture will come back as null without raising any errors (at least it did for me). So it’s a good idea to check for a null return value and deal with it accordingly.

We assign the temporary render texture to our camera’s target texture. This means that when we tell the camera to render, the results will go to our render texture instead of the screen.

And the render comes next.

camera.Render();

This will render everything the camera sees into our render texture. To recap:

  • We’ve set up a camera on its own layer.
  • We cloned the object we want to take a picture of.
  • We positioned the object in front of our camera, and changed the object to the render camera layer.
  • We acquired a temporary render texture and assigned it as the camera’s target texture.
  • We told the camera to render.

So at this point we should have our object rendered to the render texture. Now we need to get that object into a texture.

RenderTexture saveActive = RenderTexture.active;
RenderTexture.active = camera.targetTexture;
float width = camera.targetTexture.width;
float height = camera.targetTexture.height;

Texture2D texture = new Texture2D(width, height);
texture.ReadPixels(new Rect(0, 0, texture.width, texture.height), 0, 0);

texture.Apply();

This code saves the active render texture, makes our render texture active, creates a new Texture2D instance, then copies the pixels from the render texture to the Texture2D.

Finally, we call Texture2D.Apply to actually perforom the pixel copy.

All that’s left now is to clean up after ourselves by restoring the previously active render texture, releasing the temporary render texture we acquired earlier, and destroying the cloned game object.

RenderTexture.active = saveActive;
RenderTexture.ReleaseTemporary(objectImageCamera.targetTexture);
GameObject.DestroyImmediate(gameObject);

And that’s about it. The trickiest part is getting the object positioned and rotated properly in front of the camera so it looks good.

Here is a sample project that implements this. It includes a nice prefab for setting up the camera and everything.

So there you have it. Enjoy.