Search Unity

Question Need an easy way of adding texture2D to the texture2DArray in my multi material terrain shader

Discussion in 'Shaders' started by FluxAlchemist, Jun 4, 2021.

  1. FluxAlchemist

    FluxAlchemist

    Joined:
    Feb 16, 2021
    Posts:
    1
    I am trying to create a terrain shader for a voxel terrain which needs a large amount of textures for different possible materials (they get applied based on some vertex colors indicating an material ID and triplanar mapping) for this reason my shader has several texture2DArrays, one for diffuse, one for normals, etc. and it needs to be easy to add an additional material to this shader (so extend all the texture arrays by one and fill in the new spaces with the maps for the newly added material). Through a CustomEditor script for my shader this does currently work however I cannot find a way to save the variables in the custom editor script as I do not have a target object to store them on meaning any settings I apply will immediately be lost as soon as the material leaves the inspector. And while the texture arrays will stay on the material for a while, any action like starting play mode or trying to duplicate the material will reset them to nothing.

    Showing the problems:



    I simply want a to indicate how many different materials my should support and than be able to add all the maps for those materials in an easy user-friendly way while saving the changes being made.

    Below I have included the code for the custom shader GUI code with the shader code itself being less important as it is working correctly and has support for the texture arrays being put into it.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System;
    6.  
    7. public class StandardTriplanarInspector : ShaderGUI {
    8.  
    9.  
    10.     public int MaterialNum = 1;
    11.     public int TexDimensions = 1024;
    12.     public bool showTexArrays = false;
    13.     public LinkedList<MaterialColection> matList = new LinkedList<MaterialColection>();
    14.  
    15.     private TextureFormat dFormat = TextureFormat.RGB24;
    16.     private TextureFormat hFormat = TextureFormat.Alpha8;
    17.     private TextureFormat mFormat = TextureFormat.Alpha8;
    18.     private TextureFormat nFormat = TextureFormat.RGBA32;
    19.     private TextureFormat rFormat = TextureFormat.Alpha8;
    20.  
    21.     private Material targetMat;
    22.  
    23.     private MaterialProperty diffuseArray = null;
    24.     private MaterialProperty normalArray = null;
    25.     private MaterialProperty roughArray = null;
    26.     private MaterialProperty metallicArray = null;
    27.     private MaterialProperty heightArray = null;
    28.     private MaterialProperty ArrayLength = null;
    29.  
    30.     [System.Serializable]
    31.     public class MaterialColection {
    32.         public string name;
    33.         public Vector2 scroll;
    34.         public Texture2D basecolor;
    35.         public Texture2D normal;
    36.         public Texture2D metallic;
    37.         public Texture2D roughness;
    38.         public Texture2D height;
    39.  
    40.         public MaterialColection(string name) {
    41.             this.name = name;
    42.             scroll = new Vector2(0f, 0f);
    43.             basecolor = null;
    44.             normal = null;
    45.             metallic = null;
    46.             roughness = null;
    47.             height = null;
    48.         }
    49.     }
    50.  
    51.     public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader) {
    52.         base.AssignNewShaderToMaterial(material, oldShader, newShader);
    53.     }
    54.  
    55.     public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) {
    56.         //initialize and find the correct material properties (stop if problems)
    57.         if(!Init(materialEditor, properties)) {
    58.             return;
    59.         }
    60.  
    61.         //Display the settings
    62.         GUILayout.Space(20);
    63.         GUILayout.Label("Global settings");
    64.         EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
    65.         GUILayout.BeginHorizontal();
    66.         GUILayout.Label("Target Material: ", GUILayout.ExpandWidth(false));
    67.         GUILayout.EndHorizontal();
    68.         TexDimensions = EditorGUILayout.IntField("Dimensions of texture (W&H)", TexDimensions);
    69.         MaterialNum = EditorGUILayout.IntSlider("Number of materials", MaterialNum, 0, 128);
    70.  
    71.         //ensure the list of materials has exactly MaterialNum entries
    72.         while (MaterialNum > matList.Count) {
    73.             matList.AddLast(new MaterialColection("mat-" + (matList.Count)));
    74.         }
    75.  
    76.         while (MaterialNum < matList.Count) {
    77.             matList.RemoveLast();
    78.         }
    79.  
    80.  
    81.         showTexArrays = EditorGUILayout.Foldout(showTexArrays, "textures");
    82.  
    83.         //if foldout is enable show the area for adding in textures
    84.         if (showTexArrays) {
    85.             LinkedListNode<MaterialColection> node = matList.First;
    86.             for (int i = 0; i < MaterialNum; ++i) {
    87.                 MaterialField(node.Value);
    88.                 node = node.Next;
    89.             }
    90.         }
    91.  
    92.         //if the button gets pressed actually load the textures into texture arrays and insert them into the material
    93.         if (GUILayout.Button("Upload changes to target material")) {
    94.             loadTexArr();
    95.             materialEditor.serializedObject.ApplyModifiedProperties();
    96.             materialEditor.serializedObject.Update();
    97.             materialEditor.PropertiesChanged();
    98.         }
    99.  
    100.         //attempt at saving changes to object
    101.         Undo.RecordObject(targetMat, "changed");
    102.  
    103.         //draw the standard GUI
    104.         base.OnGUI(materialEditor, properties);
    105.     }
    106.  
    107.     private bool Init(MaterialEditor materialEditor, MaterialProperty[] properties) {
    108.         targetMat = materialEditor.target as Material;
    109.  
    110.         int n = 0;
    111.         foreach (MaterialProperty p in properties) {
    112.             if (p.name == "_TexArr") {
    113.                 diffuseArray = p;
    114.                 n++;
    115.             } else if (p.name == "_TexArr_n") {
    116.                 normalArray = p;
    117.                 n++;
    118.             } else if (p.name == "_TexArr_r") {
    119.                 roughArray = p;
    120.                 n++;
    121.             } else if (p.name == "_TexArr_m") {
    122.                 metallicArray = p;
    123.                 n++;
    124.             } else if (p.name == "_TexArr_h") {
    125.                 heightArray = p;
    126.                 n++;
    127.             } else if (p.name == "_ArrLength") {
    128.                 ArrayLength = p;
    129.                 n++;
    130.             }
    131.         }
    132.  
    133.         if (n != 6) {
    134.             Debug.LogError("The required texture arrays could not be found on the shader");
    135.             base.OnGUI(materialEditor, properties);
    136.             return false;
    137.         }
    138.         return true;
    139.     }
    140.  
    141.     //Creates texture2Darrays from normal textures and inserts them into the shader
    142.     public void loadTexArr() {
    143.         int n = matList.Count;
    144.         LinkedListNode<MaterialColection> node = matList.First;
    145.  
    146.         Texture2DArray diffuse = new Texture2DArray(TexDimensions, TexDimensions, n, dFormat, true);
    147.         Texture2DArray height = new Texture2DArray(TexDimensions, TexDimensions, n, hFormat, true);
    148.         Texture2DArray metallic = new Texture2DArray(TexDimensions, TexDimensions, n, mFormat, true);
    149.         Texture2DArray normal = new Texture2DArray(TexDimensions, TexDimensions, n, nFormat, true);
    150.         Texture2DArray roughness = new Texture2DArray(TexDimensions, TexDimensions, n, rFormat, true);
    151.  
    152.         for (int i = 0; i < n; i++) {
    153.             diffuse.SetPixels(node.Value.basecolor.GetPixels(0), i, 0);
    154.             height.SetPixels(node.Value.height.GetPixels(0), i, 0);
    155.             metallic.SetPixels(node.Value.metallic.GetPixels(0), i, 0);
    156.             normal.SetPixels(node.Value.normal.GetPixels(0), i, 0);
    157.             roughness.SetPixels(node.Value.roughness.GetPixels(0), i, 0);
    158.  
    159.             node = node.Next;
    160.         }
    161.  
    162.         diffuse.Apply(true);
    163.         height.Apply(true);
    164.         metallic.Apply(true);
    165.         normal.Apply(true);
    166.         roughness.Apply(true);
    167.  
    168.         diffuseArray.textureValue = diffuse;
    169.         heightArray.textureValue = height;
    170.         metallicArray.textureValue = metallic;
    171.         normalArray.textureValue = normal;
    172.         roughArray.textureValue = roughness;
    173.  
    174.         Debug.Log("Updated material texture arrays");
    175.     }
    176.  
    177.     private void MaterialField(MaterialColection mat) {
    178.         GUILayout.BeginHorizontal();
    179.         GUILayout.Label("Material name: ", GUILayout.ExpandWidth(false));
    180.         mat.name = EditorGUILayout.TextField(mat.name);
    181.         GUILayout.EndHorizontal();
    182.         mat.scroll = GUILayout.BeginScrollView(mat.scroll, GUI.skin.horizontalScrollbar, GUIStyle.none, GUILayout.ExpandHeight(false), GUILayout.MinHeight(115));
    183.         GUILayout.BeginHorizontal(GUILayout.ExpandHeight(false));
    184.         GUILayout.FlexibleSpace();
    185.         mat.basecolor = TextureField("basecolor", mat.basecolor);
    186.         mat.height = TextureField("height", mat.height);
    187.         mat.metallic = TextureField("metallic", mat.metallic);
    188.         mat.normal = TextureField("normal", mat.normal);
    189.         mat.roughness = TextureField("roughness", mat.roughness);
    190.         GUILayout.FlexibleSpace();
    191.         GUILayout.EndHorizontal();
    192.         GUILayout.EndScrollView();
    193.         EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
    194.  
    195.         if (mat.basecolor != null && mat.basecolor.format != dFormat) {
    196.             Debug.LogError("Basecolor textures can only take textures of " + dFormat);
    197.             mat.basecolor = null;
    198.         } else if (mat.height != null && mat.height.format != hFormat) {
    199.             Debug.LogError("Height textures can only take textures of " + hFormat);
    200.             mat.height = null;
    201.         } else if (mat.roughness != null && mat.roughness.format != rFormat) {
    202.             Debug.LogError("Roughness textures can only take textures of " + rFormat);
    203.             mat.roughness = null;
    204.         } else if (mat.metallic != null && mat.metallic.format != mFormat) {
    205.             Debug.LogError("Metallic textures can only take textures of " + mFormat);
    206.             mat.metallic = null;
    207.         } else if (mat.normal != null && mat.normal.format != nFormat) {
    208.             Debug.LogError("Normal textures can only take textures of " + nFormat + " was " + mat.normal.format);
    209.             mat.normal = null;
    210.         }
    211.  
    212.         if (mat.basecolor != null && (mat.basecolor.height != TexDimensions || mat.basecolor.width != TexDimensions)) {
    213.             mat.basecolor = null;
    214.             Debug.LogError("Basecolor texture was not of correct dimensions ");
    215.         } else if (mat.height != null && (mat.height.height != TexDimensions || mat.height.width != TexDimensions)) {
    216.             mat.height = null;
    217.             Debug.LogError("Height texture was not of correct dimensions ");
    218.         } else if (mat.roughness != null && (mat.roughness.height != TexDimensions || mat.roughness.width != TexDimensions)) {
    219.             mat.roughness = null;
    220.             Debug.LogError("Roughness texture was not of correct dimensions ");
    221.         } else if (mat.metallic != null && (mat.metallic.height != TexDimensions || mat.metallic.width != TexDimensions)) {
    222.             mat.metallic = null;
    223.             Debug.LogError("Metallic texture was not of correct dimensions ");
    224.         } else if (mat.normal != null && (mat.normal.height != TexDimensions || mat.normal.width != TexDimensions)) {
    225.             mat.normal = null;
    226.             Debug.LogError("Normal texture was not of correct dimensions ");
    227.         }
    228.     }
    229.     private Texture2D TextureField(string name, Texture2D texture) {
    230.         GUILayout.BeginVertical();
    231.         var style = new GUIStyle(GUI.skin.label);
    232.         style.alignment = TextAnchor.UpperCenter;
    233.         style.fixedWidth = 70;
    234.         GUILayout.Label(name, style);
    235.         var result = (Texture2D)EditorGUILayout.ObjectField(texture, typeof(Texture2D), false, GUILayout.Width(70), GUILayout.Height(70));
    236.         GUILayout.EndVertical();
    237.         return result;
    238.     }
    239. }