Render texture to png ARBG32 no opaque pixels

I’ve been wanting to render the camera view to a png so that I could use the images in my marketing.
I found Is it possible to save RenderTextures into png files for later use? - Questions & Answers - Unity Discussions that showed me how to get render textures to png.

At first it looked like it worked correctly, but upon inspecting I noticed that there were no alphas in the image.

I went ahead and changed the encoding of the image to include the alpha and got this

I don’t know why the opaque objects are being rendered transparent. I introduced a default sphere and deleted lights in the scene but I keep getting the same treatment. I’ve tried different texture format combinations and still no luck. I just don’t understand well enough what’s going on under the hood. I’ve included the script I’m using below. The script is being run by ab editor script with a button to execute.

using UnityEngine;
using System.Collections;

public class renderPNG : MonoBehaviour {
    public int imgX = 512;
    public int imgY = 512;
    public Camera virtuCamera;
    public string imageName = "myRenderTexture";

    public void renderTex()
    {
        // capture the virtuCam and save it as a square PNG.


       
        //virtuCamera.camera.aspect = 1.0f;
        // recall that the height is now the "actual" size from now on
       
        RenderTexture tempRT = new RenderTexture(imgX,imgY,24, RenderTextureFormat.ARGB32 );
        // the 24 can be 0,16,24, formats like
        // RenderTextureFormat.Default, ARGB32 etc.
       
        virtuCamera.camera.targetTexture = tempRT;
        virtuCamera.camera.Render();
       
        RenderTexture.active = tempRT;
        Texture2D virtualPhoto =
            new Texture2D(imgX,imgY, TextureFormat.ARGB32, false);
        // false, meaning no need for mipmaps
        virtualPhoto.ReadPixels( new Rect(0, 0, imgX,imgY), 0, 0);
       
        RenderTexture.active = null; //can help avoid errors
        virtuCamera.camera.targetTexture = null;
        // consider ... Destroy(tempRT);
       
        byte[] bytes;
        bytes = virtualPhoto.EncodeToPNG();
       
        System.IO.File.WriteAllBytes(
            OurTempSquareImageLocation(), bytes );
        // virtualCam.SetActive(false); ... no great need for this.
        Debug.Log ("Saved image in this location " + OurTempSquareImageLocation());
        // now use the image,
        //UseFileImageAt( OurTempSquareImageLocation() );
    }
   
    private string OurTempSquareImageLocation()
    {
        string r = Application.dataPath +"/"+imageName+".png";
        return r;
    }

}

If anyone can kindly direct me to the right information to help me get a transparent background with opaque objects I would be forever grateful! :slight_smile:

Many thanks,
Reinaldo


I thought that this might be the correct forum to post this question in. Was I mistaken, should it belong somewhere else?

I found this fantastic script which makes taking screenshots very easily and with transparencies. For some reason I get the same issue. It looks ok in the preview but if you open the image in photoshop it shows that the cube is transparent.

I’ve tried on both mac and pc and get the same result.
There is certainly something that I am overlooking or there is a defect somewhere. Anyone have any ideas?

Many thanks,
Reinaldo

2063250--134472--screen_203x338_2015-04-10_23-39-28.png

You need to make sure of three things:

  • Your second camera needs to use a clear colour with the alpha value you want in empty spaces.
  • The objects rendered by your second camera need to use shaders that write appropriate alpha values
  • The material for your plane needs to support blending so that the alpha values from the render texture are used appropriately as transparency.

also if you are using unity 4.x , you need pro for render texture output to be correct.

1 Like

Hi invadererik, thank you for your feedback. If you could kindly clarify points 1 and 2 for me, that would help me out greatly.

  • Your second camera needs to use a clear colour with the alpha value you want in empty spaces.

When you say second camera, do you mean the camera creating the render texture? I only ask since I’m doing this in the editor for marketing images, so it’s not run time.

  1. The objects rendered by your second camera need to use shaders that write appropriate alpha values

I dioremember seeing this mentioned somewhere but I don’t know how to confirm that the shaders are writing to the correct channels. In this case I would assume that they should only be writing to RGB channels since I want them to be opaque. Hw would I make sure they are? Would default shader on a cube meet these requirements?

Can you send the project? I think I can help you.

Oh that would be great if you can!
Here is a project with the scripts attached.

I just tried in unity 5 and it seems that I can’t reproduce there, so maybe the shaders change or something else all together.

2063711–134509–Render Texture Alpha.zip (1.42 MB)

Did you set the camera’s clear flag to solid color and modify the color’s alpha to 0?

Okay, I had a look at your project. I suppose you’re taking screenshots this way:

2063776--134512--1.png

So,

  1. Please make sure you always check Transparent Background:

  1. Like invadererik and Dantus said, you need to set the main camera color’s alpha to 0, because in your project it wasn’t 0.

Well, I’ve changed the alpha and now it works perfect for me. Please see the project with fix in the attachments.

2063776–134514–Render Texture Alpha.zip (1.41 MB)

Try an unlit shader or vertex lit , basically make sure the shader is explicitly writing 1 to the alpha channel.

Basic Diffuse shader modified to explicitly set the alpha channel to 1 :

Shader "custom/myDiffuse" {
Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
    _MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200

CGPROGRAM
#pragma surface surf Lambert

sampler2D _MainTex;
fixed4 _Color;

struct Input {
    float2 uv_MainTex;
};

void surf (Input IN, inout SurfaceOutput o) {
    fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    o.Albedo = c.rgb;
    o.Alpha = 1;
}
ENDCG
}

Fallback "VertexLit"
}

example screenshot ( back two spheres using default diffuse, while front one is using the above shader)

you could probably report this behavior as a bug to unity possibly.