Unity Community


Results 1 to 18 of 18

  1. Location
    Paris
    Posts
    3,730

    Super fast method to create 1 texture from multiple textures

    Hello,

    I don't know yet if RenderTextures work for iPhones, but it seems to work for iPad (and Android) since U3.

    So I found a way to create a texture from superposition of tons of other textures (special thanks to Dreamora for suggesting GUITextures/Readpixels).

    It can be super useful for clothes texture generation, for example.


    Update : I finally posted the script down the page : Link

    What you need to create :
    - a camera prefab that culls nothing else that could be rendered outside of this script. Only attach a Gui Layer to it, and set its depth mask to "don't clear".
    - a GUITexture prefab. Put it on the same culling layer than the Camera above. Set its Scale transforms to zero, as explained in the Unity docs.

    Now by code in a script, whenever you want to create your texture :
    - create a variable containing the targetted dimensions of your texture
    - create a new RenderTexture. Dimensions are the var above.
    - instantiate your camera & GUITexture prefabs at zero position
    - set camera's targetTexture to the freshly created RenderTexture
    - Initialize your RTexture with _RenderTextureVar.Create() function (see the docs).
    - Now, each time you want to add a texture in your composition, just :
    a) set your GUITexture.texture to whatever Resources stored Texture2D (or anywhere you want to take it from, ingame, web, etc).
    b) launch a camera.Render() on your Cam instance.
    (or launch a WaitForEndOfFrame(), but it's slower obviously)

    When you've added all the textures to your composition :
    - Launch a RenderTexture.active = _yourRecentlyCreatedRTexture (important place, doesn't work if put before GUITexture.texture assign)
    - create your final texture Texture2D container(formatted as RGB24/ARGB, as explained in the docs).
    - perform a _finalTextureContainer.ReadPixels() (with your texture dimensions as parameter, see docs).
    - perform a RenderTexture.active = null
    - perform a _finalTextureContainer.Apply() to create mipmaps.

    Destroy your camera, GUITexture pefabs and your RenderTexture.

    Et voilą.

    Advantages over GetPixels methods :
    - it's 10+ times faster. With GetPixels/SetPixels/Alpha Lerping operations, I had a calculation time of 0.30 seconds on my home PC, with 11 x 512x512 alpha textures. With this method, I ended with times from 0.02 to 0.01. So for mobile devices, expect to multiply it by higher numbers.
    - Operations are GPU side, which now prevent any interference with CPU operations, like animation loading.
    - Biggest change for me : you don't need ARGB huge textures anymore. Yes, you can keep your compression settings (except for the computed final texture, indeed). You also don't need any more isReadable state for your source textures. Device memory says "oh god thank you".
    - You can perform prerendered visual effect operations on your final texture, by RenderTexture manipulation, like tinting, photo grain, decals, etc. Just add a prerendered effect image on top of your textures layers.
    - You can easily resize your final texture dimensions by changing the dimensions variable. No Resize operation needed.
    This can be useful for adjusting your texture size to the device memory, for example.

    Hints & Tips :
    - There seems to be a bug when you cast camera.Render() outside of Unity basic loops (Start, Update, etc), an assertion saying something lime "screenViewCoords[0] < 0 || screenViewCoords[3] < 0" (Sorry I don't recall exactly).
    So your best use is to create the whole operation into a MonoBehaviour script that you attach to an object, and which self destroys at the the end of operations.
    - Placing your layered bitmaps by script can be hazardous, I suggest you place them directly into your source texture, putting all of them at fixed dimensions, with alpha zero pixels where there is no colors. Then you will only have to place layered bitmaps to zero position.

    Enjoy
    Last edited by n0mad; 02-26-2013 at 11:55 AM.

  2. Super Moderator
    Location
    Great Britain
    Posts
    9,661
    This could be adopted for resizing a texture as well couldn't it?


  3. Location
    Nebraska
    Posts
    378
    create a new RenderTexture. Dimensions are the var above.
    "RenderTexture class is only available in Unity Pro."
    http://unity3d.com/support/documenta...erTexture.html

    This is definitely interesting, but only pro-versions can do this correct?

  4. Super Moderator
    Location
    Great Britain
    Posts
    9,661
    Yes only pro can render to texture.


  5. Location
    Paris
    Posts
    3,730
    Quote Originally Posted by hippocoder View Post
    This could be adopted for resizing a texture as well couldn't it?
    Exactly
    You can resize at will for your final texture to fit any device memory.

    Quote Originally Posted by windexglow View Post
    "RenderTexture class is only available in Unity Pro."
    http://unity3d.com/support/documenta...erTexture.html

    This is definitely interesting, but only pro-versions can do this correct?
    Yep, Pro only. There are a lot of performance related tools and tricks that are pro only, it really worthes the money.


  6. Location
    Paris
    Posts
    3,730
    Oh I forgot, you can do it without RenderTextures (so with Free), by still using Readpixels on the screen instead of RT.

    But it's not very handy, as you won't be able to hide your texture works. Users will see big textures on screen for the calculation time.

    Not very classy, but doable without pro.


  7. Posts
    70
    Is there a good reason, why I see only chaos on the screen instead of 1 single button in the lower left corner, which I added for testing the procedure?

    I have Unity Pro 3.1 by the way and Windows XP
    Attached Images  


  8. Location
    Paris
    Posts
    3,730
    Quote Originally Posted by vollnull View Post
    Is there a good reason, why I see only chaos on the screen instead of 1 single button in the lower left corner, which I added for testing the procedure?

    I have Unity Pro 3.1 by the way and Windows XP
    Sorry for the late answer :

    Yes, the reason is that if your camera depth flag is set to "don't clear", your render texture will be added every non-transparent zone it sees at every rendering frame, without clearing what it already had written. Think of "don't clear" as an infinite additive method.
    Here you seem to have put your culling camera mask on layers that were already displaying something else than your button.

    In this procedure, "don't clear" is used to make additive layers stack on each other into a single bitmap without having to save this bitmap on every new stack added. Big performance gain.
    But if you're not setting your rendertexture's camera culling mask to a totally independant layer, you may witness this kind of mess up. Create a layer apart from all the others for this whole work, unless you want to use something that's been rendered before your script.
    Last edited by n0mad; 12-15-2010 at 12:48 PM.


  9. Posts
    70
    Thanks for your answer.
    I double checked the cameras culling mask and it is set to a special layer which I created only for GUI rendering. I get a weird result anyway. If I set the camera depth to solid color, and choose {0,0,0,0} as color, all is working as expected. But instead of one GUITexture I have several of them - one for each button - and I do a render call once at the end. Is that a good idea? It works well for a few buttons, but if I klick one of them, which causes some additional buttons to become visible, they disappear all.


  10. Location
    Paris
    Posts
    3,730
    Quote Originally Posted by vollnull View Post
    Thanks for your answer.
    I double checked the cameras culling mask and it is set to a special layer which I created only for GUI rendering. I get a weird result anyway. If I set the camera depth to solid color, and choose {0,0,0,0} as color, all is working as expected. But instead of one GUITexture I have several of them - one for each button - and I do a render call once at the end. Is that a good idea? It works well for a few buttons, but if I klick one of them, which causes some additional buttons to become visible, they disappear all.
    Several GUITextures will lose the memory benefit of the method, as you will load as much memory as you have different bitmaps. This is doable, but beware of huge memory leaps on mobile platforms, which could cause big loading slowdowns as mem goes up.
    About your weird result, check out if you put the "RenderTexture.active = _yourRecentlyCreatedRTexture" at the right place, as mentionned in the first post, or it will never snapshot your GUITextures.

    Otherway, I admit I don't have enough time to provide full support to this procedure, but if done step by step it does work. After that, I suggest to use the good ol' trial-and-error technique to reach desired result

    Good luck


  11. Posts
    1
    Hi
    Nomad i'm traing to use your method for baking blood on the ground in my topdown shooter, so far not good all i get is a crap. Could you post your script here? Please


  12. Location
    Paris
    Posts
    3,730
    Been a while since I created this topic ! But yeah, I realize I could have easily written down a more generalized version of the script in here ...
    So, after that long, here it is !


    Code:  
    1. public static Texture2D CreateLayeredTexture() {
    2. //Just a camera with a GUILayer component, ortographic, size 100,
    3. //Clear Flags set to "Don't clear"
    4.         GameObject _TCam = (GameObject) Resources.Load("TextureCam");
    5.  
    6.  // your texture size
    7.         int _texSize = 512;
    8.         RenderTexture _targetTex = new RenderTexture(_texSize, _texSize, 24, RenderTextureFormat.ARGB32);
    9.         _targetTex.isPowerOfTwo = true;
    10.         _TCam.camera.targetTexture = _targetTex;
    11.         _targetTex.Create();
    12.  
    13. //Another object with only a GUITexture component, pixel inset width = 320, height = 320
    14.         GameObject _GUITexCombiner = (GameObject) Resources.Load("TextureCombiner");
    15.  
    16.          _GUITexCombiner.transform.localScale = new Vector3(0f, 0f, 0f);
    17.          _GUITexCombiner.transform.position = new Vector3(0f, 0f, 0f);
    18.          _GUITexCombiner.guiTexture.pixelInset = new Rect(0, 0, _texSize, _texSize);
    19.  
    20. //Tex 1 :
    21.          _GUITexCombiner.guiTexture.texture = (Texture2D)Resources.Load("Texture1");
    22.         _TCam.camera.Render();
    23.         Resources.UnloadAsset(_GUITexCombiner.guiTexture.texture);
    24.  
    25. //Tex2 :
    26.          _GUITexCombiner.guiTexture.texture = (Texture2D)Resources.Load("Texture2");
    27.         _TCam.camera.Render();
    28.         Resources.UnloadAsset(_GUITexCombiner.guiTexture.texture);
    29.  
    30.         //etc, etc .....
    31.  
    32.  
    33.         Texture2D _newTex = new Texture2D(_texSize, _texSize, TextureFormat.RGB24, false);
    34.         RenderTexture.active = _targetTex;
    35.         _newTex.ReadPixels(new Rect(0, 0, _texSize, _texSize), 0, 0);
    36.         _newTex.Apply(true);
    37.  
    38.         RenderTexture.active = null;
    39.         Object.Destroy(_GUITexCombiner);
    40.         Object.Destroy(_TCam);
    41.         _targetTex.Release();
    42.  
    43.         return _newTex;
    44.     }
    Last edited by n0mad; 03-02-2013 at 03:55 AM.


  13. Location
    Rio de Janeiro, Brazil
    Posts
    1,021
    Quote Originally Posted by n0mad View Post
    Been a while since I created this topic ! But yeah, I realize I could have easily written down a more generalized version of the script in here ...
    So, after that long, here it is !


    Code:  
    1. public static Texture2D CreateLayeredTexture() {
    2. //Just a camera with a GUILayer component, ortographic, size 100
    3.         GameObject _TCam = (GameObject) Resources.Load("TextureCam");
    4.  
    5.  // your texture size
    6.         int _texSize = 512;
    7.         RenderTexture _targetTex = new RenderTexture(_texSize, _texSize, 24, RenderTextureFormat.ARGB32);
    8.         _targetTex.isPowerOfTwo = true;
    9.         _TCam.camera.targetTexture = _targetTex;
    10.         _targetTex.Create();
    11.  
    12. //Another object with only a GUITexture component, pixel inset width = 320, height = 320
    13.         GameObject _TT1 = (GameObject) Resources.Load("TextureCombiner");
    14.  
    15.         _TT1.transform.localScale = new Vector3(0f, 0f, 0f);
    16.         _TT1.transform.position = new Vector3(0f, 0f, 0f);
    17.         _TT1.guiTexture.pixelInset = new Rect(0, 0, _texSize, _texSize);
    18.  
    19. //Tex 1 :
    20.         _TT1.guiTexture.texture = (Texture2D)Resources.Load("Texture1");
    21.         _TCam.camera.Render();
    22.         Resources.UnloadAsset(_TT1.guiTexture.texture);
    23.  
    24. //Tex2 :
    25.         _TT1.guiTexture.texture = (Texture2D)Resources.Load("Texture2");
    26.         _TCam.camera.Render();
    27.         Resources.UnloadAsset(_TT1.guiTexture.texture);
    28.  
    29.         //etc, etc .....
    30.  
    31.  
    32.         Texture2D _newTex = new Texture2D(_texSize, _texSize, TextureFormat.RGB24, false);
    33.         RenderTexture.active = _targetTex;
    34.         _newTex.ReadPixels(new Rect(0, 0, _texSize, _texSize), 0, 0);
    35.         _newTex.Apply(true);
    36.  
    37.         RenderTexture.active = null
    38.         Object.Destroy(_TT1);
    39.         Object.Destroy(_TCam);
    40.         _targetTex.Release();
    41.  
    42.         return _newTex;
    43.     }
    Hi there =)
    Sent you a pm. I've been working on something like this for http://forum.unity3d.com/threads/153...ter-generation
    btw, I think there's a " ; " missing at 37

    See ya!


  14. Location
    Paris
    Posts
    3,730
    Quote Originally Posted by FernandoRibeiro View Post
    Hi there =)
    Sent you a pm. I've been working on something like this for http://forum.unity3d.com/threads/153...ter-generation
    btw, I think there's a " ; " missing at 37

    See ya!
    Thanks, I corrected the semicolon, and also put more explicit var names


  15. Location
    Rio de Janeiro, Brazil
    Posts
    1,021
    Quote Originally Posted by n0mad View Post
    Thanks, I corrected the semicolon, and also put more explicit var names
    Great = D
    I really loved the "don't clear" depth flag concept, it's really very powerful in this solution!
    I'm working on the integration of this solution on UMA project, timing couldn't be better =D


  16. Location
    Paris
    Posts
    3,730
    Quote Originally Posted by FernandoRibeiro View Post
    Great = D
    I really loved the "don't clear" depth flag concept, it's really very powerful in this solution!
    I'm working on the integration of this solution on UMA project, timing couldn't be better =D
    Ah crap, I forgot to specify this "Don't clear" property in the script ! Thanks for reminding, changing it now
    (was in the OP description but not in the script)

    I'm glad this will come to good use in your project !
    Cheers


  17. Location
    Melbourne
    Posts
    359
    Hi there

    I am using this technique for my character clothing. I think it is great! Cheers.

    So you are creating a camera, and GUITexture as prefabs and locating them in the Assets/Resources folder? I can load them. And even my first texture - but when I hit "Resources.UnloadAsset(_GUITexCombiner.guiTexture. texture);" I CRASH! And then the whole process becomes unstable.

    What could be wrong?


  18. Location
    Paris
    Posts
    3,730
    That's a very strange crash tbh ... sounds like a memory corruption or something ?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •