Friday, January 21, 2011

The Unity3D Asset Pipeline.

One of the great things about Unity3D, is the programmable content pipeline. I wrote this script so that when I add a texture named "x_SPECULAR.png" to my project, it looks for a texture named "x_DIFFUSE.png", and then copies the specular texture into the alpha channel of the diffuse texture (so that it can be used in a Unity3D specular shader). This automates what would usually be a tedious Photoshop task.

using UnityEngine;
using UnityEditor;
using System.Collections;

class ModifyTextures : AssetPostprocessor

void OnPostprocessTexture (Texture2D texture)
if (assetPath.Contains ("_SPECULAR")) {
var diffusePath = assetPath.Replace ("_SPECULAR", "_DIFFUSE");
var bytes = System.IO.File.ReadAllBytes (diffusePath);
var diffuse = new Texture2D (texture.width, texture.height);
diffuse.LoadImage (bytes);
var colors = diffuse.GetPixels ();
var specular = texture.GetPixels ();
if (colors.Length == specular.Length) {
Debug.LogWarning (assetPath + ": Adding specular values to diffuse map alpha.");
for (var i = 0; i < colors.Length; i++) {
colors[i].a = (specular[i].r + specular[i].g + specular[i].b) / 3;
diffuse.SetPixels (colors);
diffuse.Apply ();
System.IO.File.WriteAllBytes (diffusePath, diffuse.EncodeToPNG ());
AssetDatabase.ImportAsset (diffusePath);
} else {
Debug.LogWarning (assetPath + ": specular size must match diffuse size.");


Dark Acre Jack said...

Thank you very much for sharing this!

I've tried converting it to C#, and I get an error CS0117 : 'System.IO.File' does not contain a definition for 'ReadAllBytes' and 'WriteAllBytes'

I've searched the forums and so forth, but can't seem to find a solution. Any insight?

Simon Wittber said...

This code is already C#, no need to convert it. UnityScript and C# can look quite similar at times!

Is your Unity project using .NET 2 or greater?

Dark Acre Jack said...

Oh, isn't the use of var a .js thing? Confusion...

Yes, I'm on pro with 2.0 in the settings. I'll try a straight copy and paste then...

I get the same CS0117 as before, and now a 1502 and 1053 due to a conversion error. Hm.

Simon Wittber said...

The var keyword is something we can now use, as Unity now has an up to date .NET implementation. It is used with local variable to implicitly type them, avoiding the need to declare their types.

These are strange errors. I'll see if I can replicate them...

Tylo said...

I believe Unity supports .NET 3.5. Not entirely up to date, but enough for using the keyword var, yes.

Tylo said...

Is there a particular reason you chose to use the var feature so many times in this script?

Simon Wittber said...

Less typing.

Simon Wittber said...

the Jack: Are you using Unity 3.X? I suspect this code will not compile under 2.6 or earlier.

Dark Acre Jack said...

Yes, the very latest update, Unity Pro, saved off in Monodevelop.

If it's working fine for you, as I suspect it is, it could be a wider-ranging issue with my dev environment.

Thanks for looking into it though!

Popular Posts