Skip to content

Instantly share code, notes, and snippets.

@HAliss
Created March 6, 2019 10:25
Show Gist options
  • Save HAliss/cc79aa4d3e0b616f1ce75122ad9c36fc to your computer and use it in GitHub Desktop.
Save HAliss/cc79aa4d3e0b616f1ce75122ad9c36fc to your computer and use it in GitHub Desktop.

Revisions

  1. HAliss created this gist Mar 6, 2019.
    153 changes: 153 additions & 0 deletions ShaderTextureCombiner.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,153 @@
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.Experimental.Rendering;

    public class ShaderTextureCombiner : EditorWindow {

    //Input textures
    private Texture2D[] textures = new Texture2D[4];
    //Invert bool for each texture
    private bool[] invert = new bool[4];
    //Output texture
    private Texture2D generatedTexture;
    //Dimensions of output texture
    private Vector2Int textureDimensions;
    //The value for the channels where a texture is not provided
    private float defaultValue = 1.0f;

    //Counter of generated textures used for naming
    private int totalTextures;
    private bool hasAlpha = false;

    [MenuItem("Tools/ShaderTextureCombiner")]
    private static void ShowWindow() {
    var window = GetWindow<ShaderTextureCombiner>();
    window.titleContent = new GUIContent("Texture Combiner");
    window.Show();
    }

    private void OnGUI() {


    //Displaying the texture fields
    textures[0] = (Texture2D) EditorGUILayout.ObjectField("Texture 1 (R)", textures[0], typeof(Texture2D), false);
    invert[0] = GUILayout.Toggle(invert[0], "Invert", "Button");
    textures[1] = (Texture2D) EditorGUILayout.ObjectField("Texture 2 (G)", textures[1], typeof(Texture2D), false);
    invert[1] = GUILayout.Toggle(invert[1], "Invert", "Button");
    textures[2] = (Texture2D) EditorGUILayout.ObjectField("Texture 3 (B)", textures[2], typeof(Texture2D), false);
    invert[2] = GUILayout.Toggle(invert[2], "Invert", "Button");
    textures[3] = (Texture2D) EditorGUILayout.ObjectField("Texture 4 (A)", textures[3], typeof(Texture2D), false);
    invert[3] = GUILayout.Toggle(invert[3], "Invert", "Button");

    //Displaying the texture information
    textureDimensions = EditorGUILayout.Vector2IntField("Dimensions", textureDimensions);
    defaultValue = EditorGUILayout.Slider("Default value", defaultValue, 0.0f, 1.0f);

    GUILayout.BeginHorizontal();

    if (GUILayout.Button("Generate texture")) {
    GenerateTexture();
    }

    if (GUILayout.Button("Save texture")) {
    SaveGeneratedTexture();
    }

    GUILayout.EndHorizontal();

    //Showing preview of the generated texture and its alpha (if it has any)
    if (generatedTexture != null) {
    EditorGUILayout.LabelField("Generated texture preview");
    EditorGUI.DrawPreviewTexture(new Rect(50, 450, 100, 100), generatedTexture);
    if (hasAlpha) {
    EditorGUI.DrawTextureAlpha(new Rect(200, 450, 100, 100), generatedTexture);
    }
    }

    }

    private void GenerateTexture() {
    generatedTexture = null;
    if (AllTexturesAreEmpty()) {
    Debug.LogWarning("No input textures given, not generating a texture!");
    return;
    }
    hasAlpha = (textures[3] != null);
    RenderTexture rt = new RenderTexture(textureDimensions.x, textureDimensions.y, 0, GraphicsFormat.R8G8B8A8_SRGB);
    RenderTexture.active = rt;

    //Creating a material based on the custom shader
    Material mat = new Material(Shader.Find("Hidden/TextureCombinerShader"));
    SetMaterialProperties(mat);

    //Rendering on the render texture using the custom material
    Graphics.Blit(null, rt, mat);

    generatedTexture = new Texture2D(textureDimensions.x, textureDimensions.y, hasAlpha ? TextureFormat.RGBA32 : TextureFormat.RGB24, false);
    generatedTexture.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
    generatedTexture.Apply();
    }

    private void SetMaterialProperties(Material mat) {
    mat.SetTexture("_TextureR", textures[0]);
    mat.SetTexture("_TextureG", textures[1]);
    mat.SetTexture("_TextureB", textures[2]);
    mat.SetTexture("_TextureA", textures[3]);
    mat.SetFloat("_DefaultValue", defaultValue);
    mat.SetVector("_TexturesGiven", GetTexturesGiven());
    mat.SetVector("_InvertedTextures", GetInvertedTextures());
    }

    private Vector4 GetInvertedTextures() {
    Vector4 invertedTextures = new Vector4();
    invertedTextures.x = (invert[0]) ? 1 : 0;
    invertedTextures.y = (invert[1]) ? 1 : 0;
    invertedTextures.z = (invert[2]) ? 1 : 0;
    invertedTextures.w = (invert[3]) ? 1 : 0;
    return invertedTextures;
    }

    private Vector4 GetTexturesGiven() {
    Vector4 texturesGiven = new Vector4();
    texturesGiven.x = (textures[0] == null) ? 0 : 1;
    texturesGiven.y = (textures[1] == null) ? 0 : 1;
    texturesGiven.z = (textures[2] == null) ? 0 : 1;
    texturesGiven.w = (textures[3] == null) ? 0 : 1;
    return texturesGiven;
    }

    private void SaveGeneratedTexture() {
    GenerateTexture();

    //If a directory called "Textures/Generated Textures" doesn't exist, create it
    if (!Directory.Exists(Application.dataPath + "Textures/Generated Textures")) {
    Directory.CreateDirectory(Application.dataPath + "/Textures/Generated Textures/");
    totalTextures = 0;
    } else {
    totalTextures = Directory.GetFiles(Application.dataPath + "/Textures/Generated Textures/").Length;
    }

    byte[] bytes = generatedTexture.EncodeToPNG();
    while (File.Exists(Application.dataPath + "/Textures/Generated Textures/generated_texture_" + totalTextures.ToString() + ".png")) {
    totalTextures++;
    }
    File.WriteAllBytes(Application.dataPath + "/Textures/Generated Textures/generated_texture_" + totalTextures.ToString() + ".png", bytes);
    AssetDatabase.Refresh();

    EditorUtility.FocusProjectWindow();
    Selection.activeObject = AssetDatabase.LoadMainAssetAtPath("Assets/Textures/Generated Textures/generated_texture_" + totalTextures.ToString() + ".png");
    }

    private bool AllTexturesAreEmpty() {
    for (int i = 0; i < 4; i++) {
    if (textures[i] != null) {
    return false;
    }
    }
    return true;
    }

    }
    66 changes: 66 additions & 0 deletions TextureCombinerShader.shader
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    Shader "Hidden/TextureCombinerShader"
    {
    SubShader
    {
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    // make fog work
    #pragma multi_compile_fog

    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    };

    sampler2D _TextureR;
    sampler2D _TextureG;
    sampler2D _TextureB;
    sampler2D _TextureA;
    half4 _TexturesGiven;
    half4 _InvertedTextures;
    float _DefaultValue;

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = v.uv;
    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    // sample the textures
    fixed4 colR = tex2D(_TextureR, i.uv);
    fixed4 colG = tex2D(_TextureG, i.uv);
    fixed4 colB = tex2D(_TextureB, i.uv);
    fixed4 colA = tex2D(_TextureA, i.uv);

    fixed R = abs(_InvertedTextures.x - colR.r * colR.a);
    fixed G = abs(_InvertedTextures.y - colG.r * colG.a);
    fixed B = abs(_InvertedTextures.z - colB.r * colB.a);
    fixed A = abs(_InvertedTextures.w - colA.r * colA.a);

    fixed4 texCol = fixed4(R,G,B,A);
    fixed4 col = lerp(texCol, _DefaultValue , (1 - _TexturesGiven));
    return col;
    }
    ENDCG
    }
    }
    }