Turn Shader Main Preview into a sprite (png) ?

Hello,

I have multiple materials using different shaders and I would like for my player to costumize his character with those materials. But I don’t want to draw a PNG sprite for each material to display it to the player so he can “Preview” what the material looks like before pressing on it to apply. So I would like to know if it’s possible to get the Main Preview sprite used by unity shader graph in the project folder, for example this :
(this is just a material created from a shader graph)
8259606--1081356--upload_2022-7-7_6-56-45.png

and return it as a sprite/PNG ? this is what it would look like in my UI :

This is my UI for the player’s material list :
8259606--1081362--upload_2022-7-7_6-58-37.png

And I would like something like this :
8259606--1081365--upload_2022-7-7_7-0-9.png

How could I do this without having to draw or screenshot each shader/material ?

8259606--1081356--upload_2022-7-7_6-56-45.png

Shadergraph is simply drawing the current graph material on a sphere mesh in this example, rendering using a RenderTexture that is sized for that preview. That’s all you have to do as well and is fairly efficient for this use case. (you can even choose to simply update the RenderTexture only when values changes).

You can use this guide, but instead of rendering a bunch of spheres on the map with this camera, you would simply render a single sphere, with the material of your choice applied to it. The RenderTexture would update, and thus so would the preview there.

1 Like

Thank you for the answer. I didn’t even know RenderTextures were a thing before this. I implemented this in my own way and it works perfectly. For anyone wondering, I used 1 camera and 1 Sphere mesh, a coroutine to go through all my materials with some “WaitForSeconds” time (around 0.05sec) because otherwise the camera would not have the time to render the texture in my RawImage. For advanced people wanting to do the same this is the method I used, you can probably figure out how to change it for yourself :

    public List<RenderTexture> Liste_RenderTexture = new List<RenderTexture>();
    public Camera CameraMaterial;
    public GameObject SphereMaterial;
    public float TimeBetweenRenderMaterial = 0.05f;

   private void Start()
   {
        StartCoroutine(DisplayAllMaterialsOwned());
    }

    public IEnumerator DisplayAllMaterialsOwned()
    {
        int i = 0;
        while (i < _PlayerSkinsScriptableObject.Liste_MaterialsOwned.Count)
        {
                if (i < Liste_AllMaterialsOwnedButtons.Count)
                {
                    SphereMaterial.GetComponent<MeshRenderer>().material = _PlayerSkinsScriptableObject.Liste_MaterialsOwned[i]; // Assign material you want to display to the player on the sphere that is gonna be "photographed"
                    RenderTexture renderTexture = new RenderTexture(256, 256, 16, RenderTextureFormat.ARGB32); // create renderTexture
                    Liste_RenderTexture.Add(renderTexture); // add rendertexture to a list but not necessary
                    Liste_AllMaterialsOwnedButtons[i].GetComponentInChildren<RawImage>().texture = renderTexture; // apply rendertexture to your rawImage so you can display it
                    CameraMaterial.targetTexture = renderTexture; // output of the camera will be saved on the renderTexture, since we assigned the renderTexture to the RawImage above,
// the RawImage will show the renderTexture while it's assigned to the camera
// (TimeBetweenRenderMaterial) and then once we assign a new renderTexture, 
//the RawImage will keep a static image of your material
                }
                i++;
            yield return new WaitForSeconds(TimeBetweenRenderMaterial);
        }
    }

and this is the final result :

8261568--1081662--upload_2022-7-8_0-52-55.png

anyway, thanks a lot !

Nice work!
I would recommend against the WaitForSeconds method though, since that is going to differ by a user’s computer performance. Though really you should only have to wait for a frame anyways, which would just be `yield return null;

But even better, instead you could simply call CameraMateria.Render() after assigning your RenderTexture to it. You don’t have to yield each loop.

1 Like

wow, I really didn’t like my coroutine alternative and you just gave me a way better solution, works perfectly with “CameraMaterial.Render();” and faster ! thanks a lot !! :slight_smile: