Created
February 12, 2013 10:40
-
-
Save Farfarer/4761486 to your computer and use it in GitHub Desktop.
Combines a base and a detail normal map to a new normal map texture, for Unity3D.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEditor; | |
using UnityEngine; | |
using System.IO; | |
// PLACE IN EDITOR FOLDER | |
class CombineNormalMapsWizard : ScriptableWizard { | |
public Texture2D baseNormal = null; | |
public Texture2D detailNormal = null; | |
public float detailStrength = 1.0f; | |
[MenuItem ("Tools/Combine Normal Maps")] | |
static void CreateWizard () { | |
ScriptableWizard.DisplayWizard<CombineNormalMapsWizard>("Combine Normal Maps", "Combine"); | |
} | |
void OnWizardCreate () { | |
bool goodToGo = true; | |
if ( ( baseNormal == null ) || ( detailNormal == null ) ) | |
{ | |
Debug.LogWarning ( "You must specify a base and a detail normal map."); | |
goodToGo = false; | |
} | |
else if ( ( baseNormal.height != detailNormal.height ) || ( baseNormal.width != detailNormal.width ) ) | |
{ | |
Debug.LogWarning ( "Base and detail textures must be the same dimensions."); | |
goodToGo = false; | |
} | |
if (goodToGo) { | |
string path; | |
TextureImporter textureImporter; | |
bool baseNormalReadable; | |
bool baseNormalNormalmap; | |
TextureImporterFormat baseNormalFormat; | |
bool detailNormalReadable; | |
bool detailNormalNormalmap; | |
TextureImporterFormat detailNormalFormat; | |
// Set up textures as we want them. | |
path = AssetDatabase.GetAssetPath(baseNormal); | |
textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; | |
baseNormalReadable = textureImporter.isReadable; | |
baseNormalNormalmap = textureImporter.normalmap; | |
baseNormalFormat = textureImporter.textureFormat; | |
textureImporter.isReadable = true; | |
textureImporter.normalmap = false; | |
textureImporter.textureFormat = TextureImporterFormat.RGBA32; | |
AssetDatabase.ImportAsset(path); | |
path = AssetDatabase.GetAssetPath(detailNormal); | |
textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; | |
detailNormalReadable = textureImporter.isReadable; | |
detailNormalNormalmap = textureImporter.normalmap; | |
detailNormalFormat = textureImporter.textureFormat; | |
textureImporter.isReadable = true; | |
textureImporter.normalmap = false; | |
textureImporter.textureFormat = TextureImporterFormat.RGBA32; | |
AssetDatabase.ImportAsset(path); | |
Color[] detailNormalPixels; | |
Color[] combinedNormalPixels; | |
int width = baseNormal.width; | |
int height = baseNormal.height; | |
combinedNormalPixels = baseNormal.GetPixels (0); | |
detailNormalPixels = detailNormal.GetPixels (0); | |
int numPixels = width * height; | |
// Do the conversion. | |
for (int i = 0; i < numPixels; ++i) | |
{ | |
// Method from http://blog.selfshadow.com/publications/blending-in-detail/ used. | |
// I find it gives the nicest results. | |
Vector3 t = new Vector3 (combinedNormalPixels[i].r * 2.0f - 1.0f, combinedNormalPixels[i].g * 2.0f - 1.0f, combinedNormalPixels[i].b * 2.0f); | |
Vector3 u = new Vector3 (detailNormalPixels[i].r * -2.0f + 1.0f, detailNormalPixels[i].g * -2.0f + 1.0f, detailNormalPixels[i].b * 2.0f - 1); | |
if ( detailStrength != 1.0f ) | |
{ | |
u = new Vector3 ( u.x * detailStrength, u.y * detailStrength, u.z ); | |
u.Normalize(); | |
} | |
Vector3 r = t * Vector3.Dot(t, u) - u * t.z; | |
r.Normalize (); | |
Color returnColor = new Color (r.x * 0.5f + 0.5f, r.y * 0.5f + 0.5f, r.z * 0.5f + 0.5f, combinedNormalPixels[i].a); | |
combinedNormalPixels[i] = returnColor; | |
} | |
Texture2D normal = new Texture2D(width, height, TextureFormat.ARGB32, false); | |
normal.SetPixels (combinedNormalPixels); | |
normal.Apply(); | |
byte[] bytes = normal.EncodeToPNG(); | |
DestroyImmediate(normal); | |
string assetPath = AssetDatabase.GetAssetPath(baseNormal); | |
string assetDir = Path.GetDirectoryName(assetPath); | |
string assetName = Path.GetFileNameWithoutExtension(assetPath) + "_combined.png"; | |
string newAsset = Path.Combine(assetDir, assetName); | |
File.WriteAllBytes(newAsset, bytes); | |
// Revert textures back to the way they were. | |
path = AssetDatabase.GetAssetPath(baseNormal); | |
textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; | |
textureImporter.isReadable = baseNormalReadable; | |
textureImporter.normalmap = baseNormalNormalmap; | |
textureImporter.textureFormat = baseNormalFormat; | |
AssetDatabase.ImportAsset(path); | |
path = AssetDatabase.GetAssetPath(detailNormal); | |
textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; | |
textureImporter.isReadable = detailNormalReadable; | |
textureImporter.normalmap = detailNormalNormalmap; | |
textureImporter.textureFormat = detailNormalFormat; | |
AssetDatabase.ImportAsset(path); | |
// Import the new texture, set as a normal map. | |
AssetDatabase.ImportAsset(newAsset); | |
textureImporter = AssetImporter.GetAtPath(newAsset) as TextureImporter; | |
textureImporter.textureType = TextureImporterType.Bump; | |
textureImporter.normalmap = true; | |
textureImporter.convertToNormalmap = false; | |
AssetDatabase.ImportAsset(newAsset); | |
Debug.Log ("Normal maps combined to " + newAsset); | |
} | |
} | |
void OnWizardUpdate () { | |
helpString = "Press Combine to combine normal maps.\nSaved to folder with base normal map."; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment