NullReferenceException when passing texture to .fx file

Hi guys! I am developing a game in visual basic and monogame and recently updated from monogame 3.4 to 3.5. In the update process the fx file for my guassian blur effect stopped working. Apparently the update forced me to change the pixel shader to “PixelShader = compile ps_3_0 PS_GaussianBlur();”. This made it so the fx file will load, but now when I try to use it I get a nullReferenceExcpetion when passing the starting image into the file. Here is the code for the fx file:

#define RADIUS 7
#define KERNEL_SIZE (RADIUS * 2 + 1)

//-----------------------------------------------------------------------------
// Globals.
//-----------------------------------------------------------------------------

float weights[KERNEL_SIZE];
float2 offsets[KERNEL_SIZE];

//-----------------------------------------------------------------------------
// Textures.
//-----------------------------------------------------------------------------

texture2D colorMapTexture;

sampler colorMap : register(s0);

//-----------------------------------------------------------------------------
// Pixel Shaders.
//-----------------------------------------------------------------------------

float4 PS_GaussianBlur(float4 pos : SV_POSITION, float4 color1 : COLOR0, float2 texCoord : TEXCOORD0) : SV_TARGET0
{
float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f);

for (int i = 0; i < KERNEL_SIZE; ++i)
color += colorMapTexture.Sample(colorMap, texCoord.xy + offsets[i]) * weights[i];

return color;
}

//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------

technique GaussianBlur
{
pass
{
PixelShader = compile ps_3_0 PS_GaussianBlur();
}
}

And here is the code for the function that blurs the image in my game:

Public Shared Function blurImage(img As Texture2D, sb As SpriteBatch, ByRef blurTarget1 As RenderTarget2D, ByRef blurTarget2 As RenderTarget2D) As Texture2D
'Return img 'BROKEN
Dim radius As Integer = 2 : Dim amount As Single = 1.0F
Dim sigma As Single = radius / amount : Dim kernel As Single() = New Single(radius * 2) {}
Dim index As Integer = 0 : Dim total As Single = 0F : Dim distance As Single = 0F
Dim twoSigmaSquare As Single = 2.0F * sigma * sigma : Dim sigmaRoot As Single = CSng(Math.Sqrt(twoSigmaSquare * Math.PI))
Dim offsetsHoriz As Vector2() = New Vector2(radius * 2) {} : Dim offsetsVert As Vector2() = New Vector2(radius * 2) {}
Dim effect As Effect = content.Load(Of Effect)(“Effects\GaussianBlur”)

    For i As Integer = -radius To radius
        index = i + radius
        offsetsHoriz(index) = New Vector2(i * 1.0F / img.Width, 0F)
        offsetsVert(index) = New Vector2(0F, i * 1.0F / img.Height)
    Next
    index = 0
    For i As Integer = -radius To radius
        distance = i * i : index = i + radius
        kernel(index) = CSng(Math.Exp(-distance / twoSigmaSquare)) / sigmaRoot
        total += kernel(index)
    Next
    For i As Integer = 0 To kernel.Length - 1 : kernel(i) /= total : Next
    If IsNothing(blurTarget1) Then blurTarget1 = New RenderTarget2D(Game.graphics.GraphicsDevice, img.Width, img.Height, False, Game.graphics.GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.None)
    If IsNothing(blurTarget2) Then blurTarget2 = New RenderTarget2D(Game.graphics.GraphicsDevice, img.Width, img.Height, False, Game.graphics.GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.None)
    Dim srcRect As New Rectangle(0, 0, img.Width, img.Height)
    Dim destRect1 As New Rectangle(0, 0, blurTarget1.Width, blurTarget1.Height)
    Dim destRect2 As New Rectangle(0, 0, blurTarget2.Width, blurTarget2.Height)
    effect.Parameters("weights").SetValue(kernel)
    effect.Parameters("offsets").SetValue(offsetsHoriz)
    effect.Parameters("colorMapTexture").SetValue(img)
    Game.graphics.GraphicsDevice.SetRenderTarget(blurTarget1)
    sb.Begin(0, BlendState.Opaque, Nothing, Nothing, Nothing, effect)
    sb.Draw(img, New Vector2(0, 0), Color.White)
    sb.End()
    effect.Parameters("offsets").SetValue(offsetsVert)
    Game.graphics.GraphicsDevice.SetRenderTarget(blurTarget2)
    sb.Begin(0, BlendState.Opaque, Nothing, Nothing, Nothing, effect)
    sb.Draw(blurTarget1, New Vector2(0, 0), Color.White)
    sb.End()
    Game.graphics.GraphicsDevice.SetRenderTarget(Nothing)
    Return blurTarget2
End Function

The error is in this line of code: effect.Parameters(“colorMapTexture”).SetValue(img)
Thanks a lot!

When you set a breakpoint on this line and run the app, what does it say ? (do you find colorMapTexture in the effect parameters ?)

It shows that there are three parameters:

  • a scalar single “weights”
  • a vector single “offsets”
  • an object texture2D “colorMap + colormapTexture: {}”

One thing I should mention is that this code worked unchanged in monogame 3.4 (except the compile shader line being something like PixelShader = compile ps_4_0_level_9_1 PS_GaussianBlur();

I’m not sure why you would have had to change the shader level from ps_4_0_level_9_1 to 3_0. Did you change the MonoGame reference and happen to choose the WindowsGL version?

I updated it to the universal DesktopGL project, and if I left the .fx file code unchanged an error would be thrown when trying to use the mgcb tool saying that it is not a real shader.

Currently my MonoGame reference is:
Program Files (x86)\MonoGame\v3.0\Assemblies\DesktopGL\MonoGame.Framework.dll

DesktopGL is OpenGL, which is why you needed to change the pixel shader level from 4_0_level_9_1 to 3_0. If you use Windows\MonoGame.Framework.dll, you will have to change the shader level back. Try that and see if it works with the colorMapTexture parameter.

I tried, but I get that error in the mcgb tool again. Using an old version of the tool makes an xnb file that isn’t compatible with the program. Also, Is there a solution that allows compatibility with windows, linux, and mac?

I’m having a similar problem. I’ll post a solution if I find one.
Old version of the project was monogame3.5 also but only for windows dx11.
New version (remade project) for cross-platform (DesktopGL) having this issue:

An unhandled exception of type ‘System.NullReferenceException’ occurred
for:

backlight = Content.Load<Texture2D>("Textures/flare1");
mask_effect = Content.Load<Effect>("Shaders/PostFX/LightMask");            
mask_effect.Parameters["Flare"].SetValue(backlight);

So backlight and mask_effect are definitely NOT null (tested)… in fact if I simply comment out use of Flare - the entire program works fine (minus the correct shading effect).
Here’s the pertinent code from the effect file (note: this is texture 2):

Texture2D Flare : register(t1);
sampler FlareSampler : register(s1)
{ 
    Texture = (Flare);     
    AddressU = clamp;
    AddressV = clamp;
};

Shader versions were all changed to vs_3_0 and ps_3_0
One idea I had was perhaps the compiler is removing Flare through some mistaken assumption that it isn’t being used?
If this is the case, perhaps there’s a way to stop it from doing that?
It’s still odd that it works in my windows-only version but not here. (O.o)

Can you show the code where you use the texture (in the fx file).
Maybe it gets overwritten or something

Sure thing :slight_smile:

#define SAMPLE_TEXTURE(Name, texCoord)  Name.Sample(Name##Sampler, texCoord) 

Texture2D Tex : register(t0);
sampler TexSampler : register(s0)
{
	Texture = (Tex);
	AddressU = clamp;
	AddressV = clamp;
};

Texture2D Flare : register(t1);
sampler FlareSampler : register(s1)
{ 
    Texture = (Flare);     
    AddressU = clamp;
    AddressV = clamp;
};

float2 lightScreenPosition;  
float SunSize;  


struct VSOutput
{	
	float4 position: SV_Position;
	float2 texCoord : TEXCOORD0;
};

VSOutput VertexShaderFunction(VSOutput input)
{
	VSOutput output;
	output.position = float4(input.position.xyz, 1);
	output.texCoord = input.texCoord;
	return output;
}


float4 SpritePixelShader(VSOutput input) : SV_Target0
{	
	float4 col = 0;
	float2 coord;	
        coord = .5 - (input.texCoord - lightScreenPosition) / SunSize;     		
        col = (pow(SAMPLE_TEXTURE(Flare, coord), 2)) * 2; 
	return SAMPLE_TEXTURE(Tex, input.texCoord) * col;	
}

technique LightMask { 
	pass { 
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 SpritePixelShader();
	} 
}

The float4 col is truncated to a single float since you assign float4 col = 0
That’s probably something the compiler also says.

At least in dx it would only use the r value of the texture if I’m not mistaken.

But that is most likely not the problem.

But it’s a good thing to remember that I think the mgfx compiler does not accept stuff like float4 test = float4 (0). This would truncate the test to a float. In OpenGL it would make test a float4(0,0,0,0).

Apart from that the compiler most likely barks at the pow() not using pow(abs(…),2)

But you should use x*x anyways instead of pow(x,2)

The way you use your sampling is a bit outdated as well, both samplerstates do the same thing. If you don’t use tex2d() any more your samplers don’t need to specify a texture. The newer semantic TextureName.Sample(SamplerState, texcoord) can use any sampler with any texture.

Just a note

I am not 100% sure whether your problem may lay with you changing back to shader model 3.0. I’m sure konaju can help you out more BUT you can try this

#define SAMPLE_TEXTURE(Name, texCoord) tex2d(Name##Sampler, texCoord)

Which is the old semantic. In that case leave the samplers as they are now

1 Like

By the way, what’s the point of using this SAMPLE_TEXTURE macro if it is not shorter than using tex2d(a, b) ?
Is it to make shaders compatible between platforms ? (ie dx vs gl to avoid duplicate code ?)

There is no point unless you compile several times with different targets in mind, which makes it easier to switch it out.

AHA! I love you! I made all the changes you recommended and everything works fine now and it fixed some issues with other shaders too.

Out of curiosity, I isolated the problem to this:

SAMPLE_TEXTURE(Flare, coord) //which when changed to this:
tex2D(FlareSampler, coord) 

Fixed the runtime NullReferenceException
So yah, I guess it has to do with switching to 3. My understanding was 3 was the best compatible for GL stuff which is why I made the switch.
Also I updated my shaders so they avoid unwanted truncations (float4) and used the optimization you suggested instead of pow.
Thankyou so much :smiley:

Glad it worked!
If you have any other small problems you can always pm me

1 Like