2013-09-12 3 views
7

Хорошо, поэтому я портировал игру, над которой я работал, в Monogame, но теперь у меня проблема с шейдером, когда она портирована. Это странная ошибка, так как она работает над моим старым проектом XNA, и она также работает в первый раз, когда я использую ее в новом проекте monogame, но не после этого, если я не перезапущу игру.Monogame Shader Porting Issues

Шейдер - это очень простой шейдер, который смотрит на изображение в оттенках серого и на основе серого выделяет цвет из текстуры поиска. В основном я использую это, чтобы рандомизировать изображение спрайта для противника каждый раз, когда на экран помещается новый враг. Он работает в первый раз, когда враг порождается, но после этого не работает, просто давая полностью прозрачную текстуру (а не нулевую текстуру).

Кроме того, я пока что нацелен на Windows Desktop, но в какой-то момент планирую настроить таргетинг на 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)); 

Если у кого есть идеи, чтобы исправить это, я действительно ценю это, и просто дайте мне знать, если вам нужно другая информация о проблеме.

ответ

0

Я не уверен, почему у вас есть знак «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)); 

, но не оба.

+0

Да, вы правы, что я не должен делать оба. Я этого не понимал. Хотя у меня все еще есть те же проблемы - работает для первой текстуры, прозрачной после этого. –

0

Я не вижу ничего сверх очевидного, просто просматривая его, но на самом деле это может быть сложно для кого-то выяснить, просто глядя на ваш код.

Я бы рекомендовал сделать графический профиль (через визуальную студию) и захватить фрейм, который корректно отображает фрейм рендеринга и сравнивает состояние двух.

Например, является входной текстурой, что вы ожидаете, что это будет, пикселы выводятся, но забито, является выходом правильно на цели визуализации (в этом случае проблема может быть Get/SetData) и т.д.

0

Измените ps_2_0 на ps_4_0_level_9_3.

Monogame не может использовать шейдер, построенные на HLSL 2.

Также встроенные в спрайте пакетного шейдера использует ps_4_0_level_9_3 и vs_4_0_level_9_3, вы получите проблемы, если вы пытаетесь заменить пиксельную часть шейдера с различным уровнем затенением.

Это единственная проблема, которую я вижу с вашим кодом.