Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • 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
0
Question by Greenie · Jan 12, 2015 at 09:50 PM · loopfreezefor-loop

How to handle long loops

Hi there

I am currently using a for loop with a fairly large amount of code in it to generate procedural terrain. Using a 65 x 65 size terrain it is OK and works fine with about 5460 iterations. However when i make that terrain 129x129 unity stops responding and it will never end (about 20000 iterations). I hope to use this code for terrains as large as 1025x1025.

How can i make a for loop more efficient? Is there a method of making it either loop faster, or keep control so it doesn't overload the pc and crash unity.

Cheers, Greenie

Comment
Add comment · Show 7
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 CHPedersen · Jan 12, 2015 at 09:59 PM 0
Share

Impossible to really tell without seeing how that loop works. The number of iterations isn't the issue, it's what it DOES for each iteration.

avatar image Greenie · Jan 12, 2015 at 10:01 PM 0
Share

Here is the loop, it does a fair bit

 for(var p = 0; p<=steps-1; p++){
     //print(width);
         //diamond
     heights[xAnchor+width/2,yAnchor+height/2] = (((terrainDat.GetHeight(xAnchor,yAnchor)+terrainDat.GetHeight(xAnchor+width,yAnchor)+terrainDat.GetHeight(xAnchor,yAnchor+height)+terrainDat.GetHeight(xAnchor+width,yAnchor+height))/4.0)-this.gameObject.transform.position.x)/(terrainDat.size.x)+ Random.Range($$anonymous$$Noise,maxNoise);
     terrainDat.SetHeights(0,0,heights);
         //square
     heights[xAnchor+width/2,yAnchor] = ((((terrainDat.GetHeight(xAnchor,yAnchor)+terrainDat.GetHeight(xAnchor+width,yAnchor))/2.0)-this.gameObject.transform.position.x)/(terrainDat.size.x))+ Random.Range($$anonymous$$Noise,maxNoise);
     terrainDat.SetHeights(0,0,heights);
     heights[xAnchor,yAnchor+height/2] = ((((terrainDat.GetHeight(xAnchor,yAnchor)+terrainDat.GetHeight(xAnchor,yAnchor+height))/2.0)-this.gameObject.transform.position.x)/(terrainDat.size.x))+ Random.Range($$anonymous$$Noise,maxNoise);
     terrainDat.SetHeights(0,0,heights);
     heights[xAnchor+width/2,height] = ((((terrainDat.GetHeight(xAnchor+width,yAnchor+height)+terrainDat.GetHeight(xAnchor+width,yAnchor))/2.0)-this.gameObject.transform.position.x)/(terrainDat.size.x))+ Random.Range($$anonymous$$Noise,maxNoise);
     terrainDat.SetHeights(0,0,heights);
     heights[width,yAnchor+height/2] = ((((terrainDat.GetHeight(xAnchor+width,yAnchor+height)+terrainDat.GetHeight(xAnchor,yAnchor+height))/2.0)-this.gameObject.transform.position.x)/(terrainDat.size.x))+ Random.Range($$anonymous$$Noise,maxNoise);
     terrainDat.SetHeights(0,0,heights);
         //check next
     if(xAnchor+width >= origW && yAnchor+height >=origH){
         //print("y");
         width = width/2;
         height = height/2;
         step = width;
         xAnchor=0;
         yAnchor=0;
     }
     else{
         //print("n");
         
         if(xAnchor+width >=origW){
             yAnchor = yAnchor + height;
             xAnchor = 0;
         }
         else{xAnchor = xAnchor + width;}
     }
     }
avatar image CHPedersen · Jan 12, 2015 at 10:10 PM 0
Share

All the calculations aren't the issue, that's fine. 20k iterations of those should be okay. I'm not familiar with terrains, but the calls to setheights could be trouble. Does that method access mesh data? If it does reads and writes to data on large meshes, it will generate huge memory overhead, which could cripple the loop.

avatar image Greenie · Jan 12, 2015 at 10:15 PM 0
Share

It accesses terraindata which I assume is the same thing just a fancy name for unity terrain. Is there any way I could make it more efficient?

avatar image CHPedersen · Jan 13, 2015 at 07:33 AM 0
Share

Sorry I went awol yesterday - I was on my way to bed. ;) $$anonymous$$y point was pretty much identical to Owen Reynold's reply below. I think it is, as I feared, because of the SetHeights methods.

Like I said, I don't have any experience with Unity's terrains, but a tentative guess is that they are a wrapper around either the $$anonymous$$esh class or a Texture2D for storing height data. I think the exposed methods such as SetHeights manipulate either the vertices of a $$anonymous$$esh or the pixels of a height map texture in ways that make sense for a terrain.

For a $$anonymous$$esh, a common mistake (or oversight, at least) is liberal use of those of the $$anonymous$$esh's properties that access its data arrays, that is, its .vertices, .uvs, .normals, and so on. The trick with these is that they do not actually return a reference to the array that stores the data, they ins$$anonymous$$d return a fresh copy of the entire contents of the array that stores all the data. This makes each individual access to its data highly expensive and means it must be done sparsely.

For a Texture2D, the common mistake is liberal use of SetPixels and Texture2D.Apply, the latter of which is the worst because it has to transfer the updated texture data over the bus from main memory to video memory. When textures are large, they can constitute quite a lot of data, which, like $$anonymous$$esh data, means its access is expensive and must be done sparsely.

Now, your code does not access and set this data sparsely. :) And that's your problem. You call SetHeights very liberally; in fact you call it multiple times with individual updates inside each iteration of your loop. I think the most significant optimization you could do with this code is to perform your calculations on a separate, static array of height data you manage yourself, and then, AFTER all height calculations are complete, call SetHeights on the actual TerrainData ONCE, and ONCE ONLY, with the finished data.

Calculations which take place on static arrays solely in main memory are incredibly fast. You're getting killed by bus bandwidth right now.

Show more comments

3 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Owen-Reynolds · Jan 13, 2015 at 05:24 AM

What do you think all those terrainDat.SetHeights(0,0,heights); lines are doing? You have one after each time you change a height value, so maybe you think they copy that one value into Unity's heightmap? But if they did that, wouldn't it look more like (x,y,heights[x,y])?

The actual line looks more like it takes your entire array heights -- after all, it's SetHeights, plural -- and copies all 10,000+ values to the terrain, starting at xBase and yBase. If that was the case, doing it over and over and over and over again, would be incredibly slow and pointless.

Comment
Add comment · Show 2 · 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 Greenie · Jan 13, 2015 at 06:24 AM 0
Share

So I should be going "terrainDat.SetHeights(0,0,heights[x,y]);"?

avatar image Greenie · Jan 13, 2015 at 11:01 AM 0
Share

Ok just got home from work and moved the set height command out of the loop. Worked like a dream. Also thanks to Juice-Tin for the idea to pull from a 2d array ins$$anonymous$$d of using getHeight. Terrains are generating in a couple of seconds and looking good!

avatar image
1

Answer by Juice-Tin · Jan 13, 2015 at 07:40 AM

Method 1: Surely your player can't see the entire map at once?

It could be possible to first create a small section that the player spawns in, then overtime continue to slowly modify the terrain outwards as they play.

Method 2: Alternatively, "terrainDat.GetHeight" should be completely removed. If you're creating the terrain yourself, then you have no need to access the terrain's properties. Instead create the entire terrain data inside a simple 2D array, then loop through it any only set the terrain. If you need to get info, pull it from the 2D array you made, not the actual terrain itself.

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 Greenie · Jan 13, 2015 at 11:38 AM 0
Share

Thanks mate, using this and Owen Reynolds i got it working pretty good :)

avatar image
0

Answer by Kiwasi · Jan 12, 2015 at 11:21 PM

As a cheap fix you could make is a coroutine and throw in a yield return null every few iterations.

Another alternative would be to use smaller chunks of terrain, then stitch them together.

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 Greenie · Jan 12, 2015 at 11:26 PM 0
Share

Yeah what iv'e done is throw in coroutine that yields until fixed update every 50 iterations. Doesn't freeze unity but takes a few $$anonymous$$utes to do a 128x128 terrain. I'm currently experimenting with other terrain gen formulas.

Would stitching them together be faster? surely this would be the same thing just more spread out?

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.

Follow this Question

Answers Answers and Comments

29 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Help! Unsaved work stuck in frozen unity, believed to be from infinite loop. What can i do? 2 Answers

Unity crashes when using while 2 Answers

How to deactivate all GameObject in a array, except last one 4 Answers

Imported FBX Animation plays, freezes, then plays again. 2 Answers

'brake' statement makes Unity hang ? 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