1

我刚开始使用 XNA 的着色器,我遇到了一些我几乎没有立即理解的行为。

我创建了一个简单的场景,其中包含一个带纹理的盒子和一些地面,由一个使用重复纹理的单个纹理四边形组成(所以我的纹理坐标从 0,0 到 10,10 使其重复 10 次)。最初,这两个都使用了 BasicEffect 类。

然后我按照教程创建了我的第一个着色器并将其用于立方体 - 只不过是一个着色器,它在坐标坐标处返回纹理的颜色,为我提供与以前相同的纹理立方体。

然而奇怪的事情发生了——突然间,地面大部分是纯色的,有两个模糊的边缘和一个角落里的正确纹理实例。纹理不再重复。我将绘制立方体和地面的顺序更改为无效,仅注释掉立方体解决的问题。

然后我查看了我的着色器代码,大部分只是从教程中复制的,发现它为 AddressU 和 AddressV 指定了 Clamp。将其更改为 Wrap 解决了所有问题,但仍然给我留下了一个问题 - 为什么一个着色器的纹理环绕逻辑会影响基本着色器?这是一种正常的行为,我需要做某种状态保存吗,或者这是否表明我的代码中可能有另一个错误?

groundEffect.View = camera1.View; // BasicEffect
groundEffect.Projection = projection;
groundEffect.World = Matrix.CreateTranslation(0, -1.5f, 0);
groundEffect.TextureEnabled = true;
groundEffect.Texture = groundTexture;
GraphicsDevice.Indices = groundIndexBuffer;
GraphicsDevice.SetVertexBuffer(groundVertexBuffer);
foreach (EffectPass pass in groundEffect.CurrentTechnique.Passes)
{
    pass.Apply();
    GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, groundVertexBuffer.VertexCount, 0, groundIndexBuffer.IndexCount / 3); 
}


shaderEffect.Parameters["View"].SetValue(camera1.View);
shaderEffect.Parameters["Projection"].SetValue(projection);
shaderEffect.Parameters["World"].SetValue(modelPosition);
shaderEffect.Parameters["ModelTexture"].SetValue(boxTexture);
GraphicsDevice.Indices = model.IndexBuffer;
GraphicsDevice.SetVertexBuffer(model.VertexBuffer);
foreach (EffectPass pass in shaderEffect.CurrentTechnique.Passes)
{
    pass.Apply();
    GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, model.VertexBuffer.VertexCount, 0, model.IndexBuffer.IndexCount / 3);    
}
4

1 回答 1

1

渲染状态由四个状态对象控制:

GraphicsDevice.BlendState
GraphicsDevice.DepthStencilState
GraphicsDevice.RasterizerState
GraphicsDevice.SamplerStates[] // one for each sampler

他们在 XNA 4 中的介绍在这篇博文中进行了解释。

所有状态更改都通过这些变量或可以在.fx文件中设置。

IIRC,XNA 的内置Effect对象不使用任何一种方法设置状态 - 尽管SpriteBatch确实如此。

从您提供的代码中,我无法确定在您的情况下设置状态的是什么。通常我会猜这SpriteBatch是罪魁祸首(请参阅此博客文章) - 因为这出现了很多。但也许它在你的shaderEffect.

无论如何,在渲染之前简单地设置你想要的状态是完全合理的。以下是 3D 渲染的典型状态:

GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
于 2013-07-22T06:58:45.863 回答