Problems porting Monogame shaders

Ok, so I ported the game that I worked on in Monogame, but now I have a problem with the shader when it is ported. This is a strange mistake, since it works on my old XNA project, and it also works the first time I use it in a new monogame project, but not after that if I do not restart the game.

A shader is a very simple shader that looks at a grayscale image and extracts color from the search texture based on gray. I mainly use this to randomize an enemy sprite image every time a new enemy is placed on the screen. It works the first time the enemy spawns, but after that it doesn’t work, just giving a completely transparent texture (rather than a null texture).

In addition, so far I focus only on Windows Desktop, but at some point I plan to target Mac and Linux.

Here is the shader code itself.

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; iy = 1; //compare and swap if (color.r >= hair && color.r <= hairless) { ix = ((0.5 + seed + 96)/128); swap = tex2D(colorTableSampler,i); } if (color.r >= shirt && color.r <= shirtless) { ix = ((0.5 + seed + 64)/128); swap = tex2D(colorTableSampler,i); } if (color.r == 1) { ix = ((0.5 + seed + 32)/128); swap = tex2D(colorTableSampler,i); } if (color.r == 0) { ix = ((0.5 + seed)/128); swap = tex2D(colorTableSampler, i); } return swap; } technique ColorSwap { pass Pass1 { // TODO: set renderstates here. PixelShader = compile ps_2_0 PixelShaderFunction(); } } 

And here is the function that creates the texture. I should also note that texture generation works fine without a shader, I just get the basic image in grayscale.

 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; } 

And just in case, the code to load in the shader:

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

If anyone has any ideas to fix this, I would really appreciate it, and just let me know if you need other information about the problem.

+7
c # xna shader monogame
source share
3 answers

I'm not sure why you have an "at" (@) sign in front of the line when you avoid backslashes - if you don't want to have \\ in your line, but that looks weird in the file path.

You indicated in your code:

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

If you do not want \\ inside your line,

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

or

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

but do not use both.

0
source share

I don’t see anything beyond the obvious, just looking at it, but in fact it can be difficult for someone to figure out just by looking at your code.

I would recommend making a graphic profile (through a visual studio) and grab a frame that correctly displays the rendering frame and compares the state of the two.

For example, the input texture - what you expect from it - the pixels that are output but rejected are the correct result for the target rendering (in this case, the problem could be Get / SetData), etc.

0
source share

Change ps_2_0 to ps_4_0_level_9_3.

Monogame cannot use shaders built on HLSL 2.

In addition, the built-in sprite shader sprite uses ps_4_0_level_9_3 and vs_4_0_level_9_3, you will get problems if you try to replace the pixel part of the shader with another level shader.

This is the only problem I see with your code.

0
source share

All Articles