锯齿状边缘和奇怪的阴影效果

4
我正在使用从Microsoft网站下载的嵌入WinForms的XNA。我注意到当模型被绘制时,一切看起来都很好,但是一旦我旋转我的摄像机,模型边缘开始变得有锯齿。以下是两张相关的图片: 这在摄像机靠近目标物体时更加明显。我使用以下代码来绘制每个网格:
foreach (ModelMesh mesh in model.Meshes)
{
    foreach (BasicEffect effect in mesh.Effects)
    {
        effect.View = cam.view;
        effect.Projection = cam.projection;
        effect.World = mesh.ParentBone.Transform;
        effect.EnableDefaultLighting();
    }
    mesh.Draw();
}

有时候当我旋转模型时,会出现奇怪的阴影。阴影甚至不会改变它们的“位置”,但是仍然以完全相同的方式绘制。
编辑: 我Google了一下,发现启用多重采样应该可以消除锯齿。那么,有人知道如何在WinForms中实现这一点吗? 编辑2: 关于后备缓冲区,我没有在任何地方设置它,所以我想它就像它应该的那样。这是GraphicsDeviceService.cpp构造函数:
    GraphicsDeviceService(IntPtr windowHandle, int width, int height)
    {
        parameters = new PresentationParameters();

        parameters.BackBufferWidth = Math.Max(width, 1);
        parameters.BackBufferHeight = Math.Max(height, 1);
        parameters.BackBufferFormat = SurfaceFormat.Color;
        parameters.DepthStencilFormat = DepthFormat.Depth24;
        parameters.DeviceWindowHandle = windowHandle;
        parameters.PresentationInterval = PresentInterval.Immediate;
        parameters.IsFullScreen = false;

        graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
                                            GraphicsProfile.Reach,
                                            parameters);
    }

此外,reset方法会相应地设置backBuffer。

编辑3: 我尝试将MultiSampleCount设置为更大的数字,但没有帮助,现在有两张图片展示了发生的情况。首先,我在某个位置实例化对象,然后只向右移动相机。整个对象会被拉伸并出现锯齿状边缘,如下图所示。这是相机移动代码:

http://img152.imageshack.us/img152/5204/normalu.png

http://img28.imageshack.us/img28/4434/movedright.png

KeyboardState state = Keyboard.GetState();

Vector3 v;

if (state.IsKeyDown(Keys.Up) || state.IsKeyDown(Keys.W))
    v = new Vector3(0, 0, 1) * moveSpeed;
else if (state.IsKeyDown(Keys.Down) || state.IsKeyDown(Keys.S))
    v = new Vector3(0, 0, -1) * moveSpeed;
else if (state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A))
    v = new Vector3(1, 0, 0) * moveSpeed;
else if (state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D))
    v = new Vector3(-1, 0, 0) * moveSpeed;
else if (state.IsKeyDown(Keys.PageUp))
    v = new Vector3(0, -1, 0) * moveSpeed;
else if (state.IsKeyDown(Keys.PageDown))
    v = new Vector3(0, 1, 0) * moveSpeed;
else
    v = new Vector3(0, 0, 0);

view *= Matrix.CreateTranslation(v);

相机视图和投影:

view = Matrix.CreateLookAt(cameraPos, Vector3.Zero, Vector3.Up);
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45f), ratio, 0.5f, 50f);

在这种情况下,cameraPos是0,0,10

编辑:投影 我最终得到了一个投影问题的图片。正如您所看到的,每个网格都有自己的阴影,而不是只有一个阴影穿过所有网格。

http://img843.imageshack.us/img843/8263/weirdshadowing.png

这是一个模型的俯视图。


多重采样可能有助于解决问题。但我认为根源在其他地方,因为楼梯看起来比平常大一点。您确定后备缓冲区的分辨率等于呈现到的控件的分辨率吗?奇怪的阴影可能是模型中某些法线计算错误的结果。 - Nico Schertler
谢谢您的回复。 那么我该如何启用多重采样? - user1806687
只需设置 graphics.PreferMultiSampling = true; 但正如我所说,我怀疑这并不是解决您问题的实际方法。您是否检查过分辨率? - Nico Schertler
你已经解决了这个问题吗? - Lucius
1个回答

3

XNA嵌入WinForms的抗锯齿

这个问题实际上是这个问题的副本。

在此处下载XNA/WinForms示例

在您的GraphicsDeviceService类文件中导航到构造函数:

GraphicsDeviceService(IntPtr windowHandle, int width, int height)
{
    parameters = new PresentationParameters();

    // Add this line
    // Increase the count to get higher quality anti-aliasing
    parameters.MultiSampleCount = 8;

    // More parameter settings and initialization
    // ...
}

您可以在下面的图像中看到差异:

with and without multisampling comparison


旧答案

XNA应用程序的抗锯齿

graphics.PreferMultiSampling = true;

将文本翻译成中文:

根据这篇 MSDN文章,可以为后备缓冲启用抗锯齿。

PreferMultiSampling 属性是 GraphicsDeviceManager 类的成员之一。

提高/降低质量

MultiSampleCount 属性是 PresentationParameter 类的一个属性,可用于更改样本数。每像素更多的样本意味着更少的伪影和增加的渲染时间。


关于多重采样的进一步阅读


请注意,如果问题的根源在于图形管道,更具体地说是光栅化器,则此解决方案仅有效。
正如Nico Schertler所指出的那样,请确保在将图像嵌入WinForms过程中未更改图像分辨率。如果边缘上的步骤不恰好为一个像素宽,则强烈表明问题来自于在WinForms中呈现纹理。
我无法在此处解决阴影问题,因为很难从图像中猜测光照设置。

没有 GraphicsDevice.PreferMutliSampling 这样的东西,只有 GraphicsDevice.RasterizerState.MultiSampleAntiAlias,我无法将其设置为 true,但它默认已经设置为 true。所以,看起来你是正确的,多重采样不是问题。当我检查 GraphicsDevice.DisplayMode 的宽度和高度属性时,它与控件的宽度和高度不匹配。但是,GraphicsDevice.Viewport 的宽度和高度与控件的大小相匹配。那么哪一个是不正确的呢? - user1806687
PreferMultiSampling 属性是 GraphicsDeviceManager 类的成员,不是 GraphicsDevice 类的成员。默认情况下,您的游戏类中应该有一个名为 graphics 的字段。请确保阅读我在答案中已经链接到的 MSDN 文章,并尝试按照步骤操作。 对于宽度和高度:关键是后备缓冲区的大小。检查 graphics.PreferredBackBufferWidthgraphics.PreferredBackBufferHeight - Lucius
1
WinForms 中没有 Game 类 :/ - user1806687
我一开始没有检查示例。现在我的答案包括WinForms示例的说明。 - Lucius
我也尝试过下载那个示例并在其中设置MultiSampleCount,但没有任何变化。你对那个示例项目做了其他更改吗?或者可能是我的显卡不支持这个功能? - user1806687
1
我也重新下载了这个示例。只需要设置“MultiSampleCount”就可以让它在我的设备上运行了。可能与你的显卡有关,但我对此并不是专家。至少我们似乎已经缩小了问题的范围。祝你好运! - Lucius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接