【问题标题】:Monogame Shader Porting IssuesMonogame 着色器移植问题
【发布时间】:2013-09-12 00:31:23
【问题描述】:

好的,所以我将我一直在开发的游戏移植到 Monogame,但是现在我遇到了着色器问题,因为它已经移植了。这是一个奇怪的错误,因为它适用于我的旧 XNA 项目,并且在我第一次在新的 monogame 项目中使用它时也有效,但除非我重新启动游戏,否则之后就不行了。

着色器是一个非常简单的着色器,它查看灰度图像,并根据灰度从查找纹理中选择一种颜色。基本上,每次在屏幕上放置一个新敌人时,我都会使用它来随机化一个敌人的精灵图像。它在第一次生成敌人时起作用,但在那之后就不起作用了,只是给出一个完全透明的纹理(不是空纹理)。

另外,我现在只针对 Windows 桌面,但我计划在某个时候以 Mac 和 Linux 为目标。

这是着色器代码本身。

sampler input : register(s0);
Texture2D colorTable;
float seed; //calculate in program, pass to shader (between 0 and 1)

sampler colorTableSampler = 
sampler_state
{
    Texture = <colorTable>;
};

float4 PixelShaderFunction(float2 c: TEXCOORD0) : COLOR0
{
    //get current pixel of the texture (greyscale)
    float4 color = tex2D(input, c);
    //set the values to compare to.
    float hair = 139/255; float hairless = 140/255;
    float shirt = 181/255; float shirtless = 182/255;
    //var to hold new color
    float4 swap;
    //pixel coordinate for lookup
    float2 i;
    i.y = 1;

    //compare and swap
    if (color.r >= hair && color.r <= hairless)
    {
        i.x = ((0.5 + seed + 96)/128);
        swap = tex2D(colorTableSampler,i);
    }
    if (color.r >= shirt && color.r <= shirtless)
    {
        i.x = ((0.5 + seed + 64)/128);
        swap = tex2D(colorTableSampler,i);
    }
    if (color.r == 1)
    {
        i.x = ((0.5 + seed + 32)/128);
        swap = tex2D(colorTableSampler,i);
    }
    if (color.r == 0)
    {
        i.x = ((0.5 + seed)/128);
        swap = tex2D(colorTableSampler, i);
    }

    return swap;
}

technique ColorSwap
{
    pass Pass1
    {
        // TODO: set renderstates here.

        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

这里是创建纹理的函数。我还应该注意,没有着色器的纹理生成工作正常,我只得到灰度基础图像。

public static Texture2D createEnemyTexture(GraphicsDevice gd, SpriteBatch sb)
        {
            //get a random number to pass into the shader.
            Random r = new Random();
            float seed = (float)r.Next(0, 32);
            //create the texture to copy color data into
            Texture2D enemyTex = new Texture2D(gd, CHARACTER_SIDE, CHARACTER_SIDE);
            //create a render target to draw a character to.
            RenderTarget2D rendTarget = new RenderTarget2D(gd, CHARACTER_SIDE, CHARACTER_SIDE,
                false, gd.PresentationParameters.BackBufferFormat, DepthFormat.None);
            gd.SetRenderTarget(rendTarget);
            //set background of new render target to transparent.
            //gd.Clear(Microsoft.Xna.Framework.Color.Black);
            //start drawing to the new render target
            sb.Begin(SpriteSortMode.Immediate, BlendState.Opaque,
                    SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone);
            //send the random value to the shader.
            Graphics.GlobalGfx.colorSwapEffect.Parameters["seed"].SetValue(seed);
            //send the palette texture to the shader.            
            Graphics.GlobalGfx.colorSwapEffect.Parameters["colorTable"].SetValue(Graphics.GlobalGfx.palette);
            //apply the effect
            Graphics.GlobalGfx.colorSwapEffect.CurrentTechnique.Passes[0].Apply();
            //draw the texture (now with color!)
            sb.Draw(enemyBase, new Microsoft.Xna.Framework.Vector2(0, 0), Microsoft.Xna.Framework.Color.White);
            //end drawing
            sb.End();
            //reset rendertarget
            gd.SetRenderTarget(null);
            //copy the drawn and colored enemy to a non-volitile texture (instead of render target)
            //create the color array the size of the texture.
            Color[] cs = new Color[CHARACTER_SIDE * CHARACTER_SIDE];
            //get all color data from the render target
            rendTarget.GetData<Color>(cs);
            //move the color data into the texture.
            enemyTex.SetData<Color>(cs);
            //return the finished texture.
            return enemyTex;
        }

为了以防万一,在着色器中加载的代码:

BinaryReader Reader = new BinaryReader(File.Open(@"Content\\shaders\\test.mgfx", FileMode.Open));
colorSwapEffect = new Effect(gd, Reader.ReadBytes((int)Reader.BaseStream.Length));

如果有人有解决此问题的想法,我将不胜感激,如果您需要有关此问题的其他信息,请告诉我。

【问题讨论】:

    标签: c# xna shader monogame


    【解决方案1】:

    当你转义反斜杠时,我不确定为什么你在字符串前面有“at”(@)符号 - 除非你想在你的字符串中包含 \\,但它在文件路径中看起来很奇怪。

    你在你的代码中写过:

    BinaryReader Reader = new BinaryReader(File.Open(@"Content\\shaders\\test.mgfx", FileMode.Open));
    

    除非你想 \\ 在你的字符串中做

    BinaryReader Reader = new BinaryReader(File.Open(@"Content\shaders\test.mgfx", FileMode.Open));
    

    BinaryReader Reader = new BinaryReader(File.Open("Content\\shaders\\test.mgfx", FileMode.Open));
    

    但不要同时使用。

    【讨论】:

    • 是的,你是对的,我不应该两者都做。我没听懂。虽然我仍然有同样的问题 - 适用于第一个纹理,之后是透明的。
    【解决方案2】:

    我没有看到任何非常明显的内容,只是阅读它,但实际上这对于仅查看您的代码的人来说可能很棘手。

    我建议做一个图形配置文件(通过视觉工作室)并捕获正确渲染的帧然后帧渲染不正确并比较两者的状态。

    例如,输入纹理是否符合您的预期,像素是否正在输出但被剔除,渲染目标上的输出是否正确(在这种情况下,问题可能是 Get/SetData)等等。

    【讨论】:

      【解决方案3】:

      将 ps_2_0 更改为 ps_4_0_level_9_3。

      Monogame 不能使用基于 HLSL 2 构建的着色器。

      此外,内置精灵批处理着色器使用 ps_4_0_level_9_3 和 vs_4_0_level_9_3,如果您尝试用不同级别的着色器替换着色器的像素部分,则会遇到问题。

      这是我在您的代码中看到的唯一问题。

      【讨论】: