Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only. On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live. Read our full announcement for more information and let us know if you have any questions.

Question Create Image from rendertexture at runtime with prefab

Discussion in 'Editor & General Support' started by Pierre-Marie, Sep 6, 2022.

  1. Pierre-Marie

    Pierre-Marie

    Joined:
    Aug 3, 2015
    Posts:
    59
    Hello,

    I have a problem I can't figure it out how to solve it.

    I have a crafting system where the player can chose the mesh he want.
    I have a classe playerdata with a list of unlock string wich are the unlock mesh name.

    I want to create at runtime Icon of the mesh by instanciate the mesh and "take a picture".
    I have a panel wich instanciate Item for every unlock mesh.
    Thoses Item prefab call a icon manager to get a sprite :


    Code (CSharp):
    1. public void GetIconSimpleForm(string formName, Material Mat,bool isWeapon, string type , Action<Sprite> callBackSprite)
    2.     {
    3.         callbackSprite = callBackSprite;
    4.         GameObject IconMaker = Instantiate(IconMakerPrefab, this.transform,false) as GameObject;
    5.  
    6.         IconMaker.transform.localPosition = CurrentPOS;
    7.         CurrentPOS.y += 100;
    8.        
    9.         iconScript = IconMaker.GetComponent<IconMakerScript>();
    10.         iconScript.InstanciateMesh(formName, isWeapon, type, callBackSprite);
    11.         iconScript.SetMaterial(Mat);
    12.     }
    those item call the manager with a callback methode, this methode is call after the camera render.

    for each "icon demande" the manager instanciate another prefab ( "IconMakerPrefab") , wich is a mesh + a camera + a light source.

    this prefab instanciate the mesh, move the camera corresponding to the mesh type, an render the camera view on a new texture

    Code (CSharp):
    1. public void InstanciateMesh(string meshName, bool isWeapon, string type,  Action<Sprite> callbacksprite)
    2.     {
    3.         meshname = meshName;
    4.         CallbackIcon = callbacksprite;
    5.         CalbbackLoad = true;
    6.         string path = "";
    7.         if (isWeapon)
    8.         {
    9.             path = "PrefabsIcons/Weapons/" + meshName + "_Static";
    10.         }
    11.         else
    12.         {
    13.             path = "PrefabsIcons/Gears/" + meshName + "_Static";
    14.         }
    15.         ObjectDisplay = Instantiate(Resources.Load(path, typeof(GameObject)), this.transform, false) as GameObject;
    16.  
    17.         ObjectDisplay.transform.localEulerAngles = ROT;
    18.         switch (type.ToLower())
    19.         {
    20.             case "head":
    21.                 ObjectDisplay.transform.localPosition = HeadPOS;
    22.                 camera.orthographicSize = HeadSIZE/2;
    23.                 break;
    24.             case "torso":
    25.                 ObjectDisplay.transform.localPosition = TorsoPOS;
    26.                 camera.orthographicSize = TorsoSIZE / 2;
    27.                 break;
    28.             case "upperright":
    29.                 ObjectDisplay.transform.localPosition = UpperRightPOS;
    30.                 camera.orthographicSize = UpperRightSIZE / 2;
    31.                 break;
    32.             case "upperleft":
    33.                 ObjectDisplay.transform.localPosition = UpperLeftPOS;
    34.                 camera.orthographicSize = UpperLeftSIZE / 2;
    35.                 break;
    36.             case "lowerright":
    37.                 ObjectDisplay.transform.localPosition = LowerRightPOS;
    38.                 camera.orthographicSize = LowerRightSIZE / 2;
    39.                 break;
    40.             case "lowerleft":
    41.                 ObjectDisplay.transform.localPosition = LowerLeftPOS;
    42.                 camera.orthographicSize = LowerLeftSIZE / 2;
    43.                 break;
    44.             case "handright":
    45.                 ObjectDisplay.transform.localPosition = HandRightPOS;
    46.                 camera.orthographicSize = HandRightSIZE / 2;
    47.                 break;
    48.             case "handleft":
    49.                 ObjectDisplay.transform.localPosition = HandLeftPOS;
    50.                 camera.orthographicSize = HandLeftSIZE / 2;
    51.                 break;
    52.             case "legsright":
    53.                 ObjectDisplay.transform.localPosition = LegsRightPOS;
    54.                 camera.orthographicSize = LegsRightSIZE / 2;
    55.                 break;
    56.             case "legsleft":
    57.                 ObjectDisplay.transform.localPosition = LegsLeftPOS;
    58.                 camera.orthographicSize = LegsLeftSIZE / 2;
    59.                 break;
    60.             case "hips":
    61.                 ObjectDisplay.transform.localPosition = HipsPOS;
    62.                 camera.orthographicSize = HipsSIZE / 2;
    63.                 break;
    64.             case "shoulderleft":
    65.                 ObjectDisplay.transform.localPosition = ShoulderLeftPOS;
    66.                 camera.orthographicSize = ShoulderLeftSIZE / 2;
    67.                 break;
    68.             case "shoulderright":
    69.                 ObjectDisplay.transform.localPosition = ShoulderRightPOS;
    70.                 camera.orthographicSize = ShoulderRightSIZE / 2;
    71.                 break;
    72.         }
    73.         associatedTexture = new RenderTexture(OriginaleTexture);
    74.         camera.targetTexture = associatedTexture;
    75.         associatedTexture.name = meshname;
    76.  
    77.  
    78.     }
    this script also wait the camera to render to execute the call back methode :


    Code (CSharp):
    1. void OnEnable()
    2.     {
    3.         RenderPipelineManager.endCameraRendering += RenderPipelineManager_endCameraRendering;
    4.     }
    5.     void OnDisable()
    6.     {
    7.         RenderPipelineManager.endCameraRendering -= RenderPipelineManager_endCameraRendering;
    8.     }
    9.     private void RenderPipelineManager_endCameraRendering(ScriptableRenderContext context, Camera camera)
    10.     {
    11.         if (CalbbackLoad && !CallBackDone)
    12.         {
    13.             CallBackMethode();
    14.         }
    15.     }
    the call back methode create a sprite from the camera targetTexture :

    Code (CSharp):
    1. public void CallBackMethode ()
    2.     {
    3.         //camera.Render();
    4.         Texture2D texture = new Texture2D(associatedTexture.width, associatedTexture.height);
    5.         Rect rect = new Rect(0, 0, associatedTexture.width, associatedTexture.height);
    6.         var oldRt = RenderTexture.active;
    7.         RenderTexture.active = associatedTexture;
    8.  
    9.  
    10.         texture.ReadPixels(rect, 0, 0);
    11.         texture.Apply();
    12.  
    13.         RenderTexture.active = oldRt;
    14.         Sprite sprite = Sprite.Create(texture, rect, Vector2.zero);
    15.         sprite.name = meshname;
    16.         CallBackDone = true;
    17.         CallbackIcon(sprite);
    18.  
    19.     }
    And call back the item with his new sripte.

    at the next frame the 'iconmaker" prefab is destroy:


    Code (CSharp):
    1.  private void Update()
    2.     {
    3.         if (CallBackDone)
    4.         {
    5.             Destroy(this.gameObject);
    6.         }
    7.     }
    But at the end the sprite is a blank one.
    The textures are good but the sprite are not.

    When I uncomment Camera.render(); it's crash but before that my sprites are good.
    I must have miss something with the URP rendering.

    Any Iea?
    Thanks for your help.
     
  2. Pierre-Marie

    Pierre-Marie

    Joined:
    Aug 3, 2015
    Posts:
    59
    Hi I tried something else,

    I tried to return a RenderTexture and not a sprite and convert the Image of the item to a RawImage.
    It work but now I can't destroy me camera or the texture reset.

    Is there a way to "fix" the texture?
    Then I can destroy the rest?

    Thanks for your help.
     
  3. Pierre-Marie

    Pierre-Marie

    Joined:
    Aug 3, 2015
    Posts:
    59
    Hi,

    I foud a way.

    First correction, as i'm working with a lot of different Camera, I had a controle to the end cameraRendering to check if it's the good camera I want :
    Code (CSharp):
    1. void OnEnable()
    2.     {
    3.         RenderPipelineManager.endCameraRendering += RenderPipelineManager_endCameraRendering;
    4.        
    5.     }
    6.     void OnDisable()
    7.     {
    8.         RenderPipelineManager.endCameraRendering -= RenderPipelineManager_endCameraRendering;
    9.     }
    10.     private void RenderPipelineManager_endCameraRendering(ScriptableRenderContext context, Camera camera)
    11.     {
    12.         if (CalbbackLoad && !CallBackDone && camera.Equals(myCamera))
    13.         {
    14.             CallBackMethode(context, camera);
    15.         }
    16.     }

    Then, as I am using urp, I can"'t use the camera.Render().
    Instead I have to use UniversalRenderPipeline.RenderSingleCamera(context, camera);

    My call back methode become :


    Code (CSharp):
    1. public void CallBackMethode (ScriptableRenderContext context, Camera camera)
    2.     {
    3.  
    4.         RenderTexture oldRt = RenderTexture.active;
    5.         RenderTexture.active = associatedTexture;
    6.  
    7.         UniversalRenderPipeline.RenderSingleCamera(context, camera);
    8.         // Create a new Texture2D      
    9.         Texture2D texture2D = new Texture2D(associatedTexture.width, associatedTexture.height, TextureFormat.ARGB32, false);
    10.         // copies the pixels into the Texture2D        
    11.         texture2D.ReadPixels(new Rect(0, 0, associatedTexture.width, associatedTexture.height), 0, 0, false);
    12.  
    13.         texture2D.Apply();
    14.  
    15.         NewSprite = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f));
    16.  
    17.  
    18.  
    19.         CallBackDone = true;
    20.         CallbackIcon(NewSprite);
    21.     }
    Like than I can call back with a Sprite which became the new Icon Sprite.
    Then I can destroy what I don't need anymore.