Textures mix up... blurX and then blurY?

Hey!

I want to blur a rendered image. Somehow it works and somehow not. Here is what (I think) I do:

  • Blur the image from the camera horizontal (with the first pass of a shader).
  • Blur the result of 1. vertical (with the second pass of a shader).
  • return the result to a rendertexture.

But the result seems to be…

  • returns a black image (??)
  • returns a vertical blurred image from the camera (ignore input from 1.)

A few minutes ago I suddenly had a normal map from the mesh the camera is rendering in the resulting texture? Somehow the textures seem to mix up…

The C# code:

void OnRenderImage(RenderTexture source, RenderTexture dest)
{
    RenderTexture blurUBuffer = RenderTexture.GetTemporary(512, 512, 0);
    RenderTexture blurVBuffer = RenderTexture.GetTemporary(512, 512, 0);
	
	//blur horizontal
    blurDirectional(source, blurUBuffer, true); 
    
    //blur vertical
    blurDirectional(blurUBuffer, blurVBuffer, false);

    ImageEffects.Blit(blurVBuffer, dest);

    blurUBuffer.Release();
    blurVBuffer.Release();
}

private void blurDirectional(RenderTexture blurSource, RenderTexture blurDest, bool direction)
{
    RenderTexture.active = blurDest;

    float offset = 1.0f / (float)blurSource.width;
    
    GL.PushMatrix();
    GL.LoadOrtho();

    //first pass: horizontal blur
    //second pass: vertical blur
    blurMaterial.SetPass(direction ? 0 : 1);
    
    blurMaterial.SetFloat("_Offset", offset);
    blurMaterial.SetTexture("_SourceTex", blurSource);

    RenderQuad();
    
    GL.PopMatrix();
}

private void RenderQuad()
{
    GL.Begin(GL.QUADS);
    GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(-1.0f, -1.0f, 0.1f);
    GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, -1.0f, 0.1f);
    GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, 1.0f, 0.1f);
    GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(-1.0f, 1.0f, 0.1f);
    GL.End(); 
}

Any major mistake here?

The blur shader basically only gets 5 weighted samples in one direction (one in each pass) and returns the sum.

Is it correct, that for a RenderTexture I need a texRECT sampler and for a normal Texture2D a tex2D sampler?

Nobody any idea? What could be the reason that if I render an effect twice, it works only once (but there perfectly).

Even if I use a shader that just passes one sample of the input texture.

  blurDirectional(blurUBuffer, blurVBuffer, false); //works fine
  blurDirectional(blurVBuffer, blurUBuffer, false); // mixes up textures, renders black textures,...

It drives me crazy… :smile: :slight_smile: :frowning: :cry: [/code]

Ok… here is a small demo which demonstrates my problem:

http://www.janbubenik.de/da/demos/renderTextureDemo.html

The scene consists of a sphere (turning), 2 directional lights and a camera with the following script:

using UnityEngine;
using System.Collections;

public class TestRenderToTexture : MonoBehaviour {

    public int size = 512;

    public int iterations = 1;

    private string debugString = "";
    private bool releaseTemp = true;

    private static string myMatString =
@"Shader ""SSS/testCopyShader"" {
	SubShader {
		Pass {
			ZTest Always Cull Off ZWrite Off Fog { Mode Off }
			SetTexture [__RenderTex] {constantColor (0.8,0.8,1,1) combine texture * constant}
		}
	}
	Fallback off
}";

    protected Material myMaterial = null;
    protected Material getMaterial
    {
        get
        {
            if (myMaterial == null)
            {
                myMaterial = new Material(myMatString);
                myMaterial.hideFlags = HideFlags.HideAndDontSave;
                myMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
            }
            return myMaterial;
        }
    }

    void OnRenderImage(RenderTexture source, RenderTexture dest)
    {
        debugString = "";
        
        if (iterations > 0)
        {
            RenderTexture tempBuffer1 = RenderTexture.GetTemporary(size, size, 0);
            RenderTexture tempBuffer2 = RenderTexture.GetTemporary(size, size, 0);
            debugString += "-> GetTemporary temp1  temp2\n";

            bool oddEven = true;

            copyTexture(source, tempBuffer1);
            debugString += "copy(source, temp1)\n";

            for (int i = 0; i < iterations-1; i++)
            {
                if (oddEven)
                {
                    copyTexture(tempBuffer1, tempBuffer2);
                    debugString += "copy(temp1, temp2)\n";
                }
                else
                {
                    copyTexture(tempBuffer2, tempBuffer1);
                    debugString += "copy(temp2, temp1)\n";
                }
                oddEven = !oddEven;
            }

            if (oddEven)
            {
                copyTexture(tempBuffer1, dest);
                debugString += "copy(temp1, dest)\n";
            }
            else
            {
                copyTexture(tempBuffer2, dest);
                debugString += "copy(temp2, dest)\n";
            }

            if (releaseTemp)
            {
                tempBuffer1.Release();
                tempBuffer2.Release();
                debugString += "-> Release temp1  temp2\n";
            }

            if (iterations > 10)
            {
                int start = 122;
                int end = 238;
                if (!releaseTemp)
                    end -= 3;
                debugString = debugString.Remove(start, debugString.Length - end);
                debugString = debugString.Insert(start, "\n[...]\n");
            }
        }
        else
        {
            copyTexture(source, dest);
            debugString += "\ncopy(source, dest)\n\n";
        }
    }
    
    private void copyTexture(RenderTexture source, RenderTexture dest)
    {
        RenderTexture.active = dest;

        GL.PushMatrix();
        GL.LoadOrtho();

        getMaterial.SetPass(0);

        source.SetGlobalShaderProperty("__RenderTex");

        RenderQuad();

        GL.PopMatrix();
    }

    private void RenderQuad()
    {
        GL.Begin(GL.QUADS);
        GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0.0f, 0.0f, 0.1f);
        GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(1.0f, 0.0f, 0.1f);
        GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(1.0f, 1.0f, 0.1f);
        GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0.0f, 1.0f, 0.1f);
        GL.End();
    }

    void OnGUI()
    {
        GUI.Label(new Rect(5, 5, 200, 200), debugString);
        GUI.Label(new Rect(45, Screen.height - 30, 80, 25), "iterations: " + iterations.ToString());
        if (GUI.Button(new Rect(5, Screen.height - 30, 30, 25), "+"))
        {
            iterations++;
            if (iterations > 100)
                iterations = 100;
        }
        if (GUI.Button(new Rect(125, Screen.height - 30, 30, 25), "-"))
        {
            iterations--;
            if (iterations < 0)
                iterations = 0;
        }
        if (GUI.Button(new Rect(165, Screen.height - 30, 100, 25), "release: " + releaseTemp.ToString()))
            releaseTemp = !releaseTemp;
    }
}

in your blur code isnt any texture offset niether in shader or in texture coord generation.

and that is why you simply copy texture pixel by pixel all passes.

Oh, sorry… I should have mentioned, that I do this on purpose.

I removed the blur itself, because I already get the error when simply copying the texture (like you said). I am trying to simplify the whole thing to track down the problem.

If you open that link you will see a ball spinning around. If you click on “+” at the bottem-left you will increase the iteration-steps. With “Release” turned on, every second iteration-step will display the base texture of the sphere… and I really don’t know why!

Alright… I got it. The error was right here:

GL.PushMatrix();
GL.LoadOrtho();
[..]
source.SetGlobalShaderProperty("__RenderTex");

You can’t set the ShaderProperty after these GL commands. :sweat_smile:

This way it works:

[..]
source.SetGlobalShaderProperty("__RenderTex");

GL.PushMatrix();
GL.LoadOrtho();

I suppose writing _RenderTex instead of __RenderTex won’t do much difference? :slight_smile:

Also I think it is better to blur image in horizontal direction, then blur original image in vertical direction and then combine the two results.

__RenderTex or _RenderTex doesn’t make a difference. :wink:

But you have to blur the horizontal blured image vertical (not the original one).

This would be the difference:

182881--6493--$blur_707.jpg

Here’s the result so far… on the left without diffuse texture and on the right with diffuseTex multiplied.

The skin still needs a lot of tweaking. The blue edges in the left image can be removed with a proper gamma correction. At the moment I am working on that. :frowning:

Not an easy topic… sRGB textures aren’t supported, right? Floating point RTs neither… too bad.

Hello DerWoDaSo,

I tested your blur and the result I get is just a blue image. The more iterations I do the blued I see the image. Is that normal? What could I change to see a blurred result instead of a change of color?

Hey Babur, the problem is, there is no “blur shader” in here at the moment… I used a simple replacement for debugging and to demonstrate the problem.

@"Shader ""SSS/testCopyShader"" {
   SubShader {
      Pass {
         ZTest Always Cull Off ZWrite Off Fog { Mode Off }
         SetTexture [__RenderTex] {constantColor (0.8,0.8,1,1) combine texture * constant}
      }
   }
}

You need a shader that performs a separable gaussian blur. But I don’t have the code here right now… sorry. I will try to update my blog soon with some code examples, but I am pretty busy right now.

Oooups ok thanks anyway :slight_smile: It seems that the Wii does not support shaders anyway so I would need to do this on script. I don’t know if there are any tools to modify texture pixels directly from script. I will have to investigate :roll:

Oh… well, I don’t think that’s possible. You CAN read pixel values from script (see Script Reference - GetPixel), but it will be SLLOOOOOW. :wink:

Damn! I was having a look at that right now… but I don’t get why this function should be slow… a texture is a simple 2D array… or am I wrong?

A texture is just a 2D array… that gets written to and read from the graphics card.

Reading the texture out of the graphics card is slow.