Sign in to follow this  
Dom_152

XNA - Render target weirdness

Recommended Posts

Dom_152    476
OK I've been trying to figure this out and I just can't figure out what is going on. I've created a metaball renderer that uses pixel shaders to achieve the effect. I'm now trying to combine this renderer with standard sprite batch stuff, specifically I want to draw my metaballs OVER some sprites. For some reason whenever I try this I end up with this sort of thing: Obviously the purple colour is no good as I want all of that part to be transparent so I check it out in PIX and found that XNA seems to be clearing to this weird colour whenever I set a new render target. I thought a call to Clear(Color.TransparentBlack) after setting the render target would rectify this but it does not. A bit of background on my metaball rendering stuffs: I have a single screen sized offscreen render target and a screen sized texture. For each metaball I draw to the render target the influence per pixel from that ball and blend the result with the texture. The result being an "influence map" containing the summed influences for each metaball on each pixel. Of course this mean I'm constantly having to change render targets in order to save the contents of the render target to the texture after each pass. Once I have the influence map I do one final pass which will colour the pixels based upon the influence values it samples from the influence texture. Here's the C# code to illustrate what I'm on about:
// Setup some mip mapping states so the drawing doesn't look shit
            graphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Linear;
            graphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Linear;
            graphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Linear;
            graphicsDevice.SamplerStates[0].MipMapLevelOfDetailBias = 0.0f;
            graphicsDevice.SamplerStates[0].MaxMipLevel = 0;            

            for (int i = 0; i < pixels.Length; i++)
            {
                pixels[i] = Color.TransparentBlack.PackedValue;
            }

            graphicsDevice.Textures[0] = null;
            influenceMap.SetData<uint>(pixels);

            //influenceMap = new Texture2D(graphicsDevice, textureWidth, textureHeight);

            //graphicsDevice.Clear(Color.Black);
            // Create an influence map on the GPU
            foreach (Metaball aBall in balls)
            {                
                graphicsDevice.SetRenderTarget(0, offScreen);                
                graphicsDevice.Clear(Color.TransparentBlack);
                graphicsDevice.VertexDeclaration = new VertexDeclaration(graphicsDevice, VertexPositionColor.VertexElements);

                influenceMapEffect.Parameters["influenceMap"].SetValue(influenceMap);
                influenceMapEffect.Parameters["metaball"].SetValue(new Vector3(aBall.X, aBall.Y, aBall.Radius));

                influenceMapEffect.Begin();
                influenceMapEffect.CurrentTechnique.Passes[0].Begin();

                graphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, quad, 0, 4, indices, 0, 2);

                influenceMapEffect.CurrentTechnique.Passes[0].End();
                influenceMapEffect.End();

                graphicsDevice.SetRenderTarget(0, null);
                influenceMap = offScreen.GetTexture();
            }
            
            //graphicsDevice.Present();

            graphicsDevice.SetRenderTarget(0, null);

            // Draw the metaballs based upon the influence map
            //graphicsDevice.Clear(Color.TransparentBlack);
            graphicsDevice.VertexDeclaration = new VertexDeclaration(graphicsDevice, VertexPositionColor.VertexElements);

            metaballEffect.Parameters["influenceMap"].SetValue(influenceMap);

            metaballEffect.Begin();
            metaballEffect.CurrentTechnique.Passes[0].Begin();

            graphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, quad, 0, 4, indices, 0, 2);

            metaballEffect.CurrentTechnique.Passes[0].End();
            metaballEffect.End();
           

            graphicsDevice.Present();
And the pixel shader for creating the influence map:
void PixelShader(inout float4 color : COLOR0, in float2 screenPos : VPOS)
{        
    float influenceOn = (metaball.z / (float)((screenPos.x - metaball.x) * (screenPos.x - metaball.x) + (screenPos.y - metaball.y) * (screenPos.y - metaball.y)));         
	float4 influenceSum = float4(influenceOn, influenceOn, influenceOn, 1.0f);                    

	influenceSum += tex2D(textureSampler, (screenPos / ViewportSize));	
	//influenceSum.w = metaball.w;  
	
	color = influenceSum;	
}
and the pixel shader for colouring the balls:
void PixelShader(inout float4 color : COLOR0, in float2 screenPos : VPOS)
{
	float4 influenceSum = tex2D(textureSampler, screenPos / ViewportSize); 
	//color = influenceSum;
	float4 ballColour;
	
	ballColour = float4(0.0f, 0.9f, 0.4f, 1.0f);
        
	color = float4(0, 0, 0, 0);     

    if (influenceSum.x >= 0.4f)
    {                    		
		color += ballColour;
		color.z *= ddx(influenceSum.x);
    }
    else if (influenceSum.x >= 0.15f && influenceSum.x < 0.4f)
    {
		color += float4((ballColour.x + 0.03) * influenceSum.x - 0.19, (ballColour.y + 0.1) * influenceSum.x - 0.19, (ballColour.z - 0.25) * influenceSum.x - 0.19, influenceSum.x - 0.19) * 4;
    }
}

Share this post


Link to post
Share on other sites
Moe    1256
You probably know way more about the subject than I do, but I'm guessing that the SpriteBatch is setting some renderstates that you don't want to be set. Have you tried comparing your renderstates after you are done drawing your metaballs, and then after you call SpriteBatch.Begin()?

Share this post


Link to post
Share on other sites
Matias Goldberg    9583
Just by any chance, you are not using the debug runtimes, are you?

If you are, turn them off; since they force a clear every frame alternating between purple and green to catch clearing problems, but sometimes this interferes with very specific effects.

If you aren't, turn them on, they may tell about a problem you didn't know was there.

Cheers
Dark Sylinc

Share this post


Link to post
Share on other sites
Dom_152    476
I turned them on and it made my screen start flickering green =/ Not really sure whether that means things are working or not...

I'll try forcing the render states but I thought the ones I did set were the only relevant ones.

EDIT: I guess the green flickering must mean I'm not clearing properly at some point since I can see the sprites in the background so it seems like every other frame isn't working properly. Also worth noting that with the debug things on I can't see the metaballs at all, just the flickering.

Share this post


Link to post
Share on other sites
MJP    19790
That Clear you're getting is automatic behavior the frameowork. It's there by default to provide compatibility with the Xbox 360, where render targets only live in special bit of GPU memory and have to be manually copied in if you want them to survive a switch. If you don't want that behavior, you have to create RenderTargets with RenderTargetUsage.PreserveContents.

In your case, what I would do is just render the metaballs first to a render target, then switch to the backbuffer and render the sprites. After rendering all of your sprites, just render the metaball texture on top.

Share this post


Link to post
Share on other sites
Dom_152    476
Quote:
Original post by MJP
That Clear you're getting is automatic behavior the frameowork. It's there by default to provide compatibility with the Xbox 360, where render targets only live in special bit of GPU memory and have to be manually copied in if you want them to survive a switch. If you don't want that behavior, you have to create RenderTargets with RenderTargetUsage.PreserveContents.

In your case, what I would do is just render the metaballs first to a render target, then switch to the backbuffer and render the sprites. After rendering all of your sprites, just render the metaball texture on top.


Thanks a million, it's working perfectly now!
That's a nice little piece of information to remember for the future.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this