Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monogame Shader Porting Issues

Ok so I ported a game I have been working on over to Monogame, however I'm having a shader issue now that it's ported. It's an odd bug, since it works on my old XNA project and it also works the first time I use it in the new monogame project, but not after that unless I restart the game.

The shader is a very simple shader that looks at a greyscale image and, based on the grey, picks a color from the lookup texture. Basically I'm using this to randomize a sprite image for an enemy every time a new enemy is placed on the screen. It works for the first time an enemy is spawned, but doesn't work after that, just giving a completely transparent texture (not a null texture).

Also, I'm only targeting Windows Desktop for now, but I am planning to target Mac and Linux at some point.

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

And here is the function that creates the texture. I should also note that the texture generation works fine without the shader, I just get the greyscale base image.

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 for loading 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 ideas to fix this, I'd really appreciate it, and just let me know if you need other info about the problem.

like image 208
Shane S Avatar asked Sep 12 '13 00:09

Shane S


People also ask

How to use the MonoGame spritebatch shaders?

Draw(_image,newVector2(0,0),Color. White);_spriteBatch. End(); Give the shader to the MonoGame SpriteBatch and draw the image texture at the world position (0, 0). Behind the scene, the SpriteBatch will setup the texture sampler in slot 0 for us. We also pass in a color. For this shader, the color is used as a tint color.

What is the x axis in a shader?

In the shader, the color becomes a floating point value between 0 and 1. For example white is (1, 1, 1, 1). White with a 50% opacity becomes (0.5, 0.5, 0.5, 0.5). TexCoordis in UV coordinates. It’s a floating point value between 0 and 1. On the X axis, 0 means the left side of the texture and 1 means the right side.

What is the difference between position and color in a shader?

This structure gets passed to the vertex shader. Position is in the world coordinate. Color is the value passed in the SpriteBatch draw call. Earlier we set it to white. In the shader, the color becomes a floating point value between 0 and 1. For example white is (1, 1, 1, 1).

What does 50% opacity mean in a shader?

In the shader, the color becomes a floating point value between 0 and 1. For example white is (1, 1, 1, 1). White with a 50% opacity becomes (0.5, 0.5, 0.5, 0.5). TexCoordis in UV coordinates.


1 Answers

I am not sure why you have "at" (@) sign in front of the string, when you escaped backslash - unless you want to have \\ in your string, but it looks strange in the file path.

You have wrote in your code:

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

Unless you want \\ inside your string do

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.

like image 102
recineshto Avatar answered Sep 29 '22 10:09

recineshto