Search Unity

2018.3 Extract Instanced Terrain Normal?

Discussion in 'World Building' started by local306, Mar 7, 2019.

  1. local306

    local306

    Joined:
    Feb 28, 2016
    Posts:
    155
    Is it possible to get the normal map generated by the terrain that is applied to it when draw instanced is enabled?

    Reason being is that I am working with some older terrain shaders that don't currently support the instanced option, and suffer from the poor lighting we're used to previously when it relies on the present vert data (more so when viewed from a distance and the LOD steps down).

    However, said terrain shaders that I am working with allow for global normals to be applied per tile to restore these details which is somewhat of a fix for now I suppose until hopefully they roll out instanced support. Hence why I am asking whether I can get the higher quality normal maps that Unity generates from the height map for the time being.
     
  2. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    You can generate them yourselves from the terrain API, there's a function to get the normal at any point, so you can just write that out to a texture.
     
    local306 likes this.
  3. local306

    local306

    Joined:
    Feb 28, 2016
    Posts:
    155
    Thanks @jbooth. I was also the one bugging you on Discord about whether MicroSplat would support instancing as well, so maybe I'll just wait until that is complete :p
     
  4. jbooth

    jbooth

    Joined:
    Jan 6, 2014
    Posts:
    5,461
    Instancing has been supported for a while now- per-pixel normal was uploaded to the store this morning.
     
    local306 likes this.
  5. local306

    local306

    Joined:
    Feb 28, 2016
    Posts:
    155
  6. SohleHermelin

    SohleHermelin

    Joined:
    Sep 30, 2013
    Posts:
    1
    Don't exactly know if thats what you need but you can get the generated normal map for the terrain from the Terrain API.

    Code (CSharp):
    1. Terrain terrain = GetComponent<Terrain>();
    2. Texture2D normalMap = terrain.normalmapTexture;
     
  7. wlad_s

    wlad_s

    Joined:
    Feb 18, 2011
    Posts:
    148
    Could someone please help me with this problem? I got the terrain.normalmapTexture as @SohleHermelin suggested but I'm having trouble converting it to a Texture2D and saving it as PNG.

    Code (CSharp):
    1. [Sirenix.OdinInspector.Button(Sirenix.OdinInspector.ButtonSizes.Medium)]
    2.     void ExtractNormalMap() {
    3.  
    4.         Terrain terrain = GetComponent<Terrain>();
    5.         RenderTexture normalMapRT = terrain.normalmapTexture;
    6.  
    7.         Texture2D newTexture = new Texture2D(normalMapRT.width, normalMapRT.height, TextureFormat.ARGB32, false);
    8.  
    9.         RenderTexture.active = normalMapRT;
    10.         newTexture.ReadPixels(new Rect(0, 0, normalMapRT.width, normalMapRT.height), 0, 0, false);
    11.         newTexture.Apply();
    12.  
    13.         byte[] bytes = newTexture.EncodeToPNG();
    14.         System.IO.File.WriteAllBytes(Application.dataPath + "/_TERRAIN/_Utils/" +gameObject.name +"_nrm.png", bytes);
    15.  
    16.         DestroyImmediate(newTexture);
    17.  
    18.     }
    This doesn't work, the console displays an error "D3D11 unsupported ReadPixels destination texture format (5)"

    On further inspection, the rendertexture format is ARGB2101010

    As for the method @jbooth suggested, I have no idea how to read that normals information and save it to png. Would that even be a good solution? Would the resulting normal map be as if it was calculated against a flat plane, not low-res terrain mesh?