Jump to content

  • Log In with Google      Sign In   
  • Create Account


Artifacts in image that dont appear when using reference device


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
18 replies to this topic

#1 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 19 April 2012 - 04:01 AM

Ive been having a problem with a sort of white halo showing up around the blocks in my XNA game. When I debugged it in pix, I noticed that it seems to occur in the directional light shader and that it doesnt happen when I set pix to "Force REF". I've attached images of what it looks like in pix on both "Unchanged" and "Force REF" mode. What would cause this kind of thing?

Unchanged:
normal.png

Force REF:
ref.png

Sponsor:

#2 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 19 April 2012 - 04:53 AM

Do you use MSAA and a deferred renderer?

Project page: < XNA FINAL Engine >


#3 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 19 April 2012 - 03:20 PM

I am using a deferred renderer, but MSAA is off

#4 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 19 April 2012 - 07:56 PM

And what is the surface format of the depth buffer and how do you store the depth information?

You could suffer a lack of precision in the depth buffer.

Project page: < XNA FINAL Engine >


#5 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 19 April 2012 - 08:17 PM

These are the render targets used by the deferred renderer:

colorRT = new RenderTarget2D(Engine.Game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);  
normalRT = new RenderTarget2D(Engine.Game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.None);
depthRT = new RenderTarget2D(Engine.Game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Single, DepthFormat.None);
lightRT = new RenderTarget2D(Engine.Game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.None);
finalRT = new RenderTarget2D(Engine.Game.GraphicsDevice, backbufferWidth, backbufferHeight, false, SurfaceFormat.Color, DepthFormat.None);

In the GBuffer vertex shader I have
output.Depth = output.Position.zw;
and in the pixel shader I have
output.Depth = input.Depth.x / input.Depth.y


#6 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 19 April 2012 - 08:32 PM

It's really strange. Posted Image

First I think in MSAA because deferred renderers and MSAA don’t work well together, since different fragments will use the same illumination information.

Then I think that the GPU depth buffer could has little differences with your depth buffer. But it looks ok.

I don't know. Posted Image

Project page: < XNA FINAL Engine >


#7 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 19 April 2012 - 09:50 PM

I was looking through pix again and I noticed a line that said SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE). So it looks like MSAA is on. I have no idea whats turning it on though. When the graphics device is created, I explicitly turned it off. I checked all the render targets, none of them turn it on either. Ideas?

Edited by Telanor, 29 April 2012 - 03:17 PM.


#8 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 20 April 2012 - 06:27 AM

Yes. Set multisampling in the method Graphics_PreparingDeviceSettings

private static void Graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
{
	 Device.PresentationParameters.MultiSampleCount = 0;
}

When you don't explicitly set multisampling the render target constructor uses the system value. And the correct place to setting the multisampling count is this method.

Project page: < XNA FINAL Engine >


#9 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 20 April 2012 - 04:20 PM

Hmm, that didn't work. I should note that the SetRenderState line I noticed occurs RIGHT before the directional light shader starts rendering. It seems like a shader/render target specific setting, but I can't find anything in the code that might be enabling it.

Game constructor:

	public Craft()
	{
		Game = this;

		Graphics = new GraphicsDeviceManager(this)
		{
			PreferredBackBufferWidth = 1280,
			PreferredBackBufferHeight = 720,
			SynchronizeWithVerticalRetrace = false,
			PreferMultiSampling = false,
			IsFullScreen = false
		};

		Graphics.PreparingDeviceSettings += graphics_PreparingDeviceSettings;
		Content.RootDirectory = "Content";

		IsFixedTimeStep = false;
		//this.Window.AllowUserResizing = true;
		//this.IsMouseVisible = true;
	}

	void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
	{
		foreach(GraphicsAdapter adapter in GraphicsAdapter.Adapters)
		{
			if(adapter.Description.Contains("PerfHUD"))
			{
				e.GraphicsDeviceInformation.Adapter = adapter;
				GraphicsAdapter.UseReferenceDevice = true;  //  this is the modified line from usage in previous xna version
				break;
			}
		}
		
		e.GraphicsDeviceInformation.PresentationParameters.MultiSampleCount = 0;
	}


And heres a snippit of the directional light render code path:

	class DeferredRenderer
	{
		private void DrawLights()
		{
			Engine.Graphics.GraphicsDevice.SetRenderTarget(lightRT);
			Engine.Graphics.GraphicsDevice.Clear(Color.Transparent);
			Engine.Graphics.GraphicsDevice.BlendState = BlendState.AlphaBlend;
			Engine.Graphics.GraphicsDevice.DepthStencilState = DepthStencilState.None;

			DirectionalLight.Draw();
			PointLight.Draw();

			Engine.Graphics.GraphicsDevice.BlendState = BlendState.Opaque;
			Engine.Graphics.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
			Engine.Graphics.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
			Engine.Graphics.GraphicsDevice.SetRenderTarget(null);
		}
	}


	class DirectionalLight
	{
		private void DrawDirectionalLight()
		{
			directionalLightEffect.Parameters["ColorMap"].SetValue(DeferredRenderer.ColorRT);
			directionalLightEffect.Parameters["NormalMap"].SetValue(DeferredRenderer.NormalRT);
			directionalLightEffect.Parameters["DepthMap"].SetValue(DeferredRenderer.DepthRT);

			directionalLightEffect.Parameters["LightDirection"].SetValue(LightDirection);

			directionalLightEffect.Parameters["DiffuseLightColor"].SetValue(DiffuseColor);
			directionalLightEffect.Parameters["AmbientLightColor"].SetValue(AmbientColor);

			directionalLightEffect.Parameters["AmbientIntensity"].SetValue(AmbientIntensity);
			directionalLightEffect.Parameters["DiffuseIntensity"].SetValue(DiffuseIntensity);

			directionalLightEffect.Parameters["SpecularPower"].SetValue(SpecularPower);
			directionalLightEffect.Parameters["SpecularIntensity"].SetValue(SpecularIntensity);

			directionalLightEffect.Parameters["CameraPosition"].SetValue(Camera.Position);
			directionalLightEffect.Parameters["InvertViewProjection"].SetValue(Matrix.Invert(Camera.View * Camera.Projection));

			directionalLightEffect.Techniques[0].Passes[0].Apply();
			DeferredRenderer.FullScreenQuad.Draw();
		}

		public static void Draw()
		{
			foreach(DirectionalLight light in lights)
			{
				light.DrawDirectionalLight();
			}
		}
	}


#10 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 20 April 2012 - 04:30 PM

Everything looks good.

Maybe it’s a driver problem. Upload your bin directory, I will try your program if you like.

Project page: < XNA FINAL Engine >


#11 Adam_42   Crossbones+   -  Reputation: 2353

Like
0Likes
Like

Posted 20 April 2012 - 06:05 PM

Here's some things to try:

- Make sure none of the settings are overridden in the driver control panel (especially MSAA).
- Make sure there's no errors reported when you use the debug runtimes (for both hardware and ref).
- Make sure you have the latest drivers for your card.
- Try it on hardware from the other manufacturers if possible.

Note that when PIX debugs a pixel / vertex it uses the reference rasterizer to do so. It doesn't tell you what's happening on the actual hardware. It might be worth looking for any values where a small rounding error could give a different colour as output.

Are you aware of the D3D9 pixel centre issues?

#12 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 20 April 2012 - 06:26 PM

  • As far as I can tell, the settings aren't overriden in my control panel. I did have it set up that way at one point, but I deleted the profile, and I can clearly see there is no antialiasiing on the final render image.
  • I've tried to get error output from debug runtimes but I can't figure it out. I followed Shawn Hargreaves' guide but I never got any output from those programs. If someone could tell me how to do that for XNA 4.0 I would love to try.
  • I was using the latest 301 beta drivers for nvidia, I've now downgraded to the latest official drivers (296.10) with no improvement.
  • I'll try to get someone with an ATI card to test and see if they have the problem as well

I am aware of the pixel/texel issue, and I do have a + halfPixel in the shader. If that was the issue I think it'd happen on the reference device as well. Also I don't think its an issue of a small rounding error. I think the difference between the values was something like .6 vs 1.

#13 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 29 April 2012 - 12:05 AM

I've figured out a few new things. First, the antialiasing was being turned on because of this:

static readonly RasterizerState WireFramedRaster = new RasterizerState { CullMode = CullMode.None, FillMode = FillMode.WireFrame };
static readonly RasterizerState NormalRaster = new RasterizerState { CullMode = CullMode.CullCounterClockwiseFace, FillMode = FillMode.Solid };

...

Engine.Graphics.GraphicsDevice.RasterizerState = !wireFramed ? NormalRaster : WireFramedRaster;


According to the documentation, RasterizerState has multisampling turned on by default. This was actually coming from the skybox render code, not the directional light code. PIX no longer shows SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE) anywhere in the event log.

This didn't fix the problem however, and now I think its an issue of pixel/texel alignment. I previously had a project where I implemented a deferred shader with point lights using Catalin Zima's tutorial. The tutorial for that had a bug in it which caused this same type of white halo because it had -halfPixel in the shader instead of +halfPixel.

The directional light and deferred renderer code in this project also comes from that same set of tutorials. In Catalin's directional light tutorial, it again has -halfPixel, but this time its in the vertex shader instead of the pixel shader. I've tried changing it to +halfPixel, and I've tried removing it. Neither had any effect. Could someone take a look at the tutorial code and see what's wrong with it?

I've attached a SUB image comparison made with PIX between the color render target and the light render target. It definately seems like an alignment issue based off that.

Attached Thumbnails

  • comparison.png


#14 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 29 April 2012 - 07:51 AM

You are close. If multisampling was active then it was causing some halos (and performance lost), now you have to found your other source of halos.

In my engine I use this in the vertex shader of my directional light: output.position.xy += halfPixel;

Read this: http://drilian.com/2...-texel-offsets/

Edited by jischneider, 29 April 2012 - 08:01 AM.

Project page: < XNA FINAL Engine >


#15 Telanor   Members   -  Reputation: 1279

Like
1Likes
Like

Posted 29 April 2012 - 02:41 PM

I tried output.Position.xy += HalfPixel and output.Position.xy -= HalfPixel in the vertex shader. The problem is still there

#16 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 05 May 2012 - 04:04 PM

So any other ideas? Heres the full directional light shader code, just so its easier to take a look at.


//Used to compute the world-position
float4x4 InvertViewProjection; 

//Position of the camera, for specular light
float3 CameraPosition; 

//Light Properties
float3 LightDirection;

//Color Properties
float4 DiffuseLightColor;
float4 AmbientLightColor;
float AmbientIntensity; 
float DiffuseIntensity; 

//Specular Properties
float SpecularPower;
float SpecularIntensity;

//Textures
float2 HalfPixel;


// diffuse color, and specularIntensity in the alpha channel
texture ColorMap; 
// normals, and specularPower in the alpha channel
texture NormalMap;
//depth
texture DepthMap;

sampler colorSampler = sampler_state
{
    Texture = (ColorMap);
    MagFilter = Linear;
    MinFilter = Linear;
    Mipfilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};
sampler depthSampler = sampler_state
{
    Texture = (DepthMap);
    MagFilter = Point;
    MinFilter = Point;
    Mipfilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};
sampler normalSampler = sampler_state
{
    Texture = (NormalMap);
    MagFilter = Point;
    MinFilter = Point;
    Mipfilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

struct VertexShaderInput
{
     float3 Position : POSITION0;
     float2 TexCoord : TEXCOORD0;
};

struct VertexShaderOutput
{
	float4 Position : POSITION0;
	float2 TexCoord : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
	VertexShaderOutput output;
	output.Position = float4(input.Position, 1);

	//align texture coordinates
	output.TexCoord = input.TexCoord - HalfPixel;

	return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	//get normal data from the normalMap
	float4 normalData = tex2D(normalSampler,input.TexCoord);

	//tranform normal back into [-1,1] range
	float3 normal = 2.0f * normalData.xyz - 1.0f;

	//get specular power, and get it into [0,255] range]
	float specularPower = saturate(normalData.a * SpecularPower) * 255;

	//get specular intensity from the colorMap
	float specularIntensity = saturate(tex2D(colorSampler, input.TexCoord).a * SpecularIntensity);

	//read depth
	float depthVal = tex2D(depthSampler,input.TexCoord).r;

	//Only the skybox has a depth this high, so stop processing and return white
	if(depthVal > 0.999f)
		return float4(1, 1, 1, 0);

    //compute screen-space position
    float4 position;
    position.x = input.TexCoord.x * 2.0f - 1.0f;
    position.y = -(input.TexCoord.x * 2.0f - 1.0f);
    position.z = depthVal;
    position.w = 1.0f;

    //transform to world space
    position = mul(position, InvertViewProjection);
    position /= position.w;

    //surface-to-light vector
    float3 lightVector = -normalize(LightDirection);

    //compute diffuse light
	float NdL = saturate(dot(normal, lightVector));
    float4 diffuseLight = (NdL * DiffuseLightColor * DiffuseIntensity) + (AmbientLightColor * AmbientIntensity);

    //reflexion vector
    float3 reflectionVector = normalize(reflect(-lightVector, normal));

    //camera-to-surface vector
    float3 directionToCamera = normalize(CameraPosition - position);

    float specularLight = specularIntensity * pow(saturate(dot(reflectionVector, directionToCamera)), specularPower);

     return float4(diffuseLight.rgb, specularLight);
}

technique Technique0
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}


#17 jischneider   Members   -  Reputation: 252

Like
1Likes
Like

Posted 05 May 2012 - 04:21 PM

Like I said before I calculated halfpixel using the following code: output.position.xy += halfPixel; But halfpixel is equal to Vector2(-1f / destination.Width, 1f / destination.Height)); Be aware that the first value is negative. I forgot to mention before.

That said: position.y = -(input.TexCoord.x * 2.0f - 1.0f); The x should be y.

The rest seems fine. I you want to improve performance you can avoid the matrix multiplication in the world position calculation. Ask me if you want.

Edited by jischneider, 05 May 2012 - 04:25 PM.

Project page: < XNA FINAL Engine >


#18 Telanor   Members   -  Reputation: 1279

Like
0Likes
Like

Posted 05 May 2012 - 04:46 PM

Oh, good catch on that one. After a little more playing around, it seems its FINALLY working. Along with fixing that, I also tried something new this time. The tutorial computes halfpixel as 0.5/width, 0.5/height, which doesnt match what your article says, so I had tried globally changing that to -1/width, 1/height, but that didn't help. This time I decided to change it only for the directional light shader and it worked (along with the previous changes). Thanks a lot for your help jischneider.

Heres the final, working shader code, in case anyone else runs into this problem

//Used to compute the world-position
float4x4 InvertViewProjection; 

//Position of the camera, for specular light
float3 CameraPosition; 

//Light Properties
float3 LightDirection;

//Color Properties
float4 DiffuseLightColor;
float4 AmbientLightColor;
float AmbientIntensity; 
float DiffuseIntensity; 

//Specular Properties
float SpecularPower;
float SpecularIntensity;

//Textures
float2 HalfPixel;


// diffuse color, and specularIntensity in the alpha channel
texture ColorMap; 
// normals, and specularPower in the alpha channel
texture NormalMap;
//depth
texture DepthMap;

sampler colorSampler = sampler_state
{
    Texture = (ColorMap);
    MagFilter = Linear;
    MinFilter = Linear;
    Mipfilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};
sampler depthSampler = sampler_state
{
    Texture = (DepthMap);
    MagFilter = Point;
    MinFilter = Point;
    Mipfilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};
sampler normalSampler = sampler_state
{
    Texture = (NormalMap);
    MagFilter = Point;
    MinFilter = Point;
    Mipfilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

struct VertexShaderInput
{
     float3 Position : POSITION0;
     float2 TexCoord : TEXCOORD0;
};

struct VertexShaderOutput
{
	float4 Position : POSITION0;
	float2 TexCoord : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
	VertexShaderOutput output;
	output.Position = float4(input.Position, 1);
	output.Position.xy += HalfPixel;

	output.TexCoord = input.TexCoord;

	return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	//get normal data from the normalMap
	float4 normalData = tex2D(normalSampler,input.TexCoord);

	//tranform normal back into [-1,1] range
	float3 normal = 2.0f * normalData.xyz - 1.0f;

	//get specular power, and get it into [0,255] range]
	float specularPower = saturate(normalData.a * SpecularPower) * 255;

	//get specular intensity from the colorMap
	float specularIntensity = saturate(tex2D(colorSampler, input.TexCoord).a * SpecularIntensity);

	//read depth
	float depthVal = tex2D(depthSampler,input.TexCoord).r;

	//Only the skybox has a depth this high, so stop processing and return white
	if(depthVal > 0.999f)
		return float4(1, 1, 1, 0);

    //compute screen-space position
    float4 position;
    position.x = input.TexCoord.x * 2.0f - 1.0f;
    position.y = -(input.TexCoord.y * 2.0f - 1.0f);
    position.z = depthVal;
    position.w = 1.0f;

    //transform to world space
    position = mul(position, InvertViewProjection);
    position /= position.w;

    //surface-to-light vector
    float3 lightVector = -normalize(LightDirection);

    //compute diffuse light
	float NdL = saturate(dot(normal, lightVector));
    float4 diffuseLight = (NdL * DiffuseLightColor * DiffuseIntensity) + (AmbientLightColor * AmbientIntensity);

    //reflexion vector
    float3 reflectionVector = normalize(reflect(-lightVector, normal));

    //camera-to-surface vector
    float3 directionToCamera = normalize(CameraPosition - position);

    float specularLight = specularIntensity * pow(saturate(dot(reflectionVector, directionToCamera)), specularPower);

     return float4(diffuseLight.rgb, specularLight);
}

technique Technique0
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}


#19 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 05 May 2012 - 04:51 PM

You are welcome.

I don't remember how I reach my formula, but I do remember that I was sure that it was the correct and of course it works very well for me. But if your engine is working why changed, right?

Bye!!!

Project page: < XNA FINAL Engine >





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS