Saturday, September 24, 2011

Handling Texture Tiling and Offset in a Unity3d Vertex and Fragment Shader using TRANSFORM_TEX macro

When doing some test work, I found my Cg shader wasn't handling texture offset and tiling properly, resulting in distortion such as below:

The Unity shader on the left properly handles a 3x tiling factor for the texture, while my shader on the right doesn't properly handle the same 3x tiling factor



My shader setup was pretty simple, here's a snippet of the important parts:

#include "UnityCG.cginc"

sampler2D _MainTex;
float4 _Color;

v2f vert ( appdata_base v )
{
    v2f o; 

    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

    // Texture offset - BAD
    o.uv = v.texcoord;
    return o;
}

half4 frag (v2f i) : COLOR
{    
    return tex2D(_MainTex, i.uv) * _Color;
}

I bolded the problematic part, which is the Texture UV handling in the 'vert' program.  Simply grabbing the v.texcoord will work when there is not tiling or offsets in the texture, but breaks once those elements are introduced

After snooping around, I found the solution is to use the TRANSFORM_TEX macro in the UnityCG.cginc to make sure the texture's offset and tiling are properly applied.  A small caveat to this is you must, "declare float4 properties for each texture before the vertex program, with _ST appended" (Quoted from Unity3d shader docs).

Here's a snippet of my shader with the new changes:

#include "UnityCG.cginc"

sampler2D _MainTex;
float4 _Color;
uniform float4 _MainTex_ST; // Needed for TRANSFORM_TEX(v.texcoord, _MainTex)

v2f vert ( appdata_base v )
{
    v2f o; 

    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

    // Texture offset - GOOD
    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    return o;
}

half4 frag (v2f i) : COLOR
{    
    return tex2D(_MainTex, i.uv) * _Color;
}

With this happy little change, our shader now properly handles the tiling and offsets of the texture.
 

For those curious, I gleaned this information from the Unity3D Vertex and Fragment Programs and the ancient Unity 2.x Shader Conversion Guide.  The info pulled from the Shader conversion guide regards the _MainTex_ST property needed for TRANSFORM_TEX to work. 

UPDATE - Dec 1, 2013 - The Unity 2.x Shader Conversion Guide seems to have disappeared from the internet.  This information is all still relevant for Unity 4.x release versions

Sunday, June 5, 2011

Oddness with Unity3D Android's MD5 support

I ran into an odd problem when messing around with generating MD5 hashes in Unity Android recently.

When testing on my PC I was creating an MD5 object by using MD5.Create() and it worked fine. However I then published over to my Android phone to test to make sure it works, good thing I did, because I got a NullReferenceException. Looking at the code, the only thing that jumped out at me was the MD5 object wasn't being created, so I added a check for that condition, and indeed the MD5 object didn't exist. So for some reason MD5.Create() didn't work on the Android hardware.

A little bit of Googling landed me on unifycommunity.com, where I noticed the author, Matthew Wegner, wasn't using the MD5.Create() method but new'ing a MD5CryptoServiceProvider object. Curious, since they both seem to return the same object, I tried out this new method and to my amazement it worked! Horray!

Before I was about to close the book on this and forget MD5.Create() forever, I noticed my project had the Stripping Level set to use micro mscorlib. That turned on a light in my head, so out of curiosity I disabled stripping, re-enabled MD5.Create and re-published to my phone. This time MD5.Create worked.

TL;DR
MD5.Create() doesn't return an object on Unity Android when the Stripping Level is set to Micro mscorlib, but 'new MD5CryptoServiceProvider()' does. When Stripping is disabled MD5.Create() does work as expected. I haven't tested this on the iPhone but the results are probably the same.

Even Short Version:
It's seems safest to 'new MD5CryptoServiceProvider()' whenever you need an MD5 object as it appears to be the most portable.

Thursday, January 13, 2011

Valid, yet scary, code syntax

I recently encountered a scary piece of code syntax which is actually valid, but nevertheless, very confusing. The gist of it was like this (sorry for code formatting):

 if ( myobject == null )  
 {  
   *misc stuff done here*  
   myobject->PrintInfo();  
 }  

For most programmers taking a first look at snippet, it would be a huge red flag of a potential crash waiting to happen. Why the heck would you check for a pointer being null, then call a method on it? However, it ends up this is perfectly valid because the 'PrintInfo()' method looks something like this:

 void PrintInfo ()  
 {  
   if ( this != null )  
   {  
     *do work*  
   }  
 }  

PrintInfo does a null check on the this pointer before accessing any members, which will prevent a crash if the pointer you call the method on is null. This will compile and run without errors, but is sure to drive other programmers up a tree when they see it :D

Friday, November 12, 2010

Dangers of multi-threaded applications

Creating multi-threaded applications can be a scary task (at least for me). The common problems such as deadlocks, race conditions and corrupted memory are pretty intimidating, especially if you're just starting out. One less famous, but still nefarious, problem you can run into in multi-threaded development are continuously spinning threads. I'm sure there's a more common name for these, but essentially they are threads running in a non-stop loop, polling for new stuff to work on. Threads like these run as fast as possible in this loop, and greedily consume as much CPU time as they can; which leads to horrendous performance loss.

We ran into a very bad version of this today on new server software we mass tested for the first time. A lot of people complained about being unable to connect to the server, move through our game levels, or interact with items in the levels. I confirmed the server processes were running at 100% CPU, so we started looking at where our performance was going. What made matters frustrating was on our (beefy) dev machines, the servers were only running at about 8-10% usage. We spent a little time looking at some game engine profile output, and looking at some asset issues we thought were the culprit. In the end I wish I could say we found the problem through some tool or cool debug technique; but rather it came about when, on a whim, I asked another developer about some threaded functionality he recently added. I asked him to check his code to make sure his new thread was yielding if there was nothing for it to do, and voila, we found the problem.

It ended up he originally built the threaded task with some blocking functionality which had controlled the thread CPU usage (unintentionally), but later changed it to use non-blocking calls. After this change he forgot to add a thread sleep call, so the thread was simply spinning in a loop looking for something to do. While he fixed the code, I figured out how to setup a test case for our dev machines to reproduce the problem of 100% CPU usage on the servers. I remembered we could set the processor affinity through the task manager, which would allow us to simulate a single-core machine to run the game server on. Once I did this, I was able to see the game server spiking up to 100% CPU usage on the assigned core. Next I integrated our fix, which was to simply sleep the thread for 10ms every loop, and re-ran my test. The server dropped from 100% CPU usage to between 0 and 1% while idling!

Overall, it was a good day today, long as hell though.

Sunday, September 19, 2010

Read an interesting Gamasutra blog today

I read an interesting blog on Gamasutra today written by an indie developer about his first week working full-time on his project. Reading it reminded me of what it was like for me when I first made the plunge from a mod-developer in my free time to a professional game developer full time. The biggest thing I remember thinking back then, was how awesome it was to have so much time available to work on projects. Going from 'doing what I can in my free time' to 'doing this for 8 hours a day' is quite a change. Some people handle that transition well, and some people don't.

As for me, I'm currently waiting to hear back from my project partner to see if he'll be available to meet up at a coffee place today to do some work. We've made some good progress on our project so far, and I've been pretty happy so far. I let one of my co-workers play an early version on my iPhone last night and he actually seemed to enjoy what was in there so far, so I'm pretty happy about that.

Monday, August 30, 2010

Good work day on Sunday

I had a very good working day on Sunday with my game development partner. On Thursday we agreed the scope of our previous project was too large for our tastes, and decided to go in a new direction. So far that decision has been a good one, the new idea we're running with is much smaller scope, and we're able to reuse a lot of content and code from the last project.

Last night I mocked up the movement for our main entity and it feels pretty good. The other cool thing we did was build and publish a test build to an iPhone and an Android device. So far there's no content or real gameplay yet, but it's looking much less daunting now.

Tuesday, August 17, 2010

Sweet Borderlands sale on Steam

Steam is currently hosting a pretty sweet sale for Borderlands and associated DLC content; for ~$20 you can grab the game and all 3 DLC packs.

I decided to pick it up seeing as one of my co-workers is currently playing Borderlands and has been trying to convince me to play. It looks pretty interesting, I've had my eye on it for awhile but never got around to trying it out because of other games and such. I'm still working as much as I can on my Unity3d project, it's coming along but not as fast as I would like it to.

On the server front, I haven't made any decisions yet. I still want to get a server of some sort, but I've been putting off on it for the past few weeks.