Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

[FREE]MicroSplat, a modular terrain shading system for Unity Terrains

Discussion in 'Assets and Asset Store' started by jbooth, Aug 9, 2017.

  1. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,015
    Ohhhhh....got it. So now I can activate all the MicroSplat features I need, and still be at only 12 samplers! Woohoo! Wind & Glitter, here I come!

    EDIT: I don't suppose you could combine the two VS features into a single sampler?
     
    camta005 likes this.
  2. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Not without potential negative ramifications - the Anti-Tile one was the best target for something like this, because I could do it without invalidating the other workflows and gain back a bunch of samplers at once. The next most likely target would be to stop storing the per-texture properties in a texture to save one more sampler, but I'd need to make sure this didn't slow down the overall shader or sync functions. This is something I want to look into when I get some time..
     
    StevenPicard and gecko like this.
  3. ArkadiuszR

    ArkadiuszR

    Joined:
    Jan 21, 2016
    Posts:
    20
    Hello,
    I'm using unity 2017.3.0f
    After import MegaSplat 1.6 i see errors (on picture)
    DX9 is not supported in this version unity - maybe it is reason.
    ( UnityTerrainTessellation scene )
     

    Attached Files:

  4. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Yeah, Unity broke their shadow macro's in 2017.3. Update to the latest version in the asset store as I added a workaround until they fix it.
     
    mwituni likes this.
  5. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
  6. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    submitting a new version of MicroSplat to the asset store now:

    MicroSplat 1.71
    - Added support for Emissive and Metal array’s for texture packing/shaders
    - Add code to enforce that terrain blending shader is used by bendable objects
    - Add extra line feed at end of shader to make sure shader ends in a line feed
    - Optimization to app data structure

    Not a sync locked release; only Core, Texture Clusters and Terrain Blending are being updated.
     
    julianr and jbonastre like this.
  7. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,015
    I'm having an odd problem since getting 1.7 and switching to Anti-Tile Array: Several textures darken when the camera moves to some distance (100m maybe) away. However, this only happens with a few textures, not all of them. I've tried disabling all the Per-Texture settings, but that doesn't make any difference. The only thing that fixes it is disabling the Anti-Tile Array (and switching back to the original method for those features).

    I sure can't figure out why this is happening, and especially with just a few of my textures. It's not related to which textures have assigned vs. generated textures in the Config array. Any ideas?

    In these screenshots, you can see that the brown grass texture doesn't change brightness, but the rocky textures do.

    far.jpg closer.jpg
     

    Attached Files:

  8. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Could it be that your detail/distance textures are gamma and thus the 0.5 you expect to not darken/lighten is coming out as 0.3?

    If not, send me a scene and I'll have a look..
     
  9. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,015
    I had assigned your noise normal textures to those cliff rocks, and nothing to the Distance noise slots on the Anti-Tile Array. But now I've assigned your normal noise textures to distance noise -- and that solved it. So it seems the problem only occurs on textures which don't have anything assigned to Distance noise. Is that to be expected? And is there any reason not to assign textures to those slots? (I was thinking that would reduce samples, for improved performance, but I am not sure that's true.)
     
  10. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Assigning nothing should be a valid option if you are not going to use distance noise- as that can increase the compression quality of the normals slightly. It will only sample the distance texture if you turn that feature on in the anti-tile options - was that on when you were testing? If you're not providing distance textures, you should turn it off..
     
  11. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,015
    But what if I assign distance noise to some textures, but not others? Any memory/performance advantage to that? That's what seems to be causing this problem.
     
  12. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    No advantage other than the slightly better compression- they will all sample, or will all not sample. The default is to use a gray texture when not provided, but I'm betting this isn't set to linear and that's why you see the darkening. I'll take a look - you could make your own grey texture to get around it for now.
     
  13. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Yeah, that's the issue- the default texture I pack in there is gamma. Will be fixed in the next patch..
     
  14. gecko

    gecko

    Joined:
    Aug 10, 2006
    Posts:
    2,015
    ok, thanks, I'll just assign textures anyways.
     
  15. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    568
    Hi,

    Sorry if i missed the answer but seems i have the same issue and my blending is set to "best"
    Thanks in advance for your help!
    upload_2017-12-28_21-25-33.png
    upload_2017-12-28_21-43-6.png

    Sorry, i found out, i didn't try "load sampler" and no more artefacts. And you wrote it in front of my face!!:oops: sorry!
     
    Last edited: Dec 28, 2017
  16. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Yeah, I put a warning about it right above the per-texture UV controls. I could switch it automatically, but there's still some education/choices to be made, so there is no right answer, necessarily..
     
  17. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    568
    i bought your anti tile module to test the beast::)
    -regarding the use of "load sampler" textures look blury with this setting...
    -I use enviro and the terrain is all black when light goes down...

    upload_2017-12-30_0-13-25.png
    upload_2017-12-30_0-15-5.png
     
  18. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    You can use the gradient samplers instead, slower, but let’s the hardware do the mip map selection. Either is only necessary when using per texture UV scales.

    As for the lighting; Microsplat uses surface shaders, so it’s the standard Unity PBR lighting model by default. I do seem to remember this being talked about on the enviro thread as an enviro issue at some point?
     
  19. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    568
    Many thanks for your very fast support!
    -i don't use "gradient sampler" cause it keeps the artefacts lines on my previous post...
    -For the lighting, i will search on enviro thread, thanks!

    btw, i really like your wind effect!! what about the performance cost of this ? i suppose almost nothing compared with some particles effects!!!:):):):)
     
  20. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Interesting- I would have expected the gradient samplers to fix it (the issue only appears on some GPUs). In a previous version of the LOD samplers, I exposed a mip bias and fake aniso setting. I could re-add these, I suppose, but I really hate having to expose all this stuff in the first place..

    It's very cheap..
     
  21. eaque

    eaque

    Joined:
    Aug 20, 2014
    Posts:
    568
    Just for info if it can help i use gt 660 ti


    I supposed and the result is fantastic! really wanted to go thru the basics of microsplat to try that module! :)
     
  22. coverpage

    coverpage

    Joined:
    Mar 3, 2016
    Posts:
    385
    @jbooth Honestly, my opinion now is that microsplat terrain shader is the best terrain shader.

    Texture clusters is properly useful, 16 is not enough to create organic looking terrain. Place some grass on top, and together can really get very organic looking terrain.

    In the config file for texture packing, is it possible for us to label the textures. Like "mud" cluster "stone" cluster etc. Just a persistent text so that I remember what this texture/cluster is. I replace certain textures a lot because sometimes they just don't work, and it's hard to remember which one.

    As for the lava, puddle, stream module, which I think is one of the most value for money one for the tools we get. Painting the streams is like magic really, very pretty. However it's hard to use them because I can't blend them into an Aqueous ocean or RAM river. So the stream has to disappear under vegetation or cracks.

    So I have two request for that, is it possible to blend into an existing water solution. And is it possible to create depth underneath the stream, right now it's looks like thin layer of stream which has limited application.

    This is my latest wip using VS and microsplat.

    vegetation studio5.PNG

    vegetation studio4.PNG

     
    antoripa, eaque, jlocke and 2 others like this.
  23. blitzvb

    blitzvb

    Joined:
    Mar 20, 2015
    Posts:
    284
    hey @jbooth

    With the MicroSplat Global Texturing, do you think I could add Amplify Texture 2 by modifying Microsplat and give to that feature a very high resolution texture (8k,16k) virtualized ?

    The idea would be to have that high res texture as the base of the terrain texture with splats on top for details, along with all your other effects like snow, wind...

    here the documentation of what I would need to add to microsplat (Note AT2 do not support texture cluster) :

    http://wiki.amplify.pt/index.php?ti...ture_2/Manual#How_To_Convert_Your_Own_Shaders
     
    Last edited: Jan 1, 2018
  24. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Do you want a user-defined name for each texture, or each cluster? Or should the texture name of, say, the albedo texture be displayed there?


    The streams are drawn as part of the terrain itself, so the depth it does have is totally faked. What it does is adjust the height of the vertices (if using tessellation), compute a refraction basis, and then run the terrain part of the shader and draw the water over it - so it's not a separate pass or effect, but rather IS the terrain. This means that it's limited to smaller scale water effects, and cannot form into something like a full raging river or lake (I have something else for this coming soon). But the advantage is that it can integrate into the terrain in a nice way that most water solutions cannot, since it has full knowledge of the terrain shading in it's calculations.
     
  25. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Looking over that guide, doing the shader work is trivial, but it looks like they require you to use their custom editor for the shader, which would mean the MicroSplat interface wouldn't be able to be used.
     
  26. blitzvb

    blitzvb

    Joined:
    Mar 20, 2015
    Posts:
    284
    wow wow ... what you just said could changed my project a lot!

    Actually, you don't need to use Amplify Shader Editor to integrate AT2 into a shader. The screenshot attached show the diff in the shader, that need to be coded by hand into the shader.

    diff.png

    if we are on the same pages about this, here few questions:

    - In the Global texturing plugin, you do not use any texture array, you just pass the global picture as a texture?
    - Will I have the source of the plugin in order to make the change myself (unless you want to add that feature which would be even better)?
    - So if all of that is a go, I would be able to have a high res texture as a bottom layer of the terrain and add splats textures on top of it, on few areas?
    - effect like wind, glitter, streams, lava , snow should work without modification ?

    thanks in advance.

    Vincent.
     
  27. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Yes, but the "Custom Editor" line at the bottom would mean the MicroSplat shader editor wouldn't be drawn.. A given shader can only have one custom editor, so what would have to happen is that whatever they do in their custom editor would have to be done by the MicroSplat editor (or vice versa). As I don't have that asset, I have no idea what that custom editor does, or what would be involved in refactoring it such that the MicroSplat editor could possibly call it's functions.

    Yes, the global texturing textures are not packed into an array- it's just a regular old texture. All source is included with all of my assets- I don't use any DLLs, etc. Splats are blended with the global textures- there is no concept of top or bottom, just blend amount and how to blend the texture (overlay, cross fade, etc). You can set these based on distance, for instance, having 80/20 splat maps vs global when close, but fading to 20/80 splat maps vs global when far away. All of the docs are included with the core module (which is free), so I'd suggest reading them so you can see how the system works. Other effects would work without modification..
     
    blitzvb likes this.
  28. blitzvb

    blitzvb

    Joined:
    Mar 20, 2015
    Posts:
    284
    My bad. Still a noob in shader.

    Anyway, I don't think they do anything interesting in the custom inspector. It's just the standard inspector of the standard shader to give albedo, normal ... I guess that this line could be removed. (I am going to check with Amplify)

    here a screenshot:
    Capture.PNG
     
  29. wmpunk

    wmpunk

    Joined:
    Sep 5, 2015
    Posts:
    71
    I would like to make a quick announcement. Under Jason's consent I have been working on my own MicroSplat module "Advanced Details" that is currently pending release. If any one is interested or has questions please post them in the thread here to avoid any misplaced future support request.
     
  30. coverpage

    coverpage

    Joined:
    Mar 3, 2016
    Posts:
    385
    User friendly name for each cluster would be useful. 16 names max altogether is what I mean. Thanks.

    And I understand about the stream now, its still properly useful. Will definitely be interested in your water body solution when it's released.
     
  31. acaton

    acaton

    Joined:
    May 27, 2013
    Posts:
    25
    Hi Jason,
    Thanks again for this amazing shader! I'm using it and it's working great, but I do have a couple of questions I'm hoping you can help with:
    1) Is it possible to simply blend in another texture without using it's heightmap sprite (bump map)? I'd like to be able to add blood / ui textures on top of existing terrain, but it currently only shows which ever texture is on top, tessellating it according to the terrain's bump map. I have a feeling this is doable, just not sure how to get the effect I'm looking for. Specifically, I'd like for the dirt/grass to keep the same height in tessellation, just get another texture blended in to show blood and/or a ui grid for player to select an area of the map.
    2) When 2 terrain pieces bump up against each other, the tessellation effect creates a crack between them. I have pseudo-fixed this by making the seam have the same exact texture on both sides (I average the pixel on the left side of the seam with the one on the right side and set them both the same), but this is sub-optimal (the art changes so I can't get a hard line between the 2 textures), and I have to do the blend which slows things down and complicates my terrain system. I can live with this, if needed, but was hoping you might have an amazing solution so I can have better looking art and simpler code.
    If you have any questions or ideas, or suggestions of things I might try, please don't hesitate to reach out. Take care and Happy New Years!!! :)
     
  32. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    @wmpunk just announced a new module for something like this- it basically allows you to paint another layer onto the terrain and use height/angle to control where the texture is blended in to the first. Keep in mind that it's not a decal system, but rather another paintable layer, so it might not fit your exact use case if you are expecting to position/rotate textures and place them.

    If you switch the UV mode to world space I would expect this to be fixed, as each side of the terrain will have the same UV coordinate.
     
    wmpunk likes this.
  33. acaton

    acaton

    Joined:
    May 27, 2013
    Posts:
    25
    Thanks for the quick reply!
    Do you happen to have a link for the module you referred to in #1? How can I get my hands on it and/or know when it's available?
    For #2, do you think world uv would work when each side of terrain had different splatmaps (i.e. grass on right edge of left chunk and dirt [with a different bumpmap] on the left edge of the terrain on the right?)
    They do have neighbors set up through Unity, and I'm happy to give it a shot, but it seems like, since they have different terrains, their heights wouldn't line up. I create materials for each at runtime (for '_Control0', '_Control1', etc), and they look great up against each other, as long as the terrain on each side of the seam matches up, otherwise the tessellation pushes the rocky terrain up more than the sand (for example), resulting in holes in the 'seam' between the 2 neighboring terrains.
     
  34. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    The announce thread is here. Unity has been taking a long time with asset approvals, so I expect it won't come out for 3 weeks or so..

    If they are different textures, then they wouldn't have the same height values, and therefor wouldn't have the same displacement and would show a crack - they would also have a texture seem in them if you were not using tessellation. A shader cannot easily know about the terrain next to it (you'd have to do some funky thing to pack the edge textures so that it knew about the edge of the 8 possible terrains it would intersect with, then figure out if it's an edge and sample all that data to do the blend - not trivial, and better solved by ensuring that the edges have the same terrain terrain weights on them, which also fixes texture seems as well).
     
  35. acaton

    acaton

    Joined:
    May 27, 2013
    Posts:
    25
    Jason,
    Thanks for the link--I'll watch for the update.
    For #2, I think you're right, that's why I already added the code to make sure each edge had the same exact textures, which DOES fix it. I was just hoping there was a simple fix, but, as you said, I couldn't imagine one that didn't require a lot of work.
    Again, I really appreciate all your help. I had thought tessellation would be too slow to work in my game--it was a great surprise to find out I was wrong! :)
     
  36. PeterB

    PeterB

    Joined:
    Nov 3, 2010
    Posts:
    337
    I get this compilation error in 1.71 running under 2017.3.0p1, Mac:

    "Assets/MicroSplat/Core/Scripts/Editor/TextureArrayConfigEditor.cs(1006,52): error CS0103: The name `NormalizeAlphaMask' does not exist in the current context"

    Deleting MicroSplat before updating makes no difference. There is a definition for NormalizeAlphaMask on line 642, conditionalised on line 609: "#if !UNITY_2017_3_OR_NEWER".

    Please advise.
     
    Last edited: Jan 2, 2018
  37. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Ah, crap, I'll submit a patch for that immediately. You can move the function out of the define area and I'll do the same, sorry about that....
     
    PeterB likes this.
  38. PeterB

    PeterB

    Joined:
    Nov 3, 2010
    Posts:
    337
    Thanks, it worked like a charm. But now the plugins no longer load. Is this due to the difference in version numbers?
     
  39. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    Ok, patch is submitted- Unity will likely get it out tomorrow, but if anyone is not code savy, running 2017.3.0+ and needs the fix, I can send you the change..
     
  40. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    The version number didn't change in this update- so it should work fine with any 1.7 version. Did you update from a version below 1.7? If so, you need to update all the modules as well..

    Basically, the major point releases (1.6, 1.7) are version locked, where as the sub-point releases (1.71) are not.
     
    PeterB likes this.
  41. PeterB

    PeterB

    Joined:
    Nov 3, 2010
    Posts:
    337
    No, I updated from 1.7. Simply reimporting the modules fixed things; even the settings were preserved, so no work was lost. Thanks!
     
    jbooth likes this.
  42. Nazowa

    Nazowa

    Joined:
    Oct 30, 2017
    Posts:
    15
    Upgraded to latest version and here are the errors:

    Assets/MicroSplat/Core/Scripts/Editor/TextureArrayConfigEditor.cs(1006,52): error CS0103: The name `NormalizeAlphaMask' does not exist in the current context

    Unable to parse file Assets/MicroSplat/Core/Examples/Scene/MicroSplatData/MicroSplatConfig_diff_tarray.asset: [Invalid leading UTF-8 octet] at line 4

    Unable to parse file Assets/MicroSplat/Core/Examples/Scene/MicroSplatData/MicroSplatConfig_normSAO_tarray.asset: [Invalid leading UTF-8 octet] at line 4

    Looking forward to the patch. An item of interest it killed the Aquas as well by disabling its script.
     
    Last edited: Jan 3, 2018
  43. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    You can move that function out of the #ifdef in the code, or if you're not comfortable with that, you can replace the code in TextureArrayConfigEditor.cs with this version:

    Code (CSharp):
    1.  
    2. //////////////////////////////////////////////////////
    3. // MicroSplat - 256 texture splat mapping
    4. // Copyright (c) Jason Booth
    5. //////////////////////////////////////////////////////
    6.  
    7. using UnityEngine;
    8. using System.Collections;
    9. using UnityEditor;
    10. using System.Collections.Generic;
    11.  
    12. namespace JBooth.MicroSplat
    13. {
    14.    [CustomEditor(typeof(TextureArrayConfig))]
    15.    public class TextureArrayConfigEditor : Editor
    16.    {
    17.  
    18.       void DrawHeader(TextureArrayConfig cfg)
    19.       {
    20.          if (cfg.textureMode != TextureArrayConfig.TextureMode.Basic)
    21.          {
    22.             EditorGUILayout.BeginHorizontal();
    23.             EditorGUILayout.BeginVertical();
    24.             EditorGUILayout.LabelField("", GUILayout.Width(30));
    25.             EditorGUILayout.LabelField("Channel", GUILayout.Width(64));
    26.             EditorGUILayout.EndVertical();
    27.             EditorGUILayout.LabelField(new GUIContent(""), GUILayout.Width(20));
    28.             EditorGUILayout.LabelField(new GUIContent(""), GUILayout.Width(64));
    29.             EditorGUILayout.BeginVertical();
    30.             EditorGUILayout.LabelField(new GUIContent("Height"), GUILayout.Width(64));
    31.             cfg.allTextureChannelHeight = (TextureArrayConfig.AllTextureChannel)EditorGUILayout.EnumPopup(cfg.allTextureChannelHeight, GUILayout.Width(64));
    32.             EditorGUILayout.EndVertical();
    33.  
    34.             EditorGUILayout.BeginVertical();
    35.             EditorGUILayout.LabelField(new GUIContent("Smoothness"), GUILayout.Width(64));
    36.             cfg.allTextureChannelSmoothness = (TextureArrayConfig.AllTextureChannel)EditorGUILayout.EnumPopup(cfg.allTextureChannelSmoothness, GUILayout.Width(64));
    37.             EditorGUILayout.EndVertical();
    38.  
    39.             EditorGUILayout.BeginVertical();
    40.             if (cfg.IsAdvancedDetail())
    41.             {
    42.                EditorGUILayout.LabelField(new GUIContent("Alpha"), GUILayout.Width(64));
    43.                cfg.allTextureChannelAlpha = (TextureArrayConfig.AllTextureChannel)EditorGUILayout.EnumPopup(cfg.allTextureChannelAlpha, GUILayout.Width(64));
    44.             }
    45.             else
    46.             {        
    47.                EditorGUILayout.LabelField(new GUIContent("AO"), GUILayout.Width(64));
    48.                cfg.allTextureChannelAO = (TextureArrayConfig.AllTextureChannel)EditorGUILayout.EnumPopup(cfg.allTextureChannelAO, GUILayout.Width(64));
    49.             }
    50.             EditorGUILayout.EndVertical();
    51.  
    52.             EditorGUILayout.EndHorizontal();
    53.             GUILayout.Box(Texture2D.blackTexture, GUILayout.Height(3), GUILayout.ExpandWidth(true));
    54.          }
    55.       }
    56.  
    57.       void DrawAntiTileEntry(TextureArrayConfig cfg, TextureArrayConfig.TextureEntry e, int i)
    58.       {
    59.          EditorGUILayout.BeginHorizontal();
    60.          EditorGUILayout.Space();EditorGUILayout.Space();
    61.          EditorGUILayout.BeginVertical();
    62.  
    63.          EditorGUILayout.LabelField(new GUIContent("Noise Normal"), GUILayout.Width(92));
    64.          e.noiseNormal = (Texture2D)EditorGUILayout.ObjectField(e.noiseNormal, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    65.          EditorGUILayout.EndVertical();
    66.  
    67.          EditorGUILayout.BeginVertical();
    68.          EditorGUILayout.LabelField(new GUIContent("Detail"), GUILayout.Width(92));
    69.          e.detailNoise = (Texture2D)EditorGUILayout.ObjectField(e.detailNoise, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    70.          e.detailChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.detailChannel, GUILayout.Width(64));
    71.          EditorGUILayout.EndVertical();
    72.  
    73.          EditorGUILayout.BeginVertical();
    74.          EditorGUILayout.LabelField(new GUIContent("Distance"), GUILayout.Width(92));
    75.          e.distanceNoise = (Texture2D)EditorGUILayout.ObjectField(e.distanceNoise, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    76.          e.distanceChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.distanceChannel, GUILayout.Width(64));
    77.          EditorGUILayout.EndVertical();
    78.  
    79.  
    80.          EditorGUILayout.EndHorizontal();
    81.  
    82.          if (e.noiseNormal == null)
    83.          {
    84.             int index = (int)Mathf.Repeat(i, 3);
    85.             e.noiseNormal = MicroSplatUtilities.GetAutoTexture("microsplat_def_detail_normal_0" + (index+1).ToString());
    86.          }
    87.  
    88.       }
    89.  
    90.       bool DrawTextureEntry(TextureArrayConfig cfg, TextureArrayConfig.TextureEntry e, int i, bool controls = true)
    91.       {
    92.          bool ret = false;
    93.          if (controls)
    94.          {
    95.             EditorGUILayout.BeginHorizontal();
    96.  
    97.             if (e.HasTextures())
    98.             {
    99.                EditorGUILayout.LabelField(i.ToString(), GUILayout.Width(30));
    100.                EditorGUILayout.LabelField(e.diffuse != null ? e.diffuse.name : "empty");
    101.                ret = GUILayout.Button("Clear Entry");
    102.             }
    103.             else
    104.             {
    105.                EditorGUILayout.LabelField(i.ToString(), GUILayout.Width(30));
    106.                EditorGUILayout.HelpBox("Removing an entry completely can cause texture choices to change on existing terrains. You can leave it blank to preserve the texture order and MicroSplat will put a dummy texture into the array.", MessageType.Warning);
    107.                ret = (GUILayout.Button("Delete Entry"));
    108.             }
    109.             EditorGUILayout.EndHorizontal();
    110.          }
    111.  
    112.          EditorGUILayout.BeginHorizontal();
    113.  
    114.          if (cfg.textureMode == TextureArrayConfig.TextureMode.PBR)
    115.          {
    116.             #if !UNITY_2017_3_OR_NEWER
    117.             EditorGUILayout.BeginVertical();
    118.             if (controls)
    119.             {
    120.                EditorGUILayout.LabelField(new GUIContent("Substance"), GUILayout.Width(64));
    121.             }
    122.             e.substance = (ProceduralMaterial)EditorGUILayout.ObjectField(e.substance, typeof(ProceduralMaterial), false, GUILayout.Width(64), GUILayout.Height(64));
    123.             EditorGUILayout.EndVertical();
    124.             #endif
    125.          }
    126.  
    127.          EditorGUILayout.BeginVertical();
    128.          if (controls)
    129.          {
    130.             EditorGUILayout.LabelField(new GUIContent("Diffuse"), GUILayout.Width(64));
    131.          }
    132.          e.diffuse = (Texture2D)EditorGUILayout.ObjectField(e.diffuse, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    133.          EditorGUILayout.EndVertical();
    134.  
    135.          EditorGUILayout.BeginVertical();
    136.          if (controls)
    137.          {
    138.             EditorGUILayout.LabelField(new GUIContent("Normal"), GUILayout.Width(64));
    139.          }
    140.          e.normal = (Texture2D)EditorGUILayout.ObjectField(e.normal, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    141.          EditorGUILayout.EndVertical();
    142.  
    143.          if (cfg.textureMode == TextureArrayConfig.TextureMode.PBR || cfg.IsAdvancedDetail())
    144.          {
    145.             EditorGUILayout.BeginVertical();
    146.             if (controls)
    147.             {
    148.                EditorGUILayout.LabelField(new GUIContent("Height"), GUILayout.Width(64));
    149.             }
    150.             e.height = (Texture2D)EditorGUILayout.ObjectField(e.height, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    151.             if (cfg.allTextureChannelHeight == TextureArrayConfig.AllTextureChannel.Custom)
    152.             {
    153.                e.heightChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.heightChannel, GUILayout.Width(64));
    154.             }
    155.             EditorGUILayout.EndVertical();
    156.  
    157.             EditorGUILayout.BeginVertical();
    158.             if (controls)
    159.             {
    160.                EditorGUILayout.LabelField(new GUIContent("Smoothness"), GUILayout.Width(64));
    161.             }
    162.             e.smoothness = (Texture2D)EditorGUILayout.ObjectField(e.smoothness, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    163.             if (cfg.allTextureChannelSmoothness == TextureArrayConfig.AllTextureChannel.Custom)
    164.             {
    165.                e.smoothnessChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.smoothnessChannel, GUILayout.Width(64));
    166.             }
    167.             EditorGUILayout.BeginHorizontal();
    168.             EditorGUILayout.LabelField("Invert", GUILayout.Width(44));
    169.             e.isRoughness = EditorGUILayout.Toggle(e.isRoughness, GUILayout.Width(20));
    170.             EditorGUILayout.EndHorizontal();
    171.             EditorGUILayout.EndVertical();
    172.  
    173.             EditorGUILayout.BeginVertical();
    174.             if (cfg.IsAdvancedDetail())
    175.             {
    176.                if (controls)
    177.                {
    178.                   EditorGUILayout.LabelField(new GUIContent("Alpha"), GUILayout.Width(64));
    179.                }
    180.                e.alpha = (Texture2D)EditorGUILayout.ObjectField(e.alpha, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    181.                if (cfg.allTextureChannelAlpha == TextureArrayConfig.AllTextureChannel.Custom)
    182.                {
    183.                   e.alphaChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.alphaChannel, GUILayout.Width(64));
    184.                }
    185.                EditorGUILayout.BeginHorizontal();
    186.                EditorGUILayout.LabelField("Normalize", GUILayout.Width(64));
    187.                e.normalizeAlpha = EditorGUILayout.Toggle(e.normalizeAlpha, GUILayout.Width(44));
    188.                EditorGUILayout.EndHorizontal();              
    189.             }
    190.             else
    191.             {
    192.                if (controls)
    193.                {
    194.                   EditorGUILayout.LabelField(new GUIContent("AO"), GUILayout.Width(64));
    195.                }
    196.                e.ao = (Texture2D)EditorGUILayout.ObjectField(e.ao, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    197.                if (cfg.allTextureChannelAO == TextureArrayConfig.AllTextureChannel.Custom)
    198.                {
    199.                   e.aoChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.aoChannel, GUILayout.Width(64));
    200.                }
    201.             }
    202.             EditorGUILayout.EndVertical();
    203.  
    204.             if (!cfg.IsAdvancedDetail() && cfg.emisMetalArray)
    205.             {
    206.                EditorGUILayout.BeginVertical();
    207.                if (controls)
    208.                {
    209.                   EditorGUILayout.LabelField(new GUIContent("Emissive"), GUILayout.Width(64));
    210.                }
    211.                e.emis = (Texture2D)EditorGUILayout.ObjectField(e.emis, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    212.                EditorGUILayout.EndVertical();
    213.  
    214.                EditorGUILayout.BeginVertical();
    215.                if (controls)
    216.                {
    217.                   EditorGUILayout.LabelField(new GUIContent("Metal"), GUILayout.Width(64));
    218.                }
    219.                e.metal = (Texture2D)EditorGUILayout.ObjectField(e.metal, typeof(Texture2D), false, GUILayout.Width(64), GUILayout.Height(64));
    220.                e.metalChannel = (TextureArrayConfig.TextureChannel)EditorGUILayout.EnumPopup(e.metalChannel, GUILayout.Width(64));
    221.  
    222.                EditorGUILayout.EndVertical();
    223.             }
    224.          }
    225.          EditorGUILayout.EndHorizontal();
    226.  
    227.          return ret;
    228.       }
    229.  
    230.       public static bool GetFromTerrain(TextureArrayConfig cfg, Terrain t)
    231.       {
    232.          if (t != null && cfg.sourceTextures.Count == 0 && t.terrainData != null)
    233.          {
    234.             int count = t.terrainData.splatPrototypes.Length;
    235.             for (int i = 0; i < count; ++i)
    236.             {
    237.                var proto = t.terrainData.splatPrototypes[i];
    238.                var e = new TextureArrayConfig.TextureEntry();
    239.                e.diffuse = proto.texture;
    240.                e.normal = proto.normalMap;
    241.                cfg.sourceTextures.Add(e);
    242.             }
    243.             return true;
    244.          }
    245.          return false;
    246.       }
    247.  
    248.       static void GetFromTerrain(TextureArrayConfig cfg)
    249.       {
    250.          Terrain[] terrains = GameObject.FindObjectsOfType<Terrain>();
    251.          for (int x = 0; x < terrains.Length; ++x)
    252.          {
    253.             var t = terrains[x];
    254.             if (GetFromTerrain(cfg, t))
    255.                return;
    256.          }
    257.       }
    258.  
    259.       public static TextureArrayConfig CreateConfig(string path)
    260.       {
    261.          string configPath = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplatConfig.asset");
    262.          TextureArrayConfig cfg = TextureArrayConfig.CreateInstance<TextureArrayConfig>();
    263.  
    264.          AssetDatabase.CreateAsset(cfg, configPath);
    265.          AssetDatabase.SaveAssets();
    266.          AssetDatabase.Refresh();
    267.          cfg = AssetDatabase.LoadAssetAtPath<TextureArrayConfig>(configPath);
    268.          CompileConfig(cfg);
    269.          return cfg;
    270.       }
    271.  
    272.       public static TextureArrayConfig CreateConfig(Terrain t)
    273.       {
    274.          string path = MicroSplatUtilities.RelativePathFromAsset(t.terrainData);
    275.          string configPath = AssetDatabase.GenerateUniqueAssetPath(path + "/MicroSplatConfig.asset");
    276.          TextureArrayConfig cfg = TextureArrayConfig.CreateInstance<TextureArrayConfig>();
    277.          GetFromTerrain(cfg, t);
    278.  
    279.          AssetDatabase.CreateAsset(cfg, configPath);
    280.          AssetDatabase.SaveAssets();
    281.          AssetDatabase.Refresh();
    282.          cfg = AssetDatabase.LoadAssetAtPath<TextureArrayConfig>(configPath);
    283.          CompileConfig(cfg);
    284.          return cfg;
    285.  
    286.       }
    287.  
    288.       static GUIContent CTextureMode = new GUIContent("Texturing Mode", "Do you have just diffuse and normal, or a fully PBR pipeline with height, smoothness, and ao textures?");
    289.       static GUIContent CTextureSize = new GUIContent("Texture Size", "Size for all textures");
    290.       #if __MICROSPLAT_TEXTURECLUSTERS__
    291.       static GUIContent CClusterMode = new GUIContent("Cluster Mode", "Add extra slots for packing parallel arrays for texture clustering");
    292.       #endif
    293.       #if __MICROSPLAT_DETAILRESAMPLE__
    294.       static GUIContent CAntiTileArray = new GUIContent("AntiTile Array", "Create an array for each texture to have it's own Noise Normal, Detail, and Distance noise texture");
    295.       #endif
    296.  
    297.       static GUIContent CEmisMetalArray = new GUIContent("Emissive/Metal array", "Create a texture array for emissive and metallic materials");
    298.  
    299.  
    300.       void Remove(TextureArrayConfig cfg, int i)
    301.       {
    302.          cfg.sourceTextures.RemoveAt(i);
    303.          cfg.sourceTextures2.RemoveAt(i);
    304.          cfg.sourceTextures3.RemoveAt(i);
    305.       }
    306.  
    307.       void Reset(TextureArrayConfig cfg, int i)
    308.       {
    309.          cfg.sourceTextures[i].Reset();
    310.          cfg.sourceTextures2[i].Reset();
    311.          cfg.sourceTextures3[i].Reset();
    312.       }
    313.  
    314.       static void MatchArrayLength(TextureArrayConfig cfg)
    315.       {
    316.          int srcCount = cfg.sourceTextures.Count;
    317.          bool change = false;
    318.          while (cfg.sourceTextures2.Count < srcCount)
    319.          {
    320.             var entry = new TextureArrayConfig.TextureEntry();
    321.             entry.aoChannel = cfg.sourceTextures[0].aoChannel;
    322.             entry.heightChannel = cfg.sourceTextures[0].heightChannel;
    323.             entry.smoothnessChannel = cfg.sourceTextures[0].smoothnessChannel;
    324.             cfg.sourceTextures2.Add(entry);
    325.             change = true;
    326.          }
    327.  
    328.          while (cfg.sourceTextures3.Count < srcCount)
    329.          {
    330.             var entry = new TextureArrayConfig.TextureEntry();
    331.             entry.aoChannel = cfg.sourceTextures[0].aoChannel;
    332.             entry.heightChannel = cfg.sourceTextures[0].heightChannel;
    333.             entry.smoothnessChannel = cfg.sourceTextures[0].smoothnessChannel;
    334.             cfg.sourceTextures3.Add(entry);
    335.             change = true;
    336.          }
    337.  
    338.          while (cfg.sourceTextures2.Count > srcCount)
    339.          {
    340.             cfg.sourceTextures2.RemoveAt(cfg.sourceTextures2.Count - 1);
    341.             change = true;
    342.          }
    343.          while (cfg.sourceTextures3.Count > srcCount)
    344.          {
    345.             cfg.sourceTextures3.RemoveAt(cfg.sourceTextures3.Count - 1);
    346.             change = true;
    347.          }
    348.          if (change)
    349.          {
    350.             EditorUtility.SetDirty(cfg);
    351.          }
    352.       }
    353.  
    354.       public override void OnInspectorGUI()
    355.       {
    356.          var cfg = target as TextureArrayConfig;
    357.          MatchArrayLength(cfg);
    358.          EditorGUI.BeginChangeCheck();
    359.          cfg.textureMode = (TextureArrayConfig.TextureMode)EditorGUILayout.EnumPopup(CTextureMode, cfg.textureMode);
    360.  
    361.  
    362.          if (cfg.IsAdvancedDetail())
    363.          {
    364.             cfg.clusterMode = TextureArrayConfig.ClusterMode.None;
    365.          }
    366.          else
    367.          {
    368.             #if __MICROSPLAT_DETAILRESAMPLE__
    369.             cfg.antiTileArray = EditorGUILayout.Toggle(CAntiTileArray, cfg.antiTileArray);
    370.             #endif
    371.  
    372.             if (cfg.textureMode == TextureArrayConfig.TextureMode.PBR)
    373.             {
    374.                cfg.emisMetalArray = EditorGUILayout.Toggle(CEmisMetalArray, cfg.emisMetalArray);
    375.             }
    376.  
    377.             #if __MICROSPLAT_TEXTURECLUSTERS__
    378.             if (!cfg.IsAdvancedDetail())
    379.             {
    380.                cfg.clusterMode = (TextureArrayConfig.ClusterMode)EditorGUILayout.EnumPopup(CClusterMode, cfg.clusterMode);
    381.             }
    382.             #endif
    383.          }
    384.  
    385.          if (cfg.textureMode != TextureArrayConfig.TextureMode.Basic)
    386.          {
    387.             cfg.diffuseTextureSize = (TextureArrayConfig.TextureSize)EditorGUILayout.EnumPopup("Diffuse Texture Size", cfg.diffuseTextureSize);
    388.             cfg.diffuseCompression = (TextureArrayConfig.Compression)EditorGUILayout.EnumPopup("Diffuse Compression", cfg.diffuseCompression);
    389.             EditorGUILayout.BeginHorizontal();
    390.             cfg.diffuseFilterMode = (FilterMode)EditorGUILayout.EnumPopup("Diffuse Filter Mode", cfg.diffuseFilterMode);
    391.             EditorGUILayout.LabelField("Aniso", GUILayout.Width(64));
    392.             cfg.diffuseAnisoLevel = EditorGUILayout.IntSlider(cfg.diffuseAnisoLevel, 1, 16);
    393.             EditorGUILayout.EndHorizontal();
    394.  
    395.             cfg.normalSAOTextureSize = (TextureArrayConfig.TextureSize)EditorGUILayout.EnumPopup("Normal Texture Size", cfg.normalSAOTextureSize);
    396.             cfg.normalCompression = (TextureArrayConfig.Compression)EditorGUILayout.EnumPopup("Normal Compression", cfg.normalCompression);
    397.             EditorGUILayout.BeginHorizontal();
    398.             cfg.normalFilterMode = (FilterMode)EditorGUILayout.EnumPopup("Normal Filter Mode", cfg.normalFilterMode);
    399.             EditorGUILayout.LabelField("Aniso", GUILayout.Width(64));
    400.             cfg.normalAnisoLevel = EditorGUILayout.IntSlider(cfg.normalAnisoLevel, 1, 16);
    401.             EditorGUILayout.EndHorizontal();
    402.  
    403.             if (cfg.antiTileArray)
    404.             {
    405.                cfg.antiTileTextureSize = (TextureArrayConfig.TextureSize)EditorGUILayout.EnumPopup("Anti-Tile Texture Size", cfg.antiTileTextureSize);
    406.                cfg.antiTileCompression = (TextureArrayConfig.Compression)EditorGUILayout.EnumPopup("Anti-Tile Compression", cfg.antiTileCompression);
    407.                EditorGUILayout.BeginHorizontal();
    408.                cfg.antiTileFilterMode = (FilterMode)EditorGUILayout.EnumPopup("Anti-Tile Filter Mode", cfg.antiTileFilterMode);
    409.                EditorGUILayout.LabelField("Aniso", GUILayout.Width(64));
    410.                cfg.antiTileAnisoLevel = EditorGUILayout.IntSlider(cfg.antiTileAnisoLevel, 1, 16);
    411.                EditorGUILayout.EndHorizontal();
    412.             }
    413.             if (cfg.emisMetalArray)
    414.             {
    415.                cfg.emisTextureSize = (TextureArrayConfig.TextureSize)EditorGUILayout.EnumPopup("Anti-Tile Texture Size", cfg.emisTextureSize);
    416.                cfg.emisCompression = (TextureArrayConfig.Compression)EditorGUILayout.EnumPopup("Anti-Tile Compression", cfg.emisCompression);
    417.                EditorGUILayout.BeginHorizontal();
    418.                cfg.emisFilterMode = (FilterMode)EditorGUILayout.EnumPopup("Anti-Tile Filter Mode", cfg.emisFilterMode);
    419.                EditorGUILayout.LabelField("Aniso", GUILayout.Width(64));
    420.                cfg.emisAnisoLevel = EditorGUILayout.IntSlider(cfg.emisAnisoLevel, 1, 16);
    421.                EditorGUILayout.EndHorizontal();
    422.             }
    423.          }
    424.          else
    425.          {
    426.             EditorGUILayout.HelpBox("Select PBR mode to provide custom height, smoothness, and ao textures to greatly increase quality!", MessageType.Info);
    427.             cfg.diffuseTextureSize = (TextureArrayConfig.TextureSize)EditorGUILayout.EnumPopup(CTextureSize, cfg.diffuseTextureSize);
    428.             cfg.normalSAOTextureSize = cfg.diffuseTextureSize;
    429.          }
    430.  
    431.          if (MicroSplatUtilities.DrawRollup("Textures", true))
    432.          {
    433.             EditorGUILayout.HelpBox("Don't have a normal map? Any missing textures will be generated automatically from the best available source texture", MessageType.Info);
    434.             bool disableClusters = cfg.IsAdvancedDetail();
    435.             DrawHeader(cfg);
    436.             for (int i = 0; i < cfg.sourceTextures.Count; ++i)
    437.             {
    438.                using (new GUILayout.VerticalScope(GUI.skin.box))
    439.                {
    440.                   bool remove = (DrawTextureEntry(cfg, cfg.sourceTextures[i], i));
    441.  
    442.  
    443.                   if (cfg.clusterMode != TextureArrayConfig.ClusterMode.None && !disableClusters)
    444.                   {
    445.                      DrawTextureEntry(cfg, cfg.sourceTextures2[i], i, false);
    446.                   }
    447.                   if (cfg.clusterMode == TextureArrayConfig.ClusterMode.ThreeVariations && !disableClusters)
    448.                   {
    449.                      DrawTextureEntry(cfg, cfg.sourceTextures3[i], i, false);
    450.                   }
    451.                   if (remove)
    452.                   {
    453.                      var e = cfg.sourceTextures[i];
    454.                      if (!e.HasTextures())
    455.                      {
    456.                         Remove(cfg, i);
    457.                         i--;
    458.                      }
    459.                      else
    460.                      {
    461.                         Reset(cfg, i);
    462.                      }
    463.                   }
    464.  
    465.                   if (cfg.antiTileArray)
    466.                   {
    467.                      DrawAntiTileEntry(cfg, cfg.sourceTextures[i], i);
    468.                   }
    469.  
    470.                   GUILayout.Box(Texture2D.blackTexture, GUILayout.Height(3), GUILayout.ExpandWidth(true));
    471.                }
    472.             }
    473.             if (GUILayout.Button("Add Textures"))
    474.             {
    475.                if (cfg.sourceTextures.Count > 0)
    476.                {
    477.                   var entry = new TextureArrayConfig.TextureEntry();
    478.                   entry.aoChannel = cfg.sourceTextures[0].aoChannel;
    479.                   entry.heightChannel = cfg.sourceTextures[0].heightChannel;
    480.                   entry.smoothnessChannel = cfg.sourceTextures[0].smoothnessChannel;
    481.                   entry.alphaChannel = cfg.sourceTextures[0].alphaChannel;
    482.                   cfg.sourceTextures.Add(entry);
    483.                }
    484.                else
    485.                {
    486.                   var entry = new TextureArrayConfig.TextureEntry();
    487.                   entry.aoChannel = TextureArrayConfig.TextureChannel.G;
    488.                   entry.heightChannel = TextureArrayConfig.TextureChannel.G;
    489.                   entry.smoothnessChannel = TextureArrayConfig.TextureChannel.G;
    490.                   entry.alphaChannel = TextureArrayConfig.TextureChannel.G;
    491.                   cfg.sourceTextures.Add(entry);
    492.                }
    493.             }
    494.          }
    495.          if (GUILayout.Button("Grab From Scene Terrain"))
    496.          {
    497.             cfg.sourceTextures.Clear();
    498.             GetFromTerrain(cfg);
    499.          }
    500.          if (GUILayout.Button("Update"))
    501.          {
    502.             staticConfig = cfg;
    503.             EditorApplication.delayCall += DelayedCompileConfig;
    504.          }
    505.          if (EditorGUI.EndChangeCheck())
    506.          {
    507.             EditorUtility.SetDirty(cfg);
    508.          }
    509.       }
    510.  
    511.       static bool IsLinear(TextureImporter ti)
    512.       {
    513.          return ti.sRGBTexture == false;
    514.       }
    515.  
    516.       static Texture2D ResizeTexture(Texture2D source, int width, int height, bool linear)
    517.       {
    518.          RenderTexture rt = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32, linear ? RenderTextureReadWrite.Linear : RenderTextureReadWrite.sRGB);
    519.          rt.DiscardContents();
    520.          GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear) && !linear;
    521.          Graphics.Blit(source, rt);
    522.          GL.sRGBWrite = false;
    523.          RenderTexture.active = rt;
    524.          Texture2D ret = new Texture2D(width, height, TextureFormat.ARGB32, true, linear);
    525.          ret.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
    526.          ret.Apply(true);
    527.          RenderTexture.active = null;
    528.          rt.Release();
    529.          DestroyImmediate(rt);
    530.          return ret;
    531.       }
    532.  
    533.       static TextureFormat GetTextureFormat()
    534.       {
    535.          var platform = EditorUserBuildSettings.activeBuildTarget;
    536.          if (platform == BuildTarget.Android)
    537.          {
    538.             return TextureFormat.ETC2_RGBA8;
    539.          }
    540.          else if (platform == BuildTarget.iOS)
    541.          {
    542.             return TextureFormat.PVRTC_RGBA4;
    543.          }
    544.          else
    545.          {
    546.             return TextureFormat.DXT5;
    547.          }
    548.       }
    549.  
    550.       static Texture2D RenderMissingTexture(Texture2D src, string shaderPath, int width, int height, int channel = -1)
    551.       {
    552.          Texture2D res = new Texture2D(width, height, TextureFormat.ARGB32, true, true);
    553.          RenderTexture resRT = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
    554.          resRT.DiscardContents();
    555.          Shader s = Shader.Find(shaderPath);
    556.          if (s == null)
    557.          {
    558.             Debug.LogError("Could not find shader " + shaderPath);
    559.             res.Apply();
    560.             return res;
    561.          }
    562.          Material genMat = new Material(Shader.Find(shaderPath));
    563.          if (channel >= 0)
    564.          {
    565.             genMat.SetInt("_Channel", channel);
    566.          }
    567.  
    568.          GL.sRGBWrite = (QualitySettings.activeColorSpace == ColorSpace.Linear);
    569.          Graphics.Blit(src, resRT, genMat);
    570.          GL.sRGBWrite = false;
    571.  
    572.          RenderTexture.active = resRT;
    573.          res.ReadPixels(new Rect(0, 0, width, height), 0, 0);
    574.          res.Apply();
    575.          RenderTexture.active = null;
    576.          resRT.Release();
    577.          DestroyImmediate(resRT);
    578.          DestroyImmediate(genMat);
    579.          return res;
    580.       }
    581.  
    582.       static void MergeInChannel(Texture2D target, int targetChannel,
    583.          Texture2D merge, int mergeChannel, bool linear, bool invert = false)
    584.       {
    585.          Texture2D src = ResizeTexture(merge, target.width, target.height, linear);
    586.          Color[] sc = src.GetPixels();
    587.          Color[] tc = target.GetPixels();
    588.  
    589.          for (int i = 0; i < tc.Length; ++i)
    590.          {
    591.             Color s = sc[i];
    592.             Color t = tc[i];
    593.             t[targetChannel] = s[mergeChannel];
    594.             tc[i] = t;
    595.          }
    596.          if (invert)
    597.          {
    598.             for (int i = 0; i < tc.Length; ++i)
    599.             {
    600.                Color t = tc[i];
    601.                t[targetChannel] = 1.0f - t[targetChannel];
    602.                tc[i] = t;
    603.             }
    604.          }
    605.  
    606.          target.SetPixels(tc);
    607.          target.Apply();
    608.          DestroyImmediate(src);
    609.       }
    610.  
    611.  
    612.       static Texture2D NormalizeAlphaMask(Texture2D src, int targetChannel)
    613.       {
    614.          Texture2D result = RenderMissingTexture(src, "Unlit/Texture", src.width, src.height);
    615.          Color[] pixels = result.GetPixels();
    616.  
    617.          float min = 1f;
    618.          float max = 0f;
    619.          float offset = 1f / 255f;
    620.  
    621.          foreach (Color c in pixels)
    622.          {
    623.             float v = c[targetChannel];
    624.             if (v > 0)
    625.             {
    626.                if (v < min) min = v;
    627.                if (v > max) max = v;
    628.             }
    629.          }
    630.  
    631.          min -= offset;
    632.          float diff = max - min;
    633.  
    634.          if (diff > 0)
    635.          {
    636.             for (int i = 0; i < pixels.Length; i++)
    637.             {
    638.                Color c = pixels[i];
    639.                float v = c[targetChannel];
    640.  
    641.                if (v > 0)
    642.                {
    643.                   v -= min;
    644.                   v /= diff;
    645.                }
    646.                c[targetChannel] = v;
    647.                pixels[i] = new Color(v, v, v, v);
    648.             }
    649.  
    650.             result.SetPixels(pixels);
    651.             result.Apply();
    652.          }
    653.          return result;
    654.       }
    655.  
    656.  
    657.       #if !UNITY_2017_3_OR_NEWER
    658.  
    659.       static Texture2D BakeSubstance(string path, ProceduralTexture pt, bool linear = true, bool isNormal = false, bool invert = false)
    660.       {
    661.          string texPath = path + pt.name + ".tga";
    662.          TextureImporter ti = TextureImporter.GetAtPath(texPath) as TextureImporter;
    663.          if (ti != null)
    664.          {
    665.             bool changed = false;
    666.             if (ti.sRGBTexture == true && linear)
    667.             {
    668.                ti.sRGBTexture = false;
    669.                changed = true;
    670.             }
    671.             else if (ti.sRGBTexture == false && !linear)
    672.             {
    673.                ti.sRGBTexture = true;
    674.                changed = true;
    675.             }
    676.             if (isNormal && ti.textureType != TextureImporterType.NormalMap)
    677.             {
    678.                ti.textureType = TextureImporterType.NormalMap;
    679.                changed = true;
    680.             }
    681.             if (changed)
    682.             {
    683.                ti.SaveAndReimport();
    684.             }
    685.          }
    686.          var srcTex = AssetDatabase.LoadAssetAtPath<Texture2D>(texPath);
    687.          return srcTex;
    688.       }
    689.  
    690.  
    691.       static void PreprocessTextureEntries(List<TextureArrayConfig.TextureEntry> src, TextureArrayConfig cfg, bool diffuseIsLinear)
    692.       {
    693.          for (int i = 0; i < src.Count; ++i)
    694.          {
    695.             var e = src[i];
    696.             // fill out substance data if it exists
    697.             if (e.substance != null)
    698.             {
    699.                e.substance.isReadable = true;
    700.                e.substance.RebuildTexturesImmediately();
    701.                string srcPath = AssetDatabase.GetAssetPath(e.substance);
    702.  
    703.                e.substance.SetProceduralVector("$outputsize", new Vector4(11, 11, 0, 0)); // in mip map space, so 2048
    704.  
    705.                SubstanceImporter si = AssetImporter.GetAtPath(srcPath) as SubstanceImporter;
    706.  
    707.                si.SetMaterialScale(e.substance, new Vector2(2048, 2048));
    708.                string path = AssetDatabase.GetAssetPath(cfg);
    709.                path = path.Replace("\\", "/");
    710.                path = path.Substring(0, path.LastIndexOf("/"));
    711.                path += "/SubstanceExports/";
    712.                System.IO.Directory.CreateDirectory(path);
    713.                si.ExportBitmaps(e.substance, path, true);
    714.                AssetDatabase.Refresh();
    715.  
    716.                Texture[] textures = e.substance.GetGeneratedTextures();
    717.                for (int tidx = 0; tidx < textures.Length; tidx++)
    718.                {
    719.                   ProceduralTexture pt = e.substance.GetGeneratedTexture(textures[tidx].name);
    720.  
    721.                   if (pt.GetProceduralOutputType() == ProceduralOutputType.Diffuse)
    722.                   {
    723.                      e.diffuse = BakeSubstance(path, pt, diffuseIsLinear);
    724.                   }
    725.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.Height)
    726.                   {
    727.                      e.height = BakeSubstance(path, pt);
    728.                   }
    729.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.AmbientOcclusion)
    730.                   {
    731.                      e.ao = BakeSubstance(path, pt);
    732.                   }
    733.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.Normal)
    734.                   {
    735.                      e.normal = BakeSubstance(path, pt, true, true);
    736.                   }
    737.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.Smoothness)
    738.                   {
    739.                      e.smoothness = BakeSubstance(path, pt);
    740.                      e.isRoughness = false;
    741.                   }
    742.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.Roughness)
    743.                   {
    744.                      e.smoothness = BakeSubstance(path, pt, true, false);
    745.                      e.isRoughness = true;
    746.                   }
    747.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.Emissive && cfg.emisMetalArray)
    748.                   {
    749.                      e.emis = BakeSubstance(path, pt, true, false);
    750.                   }
    751.                   else if (pt.GetProceduralOutputType() == ProceduralOutputType.Metallic && cfg.emisMetalArray)
    752.                   {
    753.                      e.metal = BakeSubstance(path, pt);
    754.                   }
    755.                }
    756.             }
    757.  
    758.          }
    759.       }
    760.  
    761.       static void PreprocessTextureEntries(TextureArrayConfig cfg)
    762.       {
    763.          bool diffuseIsLinear = QualitySettings.activeColorSpace == ColorSpace.Linear;
    764.  
    765.          PreprocessTextureEntries(cfg.sourceTextures, cfg, diffuseIsLinear);
    766.          if (cfg.clusterMode != TextureArrayConfig.ClusterMode.None && !cfg.IsAdvancedDetail())
    767.          {
    768.             PreprocessTextureEntries(cfg.sourceTextures2, cfg, diffuseIsLinear);
    769.          }
    770.          if (cfg.clusterMode == TextureArrayConfig.ClusterMode.ThreeVariations && !cfg.IsAdvancedDetail())
    771.          {
    772.             PreprocessTextureEntries(cfg.sourceTextures3, cfg, diffuseIsLinear);
    773.          }
    774.  
    775.       }
    776.       #endif
    777.  
    778.       static TextureArrayConfig staticConfig;
    779.       void DelayedCompileConfig()
    780.       {
    781.          CompileConfig(staticConfig);
    782.       }
    783.  
    784.       static string GetDiffPath(TextureArrayConfig cfg, string ext)
    785.       {
    786.          string path = AssetDatabase.GetAssetPath(cfg);
    787.          // create array path
    788.          path = path.Replace("\\", "/");
    789.          return path.Replace(".asset", "_diff" + ext + "_tarray.asset");
    790.       }
    791.  
    792.       static string GetNormPath(TextureArrayConfig cfg, string ext)
    793.       {
    794.          string path = AssetDatabase.GetAssetPath(cfg);
    795.          // create array path
    796.          path = path.Replace("\\", "/");
    797.          return path.Replace(".asset", "_normSAO" + ext + "_tarray.asset");
    798.       }
    799.  
    800.       static string GetAntiTilePath(TextureArrayConfig cfg, string ext)
    801.       {
    802.          string path = AssetDatabase.GetAssetPath(cfg);
    803.          // create array path
    804.          path = path.Replace("\\", "/");
    805.          return path.Replace(".asset", "_antiTile" + ext + "_tarray.asset");
    806.       }
    807.  
    808.       static string GetEmisPath(TextureArrayConfig cfg, string ext)
    809.       {
    810.          string path = AssetDatabase.GetAssetPath(cfg);
    811.          // create array path
    812.          path = path.Replace("\\", "/");
    813.          return path.Replace(".asset", "_emis" + ext + "_tarray.asset");
    814.       }
    815.  
    816.       static int SizeToMipCount(int size)
    817.       {
    818.          int mips = 11;
    819.          if (size == 4096)
    820.             mips = 13;
    821.          else if (size == 2048)
    822.             mips = 12;
    823.          else if (size == 1024)
    824.             mips = 11;
    825.          else if (size == 512)
    826.             mips = 10;
    827.          else if (size == 256)
    828.             mips = 9;
    829.          else if (size == 128)
    830.             mips = 8;
    831.          else if (size == 64)
    832.             mips = 7;
    833.          else if (size == 32)
    834.             mips = 6;
    835.          return mips;
    836.       }
    837.  
    838.       static void CompileConfig(TextureArrayConfig cfg,
    839.          List<TextureArrayConfig.TextureEntry> src,
    840.          string ext,
    841.          bool isCluster = false)
    842.       {
    843.          bool diffuseIsLinear = QualitySettings.activeColorSpace == ColorSpace.Linear;
    844.  
    845.          int diffuseWidth = (int)cfg.diffuseTextureSize;
    846.          int diffuseHeight = (int)cfg.diffuseTextureSize;
    847.          int normalWidth = (int)cfg.normalSAOTextureSize;
    848.          int normalHeight = (int)cfg.normalSAOTextureSize;
    849.          int antiTileWidth = (int)cfg.antiTileTextureSize;
    850.          int antiTileHeight = (int)cfg.antiTileTextureSize;
    851.          int emisWidth = (int)cfg.emisTextureSize;
    852.          int emisHeight = (int)cfg.emisTextureSize;
    853.  
    854.          int diffuseAnisoLevel = cfg.diffuseAnisoLevel;
    855.          int normalAnisoLevel = cfg.normalAnisoLevel;
    856.          int antiTileAnisoLevel = cfg.antiTileAnisoLevel;
    857.          int emisAnisoLevel = cfg.emisAnisoLevel;
    858.  
    859.          FilterMode diffuseFilter = cfg.diffuseFilterMode;
    860.          FilterMode normalFilter = cfg.normalFilterMode;
    861.          FilterMode antiTileFilter = cfg.antiTileFilterMode;
    862.          FilterMode emisFilter = cfg.emisFilterMode;
    863.  
    864.          int diffuseMipCount = SizeToMipCount(diffuseWidth);
    865.          int normalMipCount = SizeToMipCount(normalWidth);
    866.          int antiTileMipCount = SizeToMipCount(antiTileWidth);
    867.          int emisMipCount = SizeToMipCount(emisWidth);
    868.  
    869.          int texCount = src.Count;
    870.          if (texCount < 1)
    871.             texCount = 1;
    872.  
    873.          // diffuse
    874.          Texture2DArray diffuseArray = new Texture2DArray(diffuseWidth, diffuseHeight, texCount,
    875.             cfg.diffuseCompression == TextureArrayConfig.Compression.AutomaticCompressed ? GetTextureFormat() : TextureFormat.ARGB32,
    876.             true, diffuseIsLinear);
    877.  
    878.          diffuseArray.wrapMode = TextureWrapMode.Repeat;
    879.          diffuseArray.filterMode = diffuseFilter;
    880.          diffuseArray.anisoLevel = diffuseAnisoLevel;
    881.  
    882.  
    883.          // normal
    884.          Texture2DArray normalSAOArray = new Texture2DArray(normalWidth, normalHeight, texCount,
    885.             cfg.normalCompression == TextureArrayConfig.Compression.AutomaticCompressed ? GetTextureFormat() : TextureFormat.ARGB32,
    886.             true, true);
    887.  
    888.          normalSAOArray.wrapMode = TextureWrapMode.Repeat;
    889.          normalSAOArray.filterMode = normalFilter;
    890.          normalSAOArray.anisoLevel = normalAnisoLevel;
    891.  
    892.          // antitile
    893.          Texture2DArray antiTileArray = null;
    894.          if (!isCluster && cfg.antiTileArray)
    895.          {
    896.             antiTileArray = new Texture2DArray(antiTileWidth, antiTileHeight, texCount,
    897.                cfg.antiTileCompression == TextureArrayConfig.Compression.AutomaticCompressed ? GetTextureFormat() : TextureFormat.ARGB32,
    898.                true, true);
    899.  
    900.             antiTileArray.wrapMode = TextureWrapMode.Repeat;
    901.             antiTileArray.filterMode = antiTileFilter;
    902.             antiTileArray.anisoLevel = antiTileAnisoLevel;
    903.          }
    904.  
    905.          // emis/metal
    906.          Texture2DArray emisArray = null;
    907.          if (cfg.emisMetalArray && !cfg.IsAdvancedDetail())
    908.          {
    909.             emisArray = new Texture2DArray(emisWidth, emisHeight, texCount,
    910.                cfg.emisCompression == TextureArrayConfig.Compression.AutomaticCompressed ? GetTextureFormat() : TextureFormat.ARGB32,
    911.                true, diffuseIsLinear);
    912.  
    913.             emisArray.wrapMode = TextureWrapMode.Repeat;
    914.             emisArray.filterMode = emisFilter;
    915.             emisArray.anisoLevel = emisAnisoLevel;
    916.          }
    917.  
    918.          for (int i = 0; i < src.Count; ++i)
    919.          {
    920.             try
    921.             {
    922.                EditorUtility.DisplayProgressBar("Packing textures...", "", (float)i / (float)src.Count);
    923.  
    924.                // first, generate any missing data. We generate a full NSAO map from diffuse or height map
    925.                // if no height map is provided, we then generate it from the resulting or supplied normal.
    926.                var e = src[i];
    927.                Texture2D diffuse = e.diffuse;
    928.                if (diffuse == null)
    929.                {
    930.                   diffuse = Texture2D.whiteTexture;
    931.                }
    932.  
    933.                // resulting maps
    934.                Texture2D diffuseHeightTex = ResizeTexture(diffuse, diffuseWidth, diffuseHeight, diffuseIsLinear);
    935.                Texture2D normalSAOTex = null;
    936.                Texture2D antiTileTex = null;
    937.                Texture2D emisTex = null;
    938.  
    939.                int heightChannel = (int)e.heightChannel;
    940.                int aoChannel = (int)e.aoChannel;
    941.                int smoothChannel = (int)e.smoothnessChannel;
    942.                int alphaChannel = (int)e.alphaChannel;
    943.                int detailChannel = (int)e.detailChannel;
    944.                int distanceChannel = (int)e.distanceChannel;
    945.                int metalChannel = (int)e.metalChannel;
    946.  
    947.                if (cfg.allTextureChannelHeight != TextureArrayConfig.AllTextureChannel.Custom)
    948.                {
    949.                   heightChannel = (int)cfg.allTextureChannelHeight;
    950.                }
    951.                if (cfg.allTextureChannelAO != TextureArrayConfig.AllTextureChannel.Custom)
    952.                {
    953.                   aoChannel = (int)cfg.allTextureChannelAO;
    954.                }
    955.                if (cfg.allTextureChannelSmoothness != TextureArrayConfig.AllTextureChannel.Custom)
    956.                {
    957.                   smoothChannel = (int)cfg.allTextureChannelSmoothness;
    958.                }
    959.                if (cfg.allTextureChannelAlpha != TextureArrayConfig.AllTextureChannel.Custom)
    960.                {
    961.                   alphaChannel = (int)cfg.allTextureChannelAlpha;
    962.                }
    963.  
    964.                if (e.normal == null)
    965.                {
    966.                   if (e.height == null)
    967.                   {
    968.                      normalSAOTex = RenderMissingTexture(diffuse, "Hidden/MicroSplat/NormalSAOFromDiffuse", normalWidth, normalHeight);
    969.                   }
    970.                   else
    971.                   {
    972.                      normalSAOTex = RenderMissingTexture(e.height, "Hidden/MicroSplat/NormalSAOFromHeight", normalWidth, normalHeight, heightChannel);
    973.                   }
    974.                }
    975.                else
    976.                {
    977.                   // copy, but go ahead and generate other channels in case they aren't provided later.
    978.                   normalSAOTex = RenderMissingTexture(e.normal, "Hidden/MicroSplat/NormalSAOFromNormal", normalWidth, normalHeight);
    979.                }
    980.  
    981.  
    982.  
    983.                if (!isCluster && cfg.antiTileArray)
    984.                {
    985.                   antiTileTex = RenderMissingTexture(e.noiseNormal, "Hidden/MicroSplat/NormalSAOFromNormal", antiTileWidth, antiTileHeight);
    986.                }
    987.  
    988.                bool destroyHeight = false;
    989.                Texture2D height = e.height;
    990.                if (height == null)
    991.                {
    992.                   destroyHeight = true;
    993.                   height = RenderMissingTexture(normalSAOTex, "Hidden/MicroSplat/HeightFromNormal", diffuseHeight, diffuseWidth);
    994.                }
    995.  
    996.                MergeInChannel(diffuseHeightTex, (int)TextureArrayConfig.TextureChannel.A, height, heightChannel, diffuseIsLinear);
    997.  
    998.  
    999.                if (cfg.emisMetalArray && !cfg.IsAdvancedDetail())
    1000.                {
    1001.                   emisTex = ResizeTexture(e.emis != null ? e.emis : Texture2D.blackTexture, emisWidth, emisHeight, diffuseIsLinear);
    1002.                   Texture2D metal = ResizeTexture(e.metal != null ? e.metal : Texture2D.blackTexture, emisWidth, emisHeight, true);
    1003.                   MergeInChannel(emisTex, 3, metal, e.metal != null ? metalChannel : 0, true, false);
    1004.                   DestroyImmediate(metal);
    1005.                }
    1006.  
    1007.                if (cfg.IsAdvancedDetail())
    1008.                {
    1009.                   if (e.alpha != null)
    1010.                   {
    1011.                      var alpha = e.normalizeAlpha? NormalizeAlphaMask(e.alpha, (int)TextureArrayConfig.TextureChannel.B) : e.alpha;
    1012.                      MergeInChannel(normalSAOTex, (int)TextureArrayConfig.TextureChannel.B, alpha, alphaChannel, true);
    1013.                   }
    1014.                   else
    1015.                   {
    1016.                      MergeInChannel(normalSAOTex, (int)TextureArrayConfig.TextureChannel.B, Texture2D.whiteTexture, 0, true);
    1017.                   }
    1018.                }
    1019.                else if (e.ao != null)
    1020.                {
    1021.                   MergeInChannel(normalSAOTex, (int)TextureArrayConfig.TextureChannel.B, e.ao, aoChannel, true);
    1022.                }
    1023.  
    1024.                if (e.smoothness != null)
    1025.                {
    1026.                   MergeInChannel(normalSAOTex, (int)TextureArrayConfig.TextureChannel.R, e.smoothness, smoothChannel, true, e.isRoughness);
    1027.                }
    1028.  
    1029.                if (!isCluster && cfg.antiTileArray && antiTileTex != null)
    1030.                {
    1031.                   Texture2D detail = e.detailNoise;
    1032.                   Texture2D distance = e.distanceNoise;
    1033.                   bool destroyDetail = false;
    1034.                   bool destroyDistance = false;
    1035.                   if (detail == null)
    1036.                   {
    1037.                      detail = new Texture2D(1, 1, TextureFormat.RGB24, true, true);
    1038.                      detail.SetPixel(0, 0, Color.grey);
    1039.                      detail.Apply();
    1040.                      destroyDetail = true;
    1041.                      detailChannel = (int)TextureArrayConfig.TextureChannel.G;
    1042.                   }
    1043.                   if (distance == null)
    1044.                   {
    1045.                      distance = new Texture2D(1, 1, TextureFormat.RGB24, true, true);
    1046.                      distance.SetPixel(0, 0, Color.grey);
    1047.                      distance.Apply();
    1048.                      destroyDistance = true;
    1049.                      distanceChannel = (int)TextureArrayConfig.TextureChannel.G;
    1050.                   }
    1051.                   MergeInChannel(antiTileTex, (int)TextureArrayConfig.TextureChannel.R, detail, detailChannel, true, false);
    1052.                   MergeInChannel(antiTileTex, (int)TextureArrayConfig.TextureChannel.B, distance, distanceChannel, true, false);
    1053.  
    1054.                   if (destroyDetail)
    1055.                   {
    1056.                      GameObject.DestroyImmediate(detail);
    1057.                   }
    1058.                   if (destroyDistance)
    1059.                   {
    1060.                      GameObject.DestroyImmediate(distance);
    1061.                   }
    1062.                }
    1063.  
    1064.  
    1065.                if (cfg.normalCompression != TextureArrayConfig.Compression.Uncompressed)
    1066.                {
    1067.                   EditorUtility.CompressTexture(normalSAOTex, GetTextureFormat(), TextureCompressionQuality.Normal);
    1068.                }
    1069.  
    1070.                if (cfg.diffuseCompression != TextureArrayConfig.Compression.Uncompressed)
    1071.                {
    1072.                   EditorUtility.CompressTexture(diffuseHeightTex, GetTextureFormat(), TextureCompressionQuality.Normal);
    1073.                }
    1074.  
    1075.                if (antiTileTex != null && cfg.antiTileCompression != TextureArrayConfig.Compression.Uncompressed)
    1076.                {
    1077.                   EditorUtility.CompressTexture(antiTileTex, GetTextureFormat(), TextureCompressionQuality.Normal);
    1078.                }
    1079.  
    1080.                if (cfg.emisMetalArray && !cfg.IsAdvancedDetail() && emisTex != null && cfg.emisCompression != TextureArrayConfig.Compression.Uncompressed)
    1081.                {
    1082.                   EditorUtility.CompressTexture(emisTex, GetTextureFormat(), TextureCompressionQuality.Normal);
    1083.                }
    1084.  
    1085.                normalSAOTex.Apply();
    1086.                diffuseHeightTex.Apply();
    1087.  
    1088.                if (antiTileTex != null)
    1089.                {
    1090.                   antiTileTex.Apply();
    1091.                }
    1092.  
    1093.                if (emisTex != null)
    1094.                {
    1095.                   emisTex.Apply();
    1096.                }
    1097.  
    1098.                for (int mip = 0; mip < diffuseMipCount; ++mip)
    1099.                {
    1100.                   Graphics.CopyTexture(diffuseHeightTex, 0, mip, diffuseArray, i, mip);
    1101.                }
    1102.                for (int mip = 0; mip < normalMipCount; ++mip)
    1103.                {
    1104.                   Graphics.CopyTexture(normalSAOTex, 0, mip, normalSAOArray, i, mip);
    1105.                }
    1106.                if (antiTileTex != null)
    1107.                {
    1108.                   for (int mip = 0; mip < antiTileMipCount; ++mip)
    1109.                   {
    1110.                      Graphics.CopyTexture(antiTileTex, 0, mip, antiTileArray, i, mip);
    1111.                   }
    1112.                }
    1113.                if (emisTex != null)
    1114.                {
    1115.                   for (int mip = 0; mip < emisMipCount; ++mip)
    1116.                   {
    1117.                      Graphics.CopyTexture(emisTex, 0, mip, emisArray, i, mip);
    1118.                   }
    1119.                }
    1120.                DestroyImmediate(diffuseHeightTex);
    1121.                DestroyImmediate(normalSAOTex);
    1122.  
    1123.                if (antiTileTex != null)
    1124.                {
    1125.                   DestroyImmediate(antiTileTex);
    1126.                }
    1127.                if (emisTex)
    1128.                {
    1129.                   DestroyImmediate(emisTex);
    1130.                }
    1131.  
    1132.                if (destroyHeight)
    1133.                {
    1134.                   DestroyImmediate(height);
    1135.                }
    1136.  
    1137.  
    1138.             }
    1139.             finally
    1140.             {
    1141.                EditorUtility.ClearProgressBar();
    1142.             }
    1143.  
    1144.          }
    1145.          EditorUtility.ClearProgressBar();
    1146.  
    1147.          diffuseArray.Apply(false, true);
    1148.          normalSAOArray.Apply(false, true);
    1149.          if (antiTileArray != null)
    1150.          {
    1151.             antiTileArray.Apply(false, true);
    1152.          }
    1153.          if (emisArray != null)
    1154.          {
    1155.             emisArray.Apply(false, true);
    1156.          }
    1157.  
    1158.          string diffPath = GetDiffPath(cfg, ext);
    1159.          string normSAOPath = GetNormPath(cfg, ext);
    1160.          string antiTilePath = GetAntiTilePath(cfg, ext);
    1161.          string emisPath = GetEmisPath(cfg, ext);
    1162.  
    1163.          {
    1164.             var existing = AssetDatabase.LoadAssetAtPath<Texture2DArray>(diffPath);
    1165.             if (existing != null)
    1166.             {
    1167.                EditorUtility.CopySerialized(diffuseArray, existing);
    1168.             }
    1169.             else
    1170.             {
    1171.                AssetDatabase.CreateAsset(diffuseArray, diffPath);
    1172.             }
    1173.          }
    1174.  
    1175.          {
    1176.             var existing = AssetDatabase.LoadAssetAtPath<Texture2DArray>(normSAOPath);
    1177.             if (existing != null)
    1178.             {
    1179.                EditorUtility.CopySerialized(normalSAOArray, existing);
    1180.             }
    1181.             else
    1182.             {
    1183.                AssetDatabase.CreateAsset(normalSAOArray, normSAOPath);
    1184.             }
    1185.          }
    1186.  
    1187.          if (cfg.antiTileArray && antiTileArray != null)
    1188.          {
    1189.             var existing = AssetDatabase.LoadAssetAtPath<Texture2DArray>(antiTilePath);
    1190.             if (existing != null)
    1191.             {
    1192.                EditorUtility.CopySerialized(antiTileArray, existing);
    1193.             }
    1194.             else
    1195.             {
    1196.                AssetDatabase.CreateAsset(antiTileArray, antiTilePath);
    1197.             }
    1198.          }
    1199.  
    1200.          if (cfg.emisMetalArray && emisArray != null)
    1201.          {
    1202.             var existing = AssetDatabase.LoadAssetAtPath<Texture2DArray>(emisPath);
    1203.             if (existing != null)
    1204.             {
    1205.                EditorUtility.CopySerialized(emisArray, existing);
    1206.             }
    1207.             else
    1208.             {
    1209.                AssetDatabase.CreateAsset(emisArray, emisPath);
    1210.             }
    1211.          }
    1212.  
    1213.          EditorUtility.SetDirty(cfg);
    1214.          AssetDatabase.Refresh();
    1215.          AssetDatabase.SaveAssets();
    1216.  
    1217.          MicroSplatUtilities.ClearPreviewCache();
    1218.          MicroSplatTerrain.SyncAll();
    1219.       }
    1220.  
    1221.       public static void CompileConfig(TextureArrayConfig cfg)
    1222.       {
    1223.          MatchArrayLength(cfg);
    1224.          #if !UNITY_2017_3_OR_NEWER
    1225.          PreprocessTextureEntries(cfg);
    1226.          #endif
    1227.          CompileConfig(cfg, cfg.sourceTextures, "", false);
    1228.          if (cfg.clusterMode != TextureArrayConfig.ClusterMode.None)
    1229.          {
    1230.             CompileConfig(cfg, cfg.sourceTextures2, "_C2", true);
    1231.          }
    1232.          if (cfg.clusterMode == TextureArrayConfig.ClusterMode.ThreeVariations)
    1233.          {
    1234.             CompileConfig(cfg, cfg.sourceTextures3, "_C3", true);
    1235.          }
    1236.  
    1237.  
    1238.          cfg.diffuseArray = AssetDatabase.LoadAssetAtPath<Texture2DArray>(GetDiffPath(cfg, ""));
    1239.          cfg.normalSAOArray = AssetDatabase.LoadAssetAtPath<Texture2DArray>(GetNormPath(cfg, ""));
    1240.  
    1241.          EditorUtility.SetDirty(cfg);
    1242.          AssetDatabase.Refresh();
    1243.          AssetDatabase.SaveAssets();
    1244.  
    1245.          MicroSplatUtilities.ClearPreviewCache();
    1246.          MicroSplatTerrain.SyncAll();
    1247.       }
    1248.  
    1249.    }
    1250. }
    1251.  
     
    jlocke likes this.
  44. Nazowa

    Nazowa

    Joined:
    Oct 30, 2017
    Posts:
    15
    Ah OK I will murde...erm move the function out of Unity version check block if that is all it takes. Thank you...
     
  45. jlocke

    jlocke

    Joined:
    Dec 16, 2017
    Posts:
    62
    Good morning .. I am wondering if there are progress on the river flows asset .. thanks a lot and have a great day
     
  46. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    still in beta, not sure when release will be yet..
     
    jlocke and blitzvb like this.
  47. blitzvb

    blitzvb

    Joined:
    Mar 20, 2015
    Posts:
    284
    Just FYI, I got an answer from Amplify, they use it just for stats and therefore think it will work.

    so it's go for me.

    thanks Jason.
     
  48. blitzvb

    blitzvb

    Joined:
    Mar 20, 2015
    Posts:
    284
    ok I did manage to integrate the first parts of the integration into some fragments and it recompile the final shader with the AT2 modifications.

    The problem is that it's not virtualizing/showing the global texture at this point and I beleave it's coming from the surf function:

    I integrated that part here :

    void GlobalTintTexturePerTex(inout RawSamples s, Config config, float camDist)
    {
    half4 texMS = tex2D(_GlobalTintTex, config.uv); //AT2
    VirtualCoord vcoord = VTComputeVirtualCoord( texMS.xy ); //AT2
    half4 tex = VTSampleBase( vcoord ); //AT2
    ...

    Also I would like to have the global texture at the bottom not blended with the splat and all the different mode avalaible doesn’t seems to give me that.
     
    Last edited: Jan 5, 2018
  49. diego_ger

    diego_ger

    Joined:
    Dec 17, 2017
    Posts:
    8
    Hello, sorry about this absolutly newbie question, but is it possible with microsplat to change betwen terrain textures at runtime in a specific part of the terrain? eg. I drive thrugh a field with grass with a car, and the wheels should change the grass leyer into just naked dirt terrain layer in the specific part where the wheels passed.
     
  50. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    3,563
    You can change textures the same way you would with standard Unity terrain, by editing the splat data. However, at runtime a faster way is to grab the control textures from the material instance and edit them directly - bypassing the Unity Terrain system all together..
     
    diego_ger and jlocke like this.