Render texture doesn't update changes made, how to ensure this happens?

I’m building a system which has a set of quads in front of each other, forming a layer system. This layers are being rendered by a orthographic camera with a render texture, which is used to generate a texture and save it to disk after the layers are populated. It happens that I need to disable some of those layers before the final texture is generated. So I built a module that disable those specific layers’ mesh renderers and raise an event to start the render to texture conversion.

To my surprise, the final image still presents the disabled layers in the final image. I’m really confused about this, cause I already debugged the code in every way I could and those specific layers shouldn’t be visible at all considering the code. It must have something to do with how often render textures update or some other obscure execution order. The entire module is composed of 3 or 4 classes with dozens of lines, so to exemplify the issue in a more succinct way, I’ll post only the method where the RT is being converted into a texture with some checks I made just before the RT pixels are read into the new texture:

public void SaveTexture(string textureName, TextureFormat textureFormat)
{
    renderTexture = GetComponent<Camera>().targetTexture;
    RenderTexture.active = renderTexture;
    var finalTexture = new Texture2D(renderTexture.width,
        renderTexture.height, textureFormat, false);

    /*First test, confirming that the marked quad' mesh renderer
     is, in fact, disabled, meaning it shouldn't be visible in the camera,
    consequently invisible in the RT. The console shows "false", meaning it's
    disabled. Even so, the quad still being rendered in the final image.*/
    //Debug.Log(transform.GetChild(6).GetChild(0).GetComponent<MeshRenderer>().enabled);

    /*Second test, changing the object' layer, because the projection camera
     has a culling mask enabled to only capture objects in one specific layer.
    Again, it doesn't work and the quad content still being saved in the final image.*/
    //transform.GetChild(6).GetChild(0).gameObject.layer = 0;

    /*Final test, destroying the object to ensure it doesn't appear in the RT.
     This also doesn't work, confirming that no matter what I do, the RT is
    "fixed" at this point of execution and it doesn't update any changes made
    on it's composition.*/
    //Destroy(transform.GetChild(6).GetChild(0).gameObject);

    finalTexture.ReadPixels(new Rect(0, 0, renderTexture.width,
        renderTexture.height), 0, 0);
    finalTexture.Apply();
    finalTexture.name = textureName;
    var teamTitle = generationController.activeTeam.title;
    var kitIndex = generationController.activeKitIndex;
    var customDirectory = saveDirectory + teamTitle + "/"+kitIndex+"/";

    StorageManager<Texture2D>.Save(finalTexture, customDirectory, finalTexture.name);
    RenderTexture.active = null;
    onSaved();
}

Funny thing is, if I manually disable that quad in inspector (at runtime, just before trigger the method above), it works, and the final texture is generated without the disabled layer.

I tried my best to show my problem, this is one of those issues that are kinda hard to show here but hopefully somebody will have some insight of what is happening and what should I do to solve that.

Well, the objects don’t get rendered when you call finalTexture.ReadPixels. The contents you copy out of camera.targetTexture have been rendered some time before the call to your SaveTexture method, so making any changes to visibility or destroying game objects at this point will have no impact on the texture you read.

You need to disable your layers before the camera renders the objects. If this is your main camera and you just use the regular render loop, then you need to disable your meshes for example in Unity - Scripting API: MonoBehaviour.OnPreRender() and then call your SaveTexture method in Unity - Scripting API: MonoBehaviour.OnPostRender() and re-enable your layers there.

Alternatively, you can render the camera manually. So if you re-enable your tests, and then add a GetComponent().Render() on line 24 of your example, this should work as well (and is probably what you intended)

1 Like

Thank you sir, I’ve only added those statements there for convenience, once I showing the entire instructions would result in a gigantic post. The actual disabling occurs before that method is called, but apparently after the camera RT is updated, so the changes doesn’t work either.

Your suggestions should work, I didn’t know these methods you mentioned, once I’ve never had this kind of issue before. I’ll adjust my structure to use those methods…

Thanks again!

EDIT - Once all my structure was ready already, all I need to do was to add the “GetComponent().Render()” on the first line of method and everything worked.

Many thanks, not sure if/when I’ll find this solution!