• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Telanor

Artifacts in image that dont appear when using reference device

18 posts in this topic

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:
[attachment=8351:normal.png]

Force REF:
[attachment=8352:ref.png]
0

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
These are the render targets used by the deferred renderer:

[CODE]
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);
[/CODE]

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

Share this post


Link to post
Share on other sites
It's really strange. [img]http://public.gamedev.net//public/style_emoticons/default/unsure.png[/img]

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. [img]http://public.gamedev.net//public/style_emoticons/default/wacko.png[/img]
0

Share this post


Link to post
Share on other sites
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
0

Share this post


Link to post
Share on other sites
Yes. Set multisampling in the method Graphics_PreparingDeviceSettings

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

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.
0

Share this post


Link to post
Share on other sites
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:

[CODE]
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;
}
[/CODE]


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

[CODE]
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();
}
}
}
[/CODE]
0

Share this post


Link to post
Share on other sites
Everything looks good.

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

Share this post


Link to post
Share on other sites
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 [url="http://msdn.microsoft.com/en-us/library/windows/desktop/bb219690%28v=vs.85%29.aspx"]D3D9 pixel centre issues[/url]?
0

Share this post


Link to post
Share on other sites
[list=1]
[*]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 [url="http://blogs.msdn.com/b/shawnhar/archive/2007/01/31/debugging-xna-graphics-problems.aspx"]Shawn Hargreaves' guide[/url] 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
[/list]

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.
0

Share this post


Link to post
Share on other sites
I've figured out a few new things. First, the antialiasing was being turned on because of this:

[code]
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;

[/code]

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 [url="http://www.catalinzima.com/tutorials/deferred-rendering-in-xna/point-lights/"]Catalin Zima's tutorial[/url]. 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 [url="http://www.catalinzima.com/tutorials/deferred-rendering-in-xna/directional-lights/"]Catalin's directional light tutorial[/url], 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.
0

Share this post


Link to post
Share on other sites
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: [url="http://drilian.com/2008/11/25/understanding-half-pixel-and-half-texel-offsets/"]http://drilian.com/2...-texel-offsets/[/url] Edited by jischneider
0

Share this post


Link to post
Share on other sites
I tried output.Position.xy += HalfPixel and output.Position.xy -= HalfPixel in the vertex shader. The problem is still there
1

Share this post


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


[code]
//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();
}
}
[/code]
0

Share this post


Link to post
Share on other sites
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
1

Share this post


Link to post
Share on other sites
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

[code]
//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();
}
}
[/code]
0

Share this post


Link to post
Share on other sites
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!!!
0

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  
Followers 0