Shaders

I’m trying to use a shader to replace the texture of a sprite as seen in:-
https://gmjosack.github.io/posts/my-first-2d-pixel-shaders-part-1/
goto part 3 he replaces a texture via a shader, watch the video seems to work, follow the instructions, not so much, here’s my shader

texture rainbowpic;
sampler MySampler  = sampler_state
{
  Texture = <rainbowpic>;
};
sampler s0;
float4 PixelShaderFunction(float2 coords : TEXCOORD0) : COLOR0
{
  float4 color = tex2D(s0, coords);
  float4 rainbow_color = tex2D(MySampler , coords);
  if(color.a)
  {
    return rainbow_color;
  }
  return color;
}
technique Technique1
{
  pass Pass1
  {
    PixelShader = compile ps_3_0 PixelShaderFunction();
  }
}

and here’s the calls from inside my app

//defs
Texture2D texture;
Texture2D rainbow;
Effect effect;
// loadcontent
      texture = Content.Load<Texture2D>("textimage");
      rainbow = Content.Load<Texture2D>("rainbow");
      effect = Content.Load<Effect>("Effect1");
// draw
      spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
      // heres the shader at work
      effect.Parameters["rainbowpic"].SetValue(rainbow);
      effect.CurrentTechnique.Passes[0].Apply();
      spriteBatch.Draw(texture, new Vector2(0, 0), Color.White);
      spriteBatch.End();

Any help would be appreciated

Try setting the sampler register explicitly to make sure s0 is at sampler slot s0.

Also, it’s cleaner to pass the effect to the SpriteBatch.Begin call instead of explicitly applying it.

changed spritebatch.begin to

spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend,null,null,null,effect,null);

changed shader to
sampler MySampler : register(s0) = sampler_state
{
Texture = (rainbowpic);
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
didn’t do diddly
anything else?

Not off the top of my head, I’ll try this in the weekend! :slight_smile:

SpriteBatch shaders Inputs must match exactly with the data being passed from the SpriteBatch, so you should use

{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0, ;
	float2 TextureCoordinates : TEXCOORD0;
};```

or 

```float4 PixelShaderFunction(float4 Position : SV_POSITION, float4 Color : COLOR0, float2 coords : TEXCOORD0) : COLOR0```

Otherwise you get the wrong data. This is a side effect of using a DX 11 shader compiler I think. DX 9 was more forgiving

not using directX using windows in openGL mode via monogame support, good to know though, thx
either way the structure isn’t needed, I can change colors real easy, I can even make a light pass over my sprite but the one thing I want it to do that don’t work is change texture, here’s my goal
You ever seen the really nice scrolling raster bars on a C64? you tube search for ALLEYKAT you’ll see them, I want to do the same effect on the title screen of a game I’m about finished with, textured shaders would be perfect, I can manipulate the texture and let the shader do the rest, I’ve searched everywhere on how to do it, light demos out the wazoo but textureing, nada, I know it can be done I’ve yet to see an example of it done, if you have one, send it to me or post it
Thx
tried your method FYI, did nothing different

If i remember well, glsl is ‘converted’ to hlsl in order to compile the effect. You need dx to create glsl effects in fact. (not sure 100% this may have changed since then)

the shader compiler for openGL does use DX

First we Compile the HLSL to a compiled DX shader when we run it through a converter to convert the compiled code into GL compatible code.
So in effect you always use the Dx compiler (at the moment).

Hopefully someone can try to port that sample and see if we get the same issues.

Just finished testing R.B.Whitikers demo and both lighting demo’s don’t work either
http://rbwhitaker.wikidot.com/specular-lighting-shader
He’s usually pretty good, i just used his code via monogame and not XNA, could this be a problem with monogame?
I’m in the process of converting backwards to XNA, if his stuff works then I fear it very well could be a monogame issue,
if it is i REALLY need some help, just as an FYI with the above comments, i also have a monogame DirectX version and get the same results, change colors fine (grey scale/invert) etc but changing textures, nada.
I don’t think it’s a HLSL - GLSL issue as it won’t work on either platform?
Suggestions?

I and several others have run into an issue with MonoGame where registering textures for samplers doesn’t work. You can instead pass the textures as parameters and sample from them. That could possibly explain the issue with your own shader here, but I’m not sure why RB Whitaker’s wouldn’t work.

Considering how complex titles are running in monogame it is very unlike that you came across monogame issue at such basic level as simple shader. Are you rendering into render targets?

Texture samplers works differently, that’s the truth, there are two work arounds, one is to send texture as parameter instead assigning it to sampler as jnoyola said.

About this: http://rbwhitaker.wikidot.com/specular-lighting-shader send screenshot of your result.

I agree i also doubt very much that it is monogame, I’ve googled a bunch of xna-monogame conversion problems and come across: “the lighting won’t convert” and “i don’t see my textures” all solutions given yield the same results i’m getting, very frustrating, I’ve asked Whitakers website for any info he might have?
You mentioned work arounds (2) what are they plz, example would be nice, below are the screen shots you asked for, obviously in mine (first one) i changed the background color for you to see the model, this is the exact copy of whitakers XNA diffuse example

Mine

Whitakers

Please help, FYI Ambient demo works, from then on they don’t

Alright, either show me your draw code or share whole project you have to this point. Or you know what, first of all make sure your model has proper normals. Also you can go through shader step by step, first simply try to to return float4(1,0,0,1), you should get red sillhouette, if that´s alright continue, render normals (send them as color output from vertex shader and just output them and only them in pixel shader and so on).

Here is the shader
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor = float4 (1, 1, 1, 1);
float AmbientIntensity = 0.1;

float4x4 WorldInverseTranspose;
float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 0, 1, 1);
float DiffuseIntensity = 1.0;

struct VertexShaderInput
{
  float4 Position : POSITION;
  float4 Normal : NORMAL;
};
struct VertexShaderOutput
{
  float4 Position : POSITION;
  float4 Color : COLOR0;
};

/*********************************************************************************************
Function Name : VertexShaderFunction
Description : this handles the vertices
*********************************************************************************************/
VertexShaderOutput VertexShaderFunction (VertexShaderInput input)
{
  VertexShaderOutput output;

  float4 worldPosition = mul (input.Position, World);
  float4 viewPosition = mul (worldPosition, View);
  output.Position = mul (viewPosition, Projection);
  float4 normal = mul (input.Normal, WorldInverseTranspose);
  float lightIntensity = dot (normal, DiffuseLightDirection);
  output.Color = saturate (DiffuseColor * DiffuseIntensity * lightIntensity);
  return output;
}

/*********************************************************************************************
Function Name : PixelShaderFunction
Description : this handles the pixels
**********************************************************************************************/
float4 PixelShaderFunction (VertexShaderOutput input) : COLOR0
{
    return saturate(input.Color + AmbientColor * AmbientIntensity);
}

technique Diffuse
{
	pass Pass1
	{
		VertexShader = compile VS_SHADERMODEL VertexShaderFunction();
		PixelShader = compile PS_SHADERMODEL PixelShaderFunction();
	}
};

and here is the call code

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;

namespace Whitakers_Shaders
{
  /// <summary>
  /// This is the main type for your game.
  /// </summary>
  /// 
/*
  Matrix world = Matrix.CreateTranslation(0, 0, 0);
  Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
  Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 1024f / 768f, 0.1f, 240f);
  float angle = 0;
  float distance = 85;
*/


  public class Game1 : Game
  {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Effect effect;

    Matrix world = Matrix.CreateTranslation(0, 0, 0);
    Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
    Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 1024f / 768f, 0.1f, 240f);

    float angle = 0;
    float distance = 85;

    Model model;

    public Game1()
    {
      graphics = new GraphicsDeviceManager(this);
      Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
      base.Initialize();
    }

    protected override void LoadContent()
    {
      spriteBatch = new SpriteBatch(GraphicsDevice);

      model = Content.Load<Model>("Models/Helicopter");
      effect = Content.Load<Effect>("Effects/Diffuse");
    }

    protected override void UnloadContent()
    {
    }

    protected override void Update(GameTime gameTime)
    {
      if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed|| Keyboard.GetState().IsKeyDown(Keys.Escape))
        this.Exit();

      angle += 0.01f;
      view = Matrix.CreateLookAt(distance * new Vector3((float)Math.Sin(angle), 0, (float)Math.Cos(angle)), new Vector3(0, 0, 0), new Vector3(0, 1, 0));

      base.Update(gameTime);
    }
    protected override void Draw(GameTime gameTime)
    {
      GraphicsDevice.Clear(Color.CornflowerBlue);

//      DrawModel(model, world, view, projection);

      DrawModelWithEffect(model, world, view, projection);

      base.Draw(gameTime);
    }

#region Regular Draw
    private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
    {
      foreach (ModelMesh mesh in model.Meshes)
      {
        foreach (BasicEffect effect in mesh.Effects)
        {
          effect.EnableDefaultLighting();
          effect.PreferPerPixelLighting = true;
          effect.World = world * mesh.ParentBone.Transform;
          effect.View = view;
          effect.Projection = projection;
        }
        mesh.Draw();
      }
    }
#endregion

    private void DrawModelWithEffect(Model model, Matrix world, Matrix view, Matrix projection)
    {
      foreach (ModelMesh mesh in model.Meshes)
      {
        foreach (ModelMeshPart part in mesh.MeshParts)
        {
          part.Effect = effect;
          effect.Parameters["World"].SetValue(world * mesh.ParentBone.Transform);
          effect.Parameters["View"].SetValue(view);
          effect.Parameters["Projection"].SetValue(projection);
          // setting the ambient color
//          effect.Parameters["AmbientColor"].SetValue(Color.Green.ToVector4());
//          effect.Parameters["AmbientIntensity"].SetValue(0.5f);
          Matrix worldInverseTransposeMatrix = Matrix.Transpose(Matrix.Invert(mesh.ParentBone.Transform * world));
          effect.Parameters["WorldInverseTranspose"].SetValue(worldInverseTransposeMatrix);
        }
        mesh.Draw();
      }
    }
  }
}

hope that helps

float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor = float4 (1, 1, 1, 1);
float AmbientIntensity = 0.1;

float4x4 WorldInverseTranspose;
float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 0, 1, 1);
float DiffuseIntensity = 1.0;

struct VertexShaderInput
{
  float4 Position : POSITION;
  float4 Normal : NORMAL;
};
struct VertexShaderOutput
{
  float4 Position : POSITION;
  float4 Color : COLOR0;
};

/*********************************************************************************************
Function Name : VertexShaderFunction
Description : this handles the vertices
*********************************************************************************************/
VertexShaderOutput VertexShaderFunction (VertexShaderInput input)
{
  VertexShaderOutput output;

  float4 worldPosition = mul (input.Position, World);
  float4 viewPosition = mul (worldPosition, View);
  output.Position = mul (viewPosition, Projection);
  float4 normal = mul (input.Normal, WorldInverseTranspose);
  float lightIntensity = dot (normal, DiffuseLightDirection);
  output.Color = normal;
  return output;
}

/*********************************************************************************************
Function Name : PixelShaderFunction
Description : this handles the pixels
**********************************************************************************************/
float4 PixelShaderFunction (VertexShaderOutput input) : COLOR0
{
    return saturate(input.Color);
}

technique Diffuse
{
	pass Pass1
	{
		VertexShader = compile VS_SHADERMODEL VertexShaderFunction();
		PixelShader = compile PS_SHADERMODEL PixelShaderFunction();
	}
};

Use this shader and send me screenshot.

Ok, now this one and screenshot

Good, so we know that shader is actually assigned and that your normals are broken (I mean to be sure it would be reasonable request to ask you to map them into 0 - 1 range by doing 2 * normals -1 buuut since you were adding ambient and it was still black I am gonna suppose they are really broken)… you know, for fun of it, one more try to be on safe side:

float4x4 World;
float4x4 View;
float4x4 Projection;

float4 AmbientColor = float4 (1, 1, 1, 1);
float AmbientIntensity = 0.1;

float4x4 WorldInverseTranspose;
float3 DiffuseLightDirection = float3(1, 0, 0);
float4 DiffuseColor = float4(1, 0, 1, 1);
float DiffuseIntensity = 1.0;

struct VertexShaderInput
{
  float4 Position : POSITION;
  float4 Normal : NORMAL;
};
struct VertexShaderOutput
{
  float4 Position : POSITION;
  float4 Color : COLOR0;
};

/*********************************************************************************************
Function Name : VertexShaderFunction
Description : this handles the vertices
*********************************************************************************************/
VertexShaderOutput VertexShaderFunction (VertexShaderInput input)
{
  VertexShaderOutput output;

  float4 worldPosition = mul (input.Position, World);
  float4 viewPosition = mul (worldPosition, View);
  output.Position = mul (viewPosition, Projection);
  float lightIntensity = dot (normal, DiffuseLightDirection);
  output.Color = float4(2 * input.Normal.rgb - 1, 1);
  return output;
}

/*********************************************************************************************
Function Name : PixelShaderFunction
Description : this handles the pixels
**********************************************************************************************/
float4 PixelShaderFunction (VertexShaderOutput input) : COLOR0
{
    return saturate(input.Color);
}

technique Diffuse
{
	pass Pass1
	{
		VertexShader = compile VS_SHADERMODEL VertexShaderFunction();
		PixelShader = compile PS_SHADERMODEL PixelShaderFunction();
	}
};

build error undeclared “normal”
float lightIntensity = dot (normal, DiffuseLightDirection);