【问题标题】:How can I restore default shaders in XNA?如何恢复 XNA 中的默认着色器?
【发布时间】:2014-03-25 16:16:31
【问题描述】:

我对 XNA 有点陌生,我正在使用 BEPU 物理创建一个 3D 游戏(这是大学课程所必需的)。我正在尝试从 Microsoft 的粒子示例中实现一个简单的粒子系统。在粒子的 Draw() 方法中,执行如下代码:

// Activate the particle effect.
foreach (EffectPass pass in particleEffect.CurrentTechnique.Passes)
{
    pass.Apply();

    //Draw particle primitives
    ...

}

CurrentTechnique.Passes 中有一个名为 P0 的 pass,它对应于粒子效果 FX 文件中的以下 pass:

// Effect technique for drawing particles.
technique Particles
{
    pass P0
    {
        VertexShader = compile vs_2_0 ParticleVertexShader();
        PixelShader = compile ps_2_0 ParticlePixelShader();
    }
}

但是,此操作会导致我的某些模型的 UV 贴图渲染不正确,并且除了用于粒子系统的着色器之外,我没有使用任何自定义着色器。是否可以有效地撤消应用此通道的效果以绘制我的其他模型?我可以在游戏的主 Draw() 循环开始时调用 GraphicsDevice.Reset(),这解决了问题,但在全屏模式下,每次调用 GraphicsDevice.Reset() 时屏幕都会闪烁黑屏。

【问题讨论】:

    标签: 3d xna shader xna-4.0


    【解决方案1】:

    您需要将必要的渲染状态显式设置为适合您的模型的任何内容。渲染代码(在 XNA 或其他方式中)以您期望的方式“自行清理”是不常见的;这将是通常不必要的额外费用。相反,通常假设如果您需要在渲染之前以某种方式设置设备,那么您当时会自己这样做,如果您没有明确设置某些东西,那么您可以随意设置价值。

    当您说您的模型“渲染不正确”时,很难确切知道出了什么问题,但我建议您调查 GraphicsDevice 上的以下属性:

    MSDN 文档指定了它们的默认值,因此您可以尝试显式重置它们。您不太可能需要重置所有这些;根据您所写的内容,我的猜测是SamplerStates 可能是罪魁祸首。了解每个人的工作,并尝试了解它可能如何影响您所看到的内容。

    绝对不要打电话给GraphicsDevice.Reset().,这太过分了,而且不是为了这个目的。

    【讨论】:

    • 这是一个非常有用的答案。每次渲染粒子时,我已经在保存/恢复 BlendState 和 DepthStencilState,这修复了一些深度缓冲区问题。不幸的是,保存/恢复任何其他 GraphicsDevice 状态并没有为我解决任何问题,但我遇到了一个不同的解决方案并将其作为单独的答案发布。
    【解决方案2】:

    Cole Campbell 对我的问题的回答绝对可以帮助解决一些着色器问题,因此如果您遇到类似问题,请务必查看一下。但是,当我发现 FX 文件中使用了以下采样器代码时,我解决了我的问题:

    sampler Sampler = sampler_state
    {
        Texture = (Texture);    
    
        ...
    
        AddressU = Clamp;
        AddressV = Clamp;
    };
    

    我的模型纹理应该是包裹的,但正如您所见,着色器被设置为钳制纹理(这是我的纹理扭曲的来源)。粒子系统实际上并不需要固定纹理,因此我将上述代码中的两个值都设置为Wrap 而不是Clamp。这解决了我的问题!

    【讨论】:

    • 注意,这相当于在GraphicsDevice上设置了相关的SamplerState。应用着色器时,着色器中的值会覆盖 XNA 中设置的值。
    • 啊,我明白了。好吧,我得到了一些有趣的结果。我现在发现,如果我设置 GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap、 和 我调用 spriteBatch.Begin() 和 spriteBatch.End()(我将其用于简单的 2D HUD ) 在我的 Draw() 循环中的某处。
    • 如果您在渲染模型之前手动设置采样器状态,SpriteBatch 会对其产生任何影响,这非常奇怪。 Begin() 和 End() 只是设置相同的渲染状态。我觉得你渲染模型的方式必须有其他事情发生。你能发布那个代码吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多