是否存在需要在着色器之间重置的状态

时间:2013-07-21 14:46:33

标签: c# xna shader xna-4.0

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

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

然后我按照教程创建了我的第一个着色器并将其用于多维数据集 - 只不过是一个着色器,它在坐标坐标处返回纹理的颜色,给我与之前相同的纹理多维数据集。

然而奇怪的事情发生了 - 突然地面大部分都是纯色,有2个模糊边缘,角落里有一个合适质地的实例。纹理不再重复。我改变了我绘制立方体和地面的顺序没有效果,只是注释了立方体解决了问题。

然后我查看了我的着色器代码,大部分只是从教程中复制,并看到它为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);    
}

1 个答案:

答案 0 :(得分:1)

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

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

this blog post中解释了它们在XNA 4中的介绍。

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

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

我无法确定您所提供的代码中的状态设置是什么。通常我会猜测SpriteBatch是罪魁祸首(see this blog post) - 因为这会出现很多。但也许这是shaderEffect中的内容。

在任何情况下,在渲染之前简单地设置所需的状态是完全合理的。以下是3D渲染的典型状态:

GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;