Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
1
Question by Jazzer008 · Apr 24, 2013 at 04:13 PM · texture2duvheightplanetsetpixel

'Planet' height based, Texture2D setPixel performance queries.

Hello,

So I've been working on generating random meshes for planets, and then coloring those meshes based on the height of the UV map at that point. The mesh generation is relatively quick, less than a second for 40 segments down and 80 segments across. But when it comes to setting pixel colours, even a small texture size of 126x126 takes around 5 seconds to complete.

Currently my UV map stretches across the entire planet, after the mesh is fully generated I run another script with moves across the UV in a for loop using x and y values, proportionately to the texture size.

So with a texture of 126x126 the script would do a total of 15876 calculations, for each square in the texture. In each calculation, the real world position of the UV map at that point is grabbed, the distance to the center of the planet calculated and then a corresponding color is assigned to that point in the texture.

I'm wondering if anyone knows how to rapidly speed this process up, it's my first time doing it so I feel like I'm being really inefficient somewhere. I want this to be part of a game and I don't want users to have to wait more than 10 seconds for a new scene to load. I would much prefer a larger texture size as well. At the moment, 126 isn't really cutting it, as you can see.

Current textured planet

Incoming wall of code:

 var radius :float = 10.0;
 var perlinRange :float = 0.05;
 var segments :int =20;
 
 private var Planet : GameObject; 
 Planet = transform.parent.gameObject;
 
 private var textureMaxHeight =  (radius*1.0);
 private var textureMinHeight =  (radius*(1.0-perlinRange));
 
 private var defaultMaterial = Resources.Load("Materials/Generation/Terrain/PlanetMaterial") as Material;
 private var newMaterial :Material = new Material(Shader.Find("Diffuse"));
 newMaterial.color = defaultMaterial.color;
 
 private var colorDefault = newMaterial.color;
 private var PlanetTexture :Texture2D = new Texture2D(126, 126);
 
 private var worldPosition:Vector3;
 private var heightVariance:float;
 private var colorOutput:Color;
 
 private var mesh: Mesh;
 private var tris: int[];
 private var uvs: Vector2[];
 private var verts: Vector3[];
 
 function Start(){
 
   mesh = GetComponent(MeshFilter).mesh;
   tris = mesh.triangles;
   uvs = mesh.uv;
   verts = mesh.vertices;
 
         for (var yC : int = 0; yC < PlanetTexture.height; ++yC){
             for (var xC : int = 0; xC <  PlanetTexture.width; ++xC){
 
                 worldPosition = UvTo3D(Vector2((xC*1.0)/PlanetTexture.width,(yC*1.0)/PlanetTexture.height));
 
                 heightVariance = (Vector3.Distance(worldPosition,Planet.transform.position)-textureMinHeight)/
                 (textureMaxHeight-textureMinHeight);
 
                 colorOutput = colorDefault;
 
                 if( heightVariance < 0.75){
                     colorOutput.r = 0.2;
                     colorOutput.g = 0.2;
                     colorOutput.b = 0.6;
 
                 }else if( heightVariance > 0.8){
                     colorOutput.r = 0.0;
                     colorOutput.g = 0.4;
                     colorOutput.b = 0.0;
 
                 }
 
                     colorOutput.r += heightVariance/2;
                     colorOutput.g += heightVariance/2;
                     colorOutput.b += heightVariance/2;
 
 
                 PlanetTexture.SetPixel (xC, yC, colorOutput);
             }
         }
 
         PlanetTexture.Apply();
 
         renderer.material = newMaterial;
         renderer.material.mainTexture = PlanetTexture;
         renderer.material.mainTexture.wrapMode = TextureWrapMode.Clamp;
 }
 
 function UvTo3D(checkUv: Vector2): Vector3 {
   for (var i: int = 0; i < tris.length; i += 3){
     var u1: Vector2 = uvs[tris[i]]; // get the triangle UVs
     var u2: Vector2 = uvs[tris[i+1]];
     var u3: Vector2 = uvs[tris[i+2]];
     // calculate triangle area - if zero, skip it
     var a: float = Area(u1, u2, u3); if (a == 0) continue;
     // calculate barycentric coordinates of u1, u2 and u3
     // if anyone is negative, point is outside the triangle: skip it
     var a1: float = Area(u2, u3, checkUv)/a; if (a1 < 0) continue;
     var a2: float = Area(u3, u1, checkUv)/a; if (a2 < 0) continue;
     var a3: float = Area(u1, u2, checkUv)/a; if (a3 < 0) continue;
     // point inside the triangle - find mesh position by interpolation...
     var p3D: Vector3 = a1*verts[tris[i]]+a2*verts[tris[i+1]]+a3*verts[tris[i+2]];
     // and return it in world coordinates:
     return transform.TransformPoint(p3D);
   }
   // point outside any uv triangle: return Vector3.zero
   return Vector3.zero;
 }
  
 // calculate signed triangle area using a kind of "2D cross product":
 function Area(p1: Vector2, p2: Vector2, p3: Vector2): float {
   var v1: Vector2 = p1 - p3;
   var v2: Vector2 = p2 - p3;
   return (v1.x * v2.y - v1.y * v2.x)/2;
 }
Comment
Add comment · Show 3
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 Loius · Apr 24, 2013 at 04:40 PM 0
Share

Are you accessing mesh.anything every cycle? $$anonymous$$esh.anything that returns an array is actually copying the array before giving it to you, so you need to cache that, use your cache, then reassign it.

Assu$$anonymous$$g that's not it, what's your coloring code look like?

avatar image Jazzer008 · Apr 24, 2013 at 04:55 PM 0
Share

Well actually my UvTo3D function does grab the mesh every time. I'll throw that in the start function, brb.

avatar image Jazzer008 · Apr 24, 2013 at 04:58 PM 0
Share

Ok, so accessing mesh only once. Not really much improvement in the speed. I'll show my code, editing it into the bottom of the main post.

1 Reply

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

Answer by whydoidoit · Apr 24, 2013 at 05:11 PM

The fastest way would be to allocate a Color32[] the width*height of the texture, set those values using (y * width) + x (or even better, just an incrementing index), then use SetPixels32 to assign the array just before you Apply.

Comment
Add comment · Show 14 · 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 whydoidoit · Apr 24, 2013 at 05:14 PM 0
Share

That said that's a huge loop over the triangles for each point. Need to think about how to stop that.

avatar image whydoidoit · Apr 24, 2013 at 05:22 PM 0
Share

Yep it's probably the 24m barycentric calculations (on average) that cause the slow down...

How about calculating the centroid of each triangle and doing a nearest triangle calculation.

You could do something like this; turning the problem on its head:

  • Iterate through the triangles

  • For each triangle calculate the UV point that falls within it (closest to its centroid), fill in a 2d array with this information

  • Iterate through the UVs

  • Lookup the triangle that is closest from the array

  • Do the barycentric calculation and work out the height for the current point.

avatar image Jazzer008 · Apr 24, 2013 at 05:23 PM 0
Share

I haven't encountered much use of the Color32 system prior. The function would create an array of colors in a better performance format? And I would have to choose a color from that array based on the height I receive?

avatar image whydoidoit · Apr 24, 2013 at 05:25 PM 0
Share

You could make a perfect version by having that array be a list of all the triangles that are near the uv - so calculate the uv of each point in the triangle and add it to the list at the location. Then you only have a few triangles to test for a particular UV. Better still you might be able to do that calculation on the first pass with just a replacement if you find a better candidate triangle.

avatar image Jazzer008 · Apr 24, 2013 at 05:27 PM 0
Share

How would that loop perform any quicker? The height changes over each triangle and I need to calculate that height to assign a color. If I just get the height of the center of the triangle, then the entire triangle would be the same color.

I don't think I'm understanding what your trying to get at.

Show more comments

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

14 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

Related Questions

Finding a pixel in an images texture by raycast 0 Answers

Finding size of texture GUI 0 Answers

Combine 2 textures of different sizes at specific location 1 Answer

Translate a pixel using SetPixel on a Texture2D? 1 Answer

Setpixels creates gradient texture instead of raw colored pixels 1 Answer


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