Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 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
1
Question by galbix · Apr 30, 2020 at 01:56 AM · shadersoptimizationtexturessetpixelsdepthmask

Punching holes through a texture and making them regenerate back again in an efficient way

I'm working on a prototype where the user can use the mouse to punch holes through a texture, making this texture see-through in that area for a certain amount of time. After that time, the hole will "regenerate" back again, effectively just increasing the alpha value back to 1 until is opaque. I already have all this working, but I'm afraid my current implementation is not exactly good in terms of performance, and is definitely not suitable for big textures. This is what I have working right now, using small textures (the hair and the head are separate textures):


alt text


What I'm doing is using a depth mask shader and drawing the holes (black circles) in the second texture with every mouse click. This works perfectly well, but then I need to regenerate the holes, so what i do is (and I totally realize this is a really hacky approach) use the red channel in the color of each pixel to determine if that pixel should lerp back to opaque (go back to an alpha value of 1). As I said, this kind of works for small textures, but as soon as I try it on a big one, it is just unable to handle that amount of pixels at once. I tried to summarize the code of my implementation here:


 public class TextureHoles : MonoBehaviour
 {
     public Texture2D sourceTexture;
     public Camera sceneCamera;
     public LayerMask targetLayerMask;
 
     public Color drawColor;
     public float circleRadiusSize;
 
     private Texture2D currentTexture;
 
     private Renderer rend;
     private MeshCollider meshCollider;
 
     private Color[] colors;
     private Color[] targetColors;
 
     private List<Hole> holes = new List<Hole>();
     private float redChannelValue = 0f;
     private const float HOLES_MAX_TIME = 3f;
 
     [System.Serializable]
     public class Hole
     {
         public Hole(Color _color)
         {
             color = _color;
             timer = 0f;
         }
 
         public void Run()
         {
             timer += Time.deltaTime;
         }
 
         public Color32 color;
         public float timer;
     }
 
     private void Start()
     {
         // create copy of source tex
         currentTexture = new Texture2D(sourceTexture.width, sourceTexture.height, TextureFormat.RGBA32, false);
         currentTexture.SetPixels(sourceTexture.GetPixels());
         currentTexture.Apply();
 
         rend.material.SetTexture("_Mask", currentTexture);
 
         targetColors = currentTexture.GetPixels();
     }
 
     private void Update()
     {
         if(Input.GetMouseButtonDown(0))
         {
             CutHair();
         }
 
         for(int i = 0; i < holes.Count; i++)
         {
             RecoverHair(holes[i]);
         }
     }
 
     public void CutHair()
     {
         RaycastHit hit;
 
         if(Physics.Raycast(Cursor.Instance.GetRayInitialPos(), Vector3.forward, out hit, Mathf.Infinity, targetLayerMask))
         {
             Vector2 uv;
 
             uv.x = (hit.point.x - hit.collider.bounds.min.x) / hit.collider.bounds.size.x;
             uv.y = (hit.point.y - hit.collider.bounds.min.y) / hit.collider.bounds.size.y;
 
             Vector2 coord = new Vector2((int)(uv.x * currentTexture.width), (int)(uv.y * currentTexture.height));
 
             int circleRadius = (int)(Cursor.Instance.GetCircleSize() * circleRadiusSize);
 
             // we use the red channel value to identify which color we should lerp back to opaque
             redChannelValue += .03f;
             Color holeColor = new Color(redChannelValue, 0f, 0f, 0f);
 
             currentTexture.DrawCircle(holeColor, (int)coord.x, (int)coord.y, circleRadius);
             currentTexture.Apply(true);
 
             holes.Add(new Hole(holeColor));
         }
     }
 
     private void RecoverHair(Hole hole)
     {   
         if(hole.timer >= HOLES_MAX_TIME) return;
 
         hole.Run();
 
         colors = currentTexture.GetPixels();
 
         // go through all colors in the texture
         for(int i = 0; i < colors.Length; i++)
         {
             if(colors[i].r == 1) continue;  // dont touch colors with full red channel value
 
             if(((Color32)colors[i]).r == hole.color.r)
             {
                 // lerp alpha value of colors with matching red channel value
                 float newAlpha = Mathf.Lerp(hole.color.a, targetColors[i].a, hole.timer / HOLES_MAX_TIME);
                 colors[i] = colors[i].WithA(newAlpha);
 
                 int y = i / currentTexture.width;
                 int x = i - (y * currentTexture.width);
                 currentTexture.SetPixel(x, y, colors[i]);
             }
         }
 
         currentTexture.Apply();
     }
 }
 
 public static class TextureExtensions
 {
     public static Texture2D DrawCircle(this Texture2D tex, Color32 color, int x, int y, int radius = 3)
     {
         float rSquared = radius * radius;
 
         for (int u = x - radius; u < x + radius + 1; u++)
             for (int v = y - radius; v < y + radius + 1; v++)
                 if ((x - u) * (x - u) + (y - v) * (y - v) < rSquared)
                     tex.SetPixel(u, v, color);
 
         return tex;
     }
 }


I know I'm using GetPixels and SetPixels a lot, and that is probably what is draining all the resources from the CPU and giving me such bad performance in bigger textures, but I'm at a bit of a lost right now in terms of how should I approach optimizing this algorithm. And this is my main question really, what method can I use to regenerate (lerp alpha value) every individual hole at its own pace in a performant way? Every suggestion or hint on a potential approach is appreciated, thank you.

final.gif (505.5 kB)
Comment
Add comment · Show 1
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 toddisarockstar · Apr 30, 2020 at 06:31 AM 0
Share

seems you got a good understanding of 2d program$$anonymous$$g. you might want to look into custom shader program$$anonymous$$g. it's a different language but you would figure it out quick enough. in a shader script you can do a little more. it would be possible to use a lesser resolution "map" texture to decide where a higher resolution image would be displayed.

0 Replies

· Add your reply
  • Sort: 

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

141 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 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 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 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 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

Batch texture sampling in shader? 1 Answer

Performance Question: Baked textures vs Procedural shaders 0 Answers

Performance issue. Optimize or change SetPixel to allow for painting specific areas of a texture. 1 Answer

Graphics Performance Question 2 Answers

Complicated shader problem 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