• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by John 2 · Mar 03, 2010 at 10:24 PM · textureterraingrassdetail

How can I automatically place grass and other details on my terrain to correspond with the splatmap?

I have a grass texture on certain parts of my terrain, and I want to have a grass detail everywhere that texture is. Is there a quick way to do t$$anonymous$$s?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

5 Replies

· Add your reply
  • Sort: 
avatar image
6

Answer by duck · Mar 04, 2010 at 11:43 AM

There isn't a quick way, but it is possible, however you'd have to use some of the undocumented terrain commands to read the Alphamap (splat map) data, and then construct a corresponding detail layers to match it.

The commands you'll need to use are:

// read all layers of the alphamap (the splatmap) into a 3D float array: float[,,] alphaMapData = terrainData.GetAlphamaps(x, y, width, height);

// read all detail layers into a 3D int array: int numDetails = terrainData.detailPrototypes.Length; int [,,] detailMapData = new int[terrainData.detailWidth, terrainData.detailHeight, numDetails]; for (int layerNum=0; layerNum < numDetails; layerNum++) { int[,] detailLayer = terrainData.GetDetailLayer(x, y, width, height, layerNum); }

// write all detail data to terrain data: for (int n = 0; n < detailMapData.Length; n++) { terrainData.SetDetailLayer(0, 0, n, detailMapData[n]); }

// write alpha map data to terrain data: terrainData.SetAlphamaps(x, y, alphaMapData);

In your case, you might not want to read the detail layers, you might just want to start with the new int[,,] detailMapData and populate it yourself based on whatever's in the alpha map. You'd then might want to wrap all t$$anonymous$$s up in an editor script, so that you can call it from a menu or somet$$anonymous$$ng.

Important t$$anonymous$$ngs to note:

  • The detail map width and height might be different to the alpha map width and heigth (depending on your terrain settings).

  • These functions are undocumented. Any future updates of the unity engine might change or remove these functions from the API. T$$anonymous$$s means your project may not work in future versions of the Unity editor, and webplayer builds may not work with future versions of the plugin.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bad Commander Filename · Feb 21, 2011 at 03:55 AM 0
Share

how exactly would these commands be implemented?

avatar image
1

Answer by chad · Mar 19, 2010 at 04:04 PM

You can do t$$anonymous$$s with these scripts: http://lemuria.org/projects/wiki/TerrainTools

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by bingomanatee · Oct 30, 2011 at 04:34 PM

where are these x,y coming from?

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by RKSandswept · Apr 17, 2014 at 01:06 AM

We do synthetic grass on terrain. I arrived at t$$anonymous$$s info by trial and error and some guesses as to how it is implemented inside Utity3D.

The call SetDetailLayer sets a detail layer. So if your terrain has 4 grasses defined in the detail part, they are indicies 0,1,2,3. So say we have 4 grasses called grass, weed1, weed2, weed3

You make int[z,x] arrays for each layer. Then the value of the array entries is the grass density. We keep track of road paths and various biome regions so we change the mix and keep grass out of roads.

You fill in your arrays and then call SetDetailLayer for each layer.

The array values appear to range from 0 to 14 (why????? Maybe it is stored as a 8 bit byte and 0xFF flags somet$$anonymous$$ng?) where 0 is no ground cover, and 14 is very dense.

You can set a sub region by passing a smaller array to SetDetailLayer and then the first tow params xBase and yBase to some where in the overall detail grid area.

T$$anonymous$$s code is very particular to our game, but is an example...

WARNING - A later found that x and z are swapped. It should read nearTerrainGrass3[z,x] in lots of places.

Also, our world is X and Z are the ground directions, and Y is altitude.

WorldPosition wp = new WorldPosition(); for(int z = 0; z

                 debugn = (int)b;
                 // Terrain splats are: 
                 //     
                 //                 R      G      B             A
                 // terrainSplat1 sand    mud   grass       rocky grass
                 // terrainSplat2 farm   woods roadside   alpha to terrainSplat1
                 //
                 // terrainSplat2 alpha 0.0f mean see through to terrainSplat1
                 // terrainSplat2 alpha is either 1.0f or 0.0f (no fractional values)
                 // Also wierdness, terrainSplat1 alpha is inverted as a value for rocky grass.
                 // Also these draw in layer order R then G then B then Alpha and last wins.
                 // and also must add up to 1 if factional.
                 //

                 // The detail density ranges from 0 to 14.
                 int grassMax = 14;

                 switch(b)
                 {
                 case eGroundAlphaType.Aspen:
                     terrainSplat2.SetPixel(x, z, woods2);
                     nearTerrainGrass0[x,z] = 6;
                     nearTerrainGrass1[x,z] = 6;
                     nearTerrainGrass2[x,z] = 6;
                     nearTerrainGrass3[x,z] = 6;
                     break;
                 case eGroundAlphaType.FarmField:
                     terrainSplat2.SetPixel(x, z, farm2);
                     nearTerrainGrass0[x,z] = 4;
                     nearTerrainGrass1[x,z] = 4;
                     nearTerrainGrass2[x,z] = 4;
                     nearTerrainGrass3[x,z] = 2;
                     break;
                 case eGroundAlphaType.Grass:
                     terrainSplat1.SetPixel(x, z, grass1);
                     terrainSplat2.SetPixel(x, z, off2);
                     nearTerrainGrass0[x,z] = 12;
                     nearTerrainGrass1[x,z] = 2;
                     nearTerrainGrass2[x,z] = 2;
                     nearTerrainGrass3[x,z] = 2;
                     break;
                 case eGroundAlphaType.Maple:
                     terrainSplat2.SetPixel(x, z, woods2);
                     nearTerrainGrass0[x,z] = 6;
                     nearTerrainGrass1[x,z] = 6;
                     nearTerrainGrass2[x,z] = 6;
                     nearTerrainGrass3[x,z] = 6;
                     break;
                 case eGroundAlphaType.Pine:
                     terrainSplat2.SetPixel(x, z, woods2);
                     nearTerrainGrass0[x,z] = 6;
                     nearTerrainGrass1[x,z] = 6;
                     nearTerrainGrass2[x,z] = 6;
                     nearTerrainGrass3[x,z] = 6;
                     break;
                 case eGroundAlphaType.Road:
                     terrainSplat2.SetPixel(x, z, roadside2);
                     nearTerrainGrass0[x,z] = 0;
                     nearTerrainGrass1[x,z] = 0;
                     nearTerrainGrass2[x,z] = 0;
                     nearTerrainGrass3[x,z] = 0;
                     break;
                 case eGroundAlphaType.RockyGrass:
                     terrainSplat1.SetPixel(x, z, rockyGrass1);
                     terrainSplat2.SetPixel(x, z, off2);
                     nearTerrainGrass0[x,z] = 9;
                     nearTerrainGrass1[x,z] = 3;
                     nearTerrainGrass2[x,z] = 2;
                     nearTerrainGrass3[x,z] = 2;
                     break;
                 default:
                     terrainSplat1.SetPixel(x, z, grass1);
                     terrainSplat2.SetPixel(x, z, off2);
                     nearTerrainGrass0[x,z] = 4;
                     nearTerrainGrass1[x,z] = 4;
                     nearTerrainGrass2[x,z] = 4;
                     nearTerrainGrass3[x,z] = 4;
                     break;
                 }
             }
         }
     }

     terrainSplat1.Apply();
     terrainSplat2.Apply();

// byte[] png = terrainSplat1.EncodeToPNG(); // File.WriteAllBytes("Splat1.png", png); // png = terrainSplat2.EncodeToPNG(); // File.WriteAllBytes("Splat2.png", png);

     if(needsSet)
     {
         TheDeadLinger.tdl.globalTerrain.materialTemplate.SetTexture("_Splat1", terrainSplat1);
         TheDeadLinger.tdl.globalTerrain.materialTemplate.SetTexture("_Splat2", terrainSplat2);
         TheDeadLinger.tdl.globalTerrain.terrainData.SetDetailLayer(0, 0, 0, nearTerrainGrass0);
         TheDeadLinger.tdl.globalTerrain.terrainData.SetDetailLayer(0, 0, 1, nearTerrainGrass1);
         TheDeadLinger.tdl.globalTerrain.terrainData.SetDetailLayer(0, 0, 2, nearTerrainGrass2);
         TheDeadLinger.tdl.globalTerrain.terrainData.SetDetailLayer(0, 0, 3, nearTerrainGrass3);
     }

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by theFongz · Jun 12, 2017 at 11:33 PM

Here you go, t$$anonymous$$s one worked for me. It's a bit simple but you should be able to extend it. Thanks @duck and @RKSandswept for putting me on the right path:

     public Terrain terrain;
 
     private int detailStrength = 10; //A fair value to make the grass t$$anonymous$$ck and luscious
 
     private int myTextureLayer = 1; //Assumed to be the first non-base texture layer - t$$anonymous$$s is the ground texture from w$$anonymous$$ch we wish to sprout grass
     private int myDetailLayer = 0; //Assumed to be the first detail layer - t$$anonymous$$s is the grass we wish to auto-populate
 
     // Use t$$anonymous$$s for initialization
     void Start () {
 
         TerrainData terrainData = terrain.terrainData;
 
         // get the alhpa maps - i.e. all the ground texture layers
         float[,,] alphaMapData = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);
         //get the detail map for the grass layer we're after
         int[,] map = terrainData.GetDetailLayer(0, 0, terrainData.detailWidth, terrainData.detailHeight, myDetailLayer);
 
         //now copy-paste the alpha map onto the detail map, pixel by pixel
         for(int x = 0 ; x < terrainData.alphamapWidth; x++) {
             for(int y = 0 ; y < terrainData.alphamapHeight; y++) {
                 //Check the Detail Resolution and the Control Texture Resolution in the terrain settings.
                 //By default the detail resolution is twice the alpha resolution! So every detail co-ordinate is going to have to affect a 2x2 square!
                 //Would be nice if I could so some anti aliasing but t$$anonymous$$s will have to do for now
                 int x1 = x * 2;
                 int x2 = (x * 2)+1;
                 int y1 = y * 2;
                 int y2 = (y * 2) + 1;
                 map [x1, y1] = (int)alphaMapData [x, y, myTextureLayer] * 10;
                 map [x1, y2] = (int)alphaMapData [x, y, myTextureLayer] * 10;
                 map [x2, y1] = (int)alphaMapData [x, y, myTextureLayer] * 10;
                 map [x2, y2] = (int)alphaMapData [x, y, myTextureLayer] * 10;
                 //if the resolution was the same we could just do the following instead: map [x, y] = (int)alphaMapData [x, y, myTextureLayer] * 10;
             }
         }
         terrainData.SetDetailLayer(0, 0, myDetailLayer, map);
     }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

Can I modify grass or details on the terrain at runtime? 2 Answers

Terrain texture with alpha? 1 Answer

baked grass? lightmapping 1 Answer

whats a good size for a standard terrain? Details, grass, trees disappear when zoomed out editing. 1 Answer

Terrain Grass texture transparancy not working 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges