(SOLVED) Porting Complex XNA 4 Game to Monogames need Sharder Help!

Hello All,

I’ve been working on a XNA game for about 3 years now and I just got to a good cut off point to start my conversion which I’m doing mainly to get my game into x64 so I can use more than 1.3gigs of ram and the mutliplatform is a large bonus as well.

I just started converting my game yesterday and I’m using the Monogame Pipline tool to convert all my assets over and check for any compile errors in my shaders. I’ve been reading posts for weeks in this community and as with most people porting over the shaders / custom effect are a real problem. I’ve gotten most my sharders to compile via the tool except my most complex one which is used to render my planets. You can see an example below of what the sharder does:

The code for the effect is below:

////////////////////////////////////////////////////////////////////////////////
// Varibles
////////////////////////////////////////////////////////////////////////////////
float4x4 world : WORLD;
float4x4 view : VIEW;
float4x4 projection : PROJECTION;

float2 cloudMove;
float2 cloudShadowOffSet;
float4 cameraPos;
float4 globalAmbient;
float4 lightDir;
float4 lightColor;
float4 materialAmbient;
float4 materialDiffuse;
float4 materialSpecular;
float materialShininess;
float cloudStrength;

////////////////////////////////////////////////////////////////////////////////
// Texture Maps
////////////////////////////////////////////////////////////////////////////////
texture2D landOceanColorGlossMap;
sampler landOceanColorGlossMapSampler = sampler_state
{
	Texture = <landOceanColorGlossMap>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

texture2D cloudColorMap;
sampler cloudColorMapSampler = sampler_state
{
	Texture = <cloudColorMap>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

texture2D LowAltCloudColorMap;
sampler lowAltCloudColorMapSampler = sampler_state
{
	Texture = <LowAltCloudColorMap>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

texture2D highAltCloudColorMap;
sampler highAltCloudColorMapSampler = sampler_state
{
	Texture = <highAltCloudColorMap>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

texture2D nightColorMap;
sampler nightColorMapSampler = sampler_state
{
	Texture = <nightColorMap>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

texture2D normalMap;
sampler normalMapSampler = sampler_state
{
    Texture = <normalMap>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

////////////////////////////////////////////////////////////////////////////////
// Vertex Shaders
////////////////////////////////////////////////////////////////////////////////
void ParticleVertexShader(in  float4 inPosition  : POSITION,
             in  float2 inTexCoord  : TEXCOORD,
			 in  float3 inNormal    : NORMAL,
			 in  float3 inTangent   : TANGENT,
			 in  float3 inBitangent : BINORMAL,
			 out float4 outPosition : POSITION,
			 out float2 outTexCoord : TEXCOORD0,
			 out float3 outLightDir : TEXCOORD1,
			 out float3 outViewDir  : TEXCOORD2,
			 out float3 outNormal   : TEXCOORD3)
{
	float4 worldPos = mul(inPosition, world);

    float3 n = mul(inNormal, (float3x3)world);
	float3 t = mul(inTangent, (float3x3)world);
	float3 b = mul(inBitangent, (float3x3)world);
	float3x3 tbnMatrix = float3x3(t.x, b.x, n.x,
	                              t.y, b.y, n.y,
	                              t.z, b.z, n.z);	
	
	outPosition = mul(mul(worldPos, view), projection);
	outTexCoord = inTexCoord;
	outLightDir = mul(-lightDir.xyz, tbnMatrix);
	outViewDir = mul((cameraPos - worldPos).xyz, tbnMatrix);
	outNormal = n;
}

/////////////////////////////////////////////////////////////////////////////////
// Pixel Shaders
/////////////////////////////////////////////////////////////////////////////////
void ParticlePixelShader(in  float2 inTexCoord : TEXCOORD0,
			 in  float3 inLightDir : TEXCOORD1,
			 in  float3 inViewDir  : TEXCOORD2,
			 in  float3 inNormal   : TEXCOORD3,
			 out float4 outColor   : COLOR,
			 uniform bool bClouds, uniform bool atmos)
{   
    // X Attribute = Alpha | Y Attrubte = Green | Z Attribute is computed.
	// DXT5nm format is used for the normalMapSampler.
    float3 n = tex2D(normalMapSampler, inTexCoord).agb * 2.0f - 1.0f;
    n.z = sqrt(1.0f - n.x * n.x - n.y * n.y);
    n = normalize(n);
    
    float3 l = normalize(inLightDir);
	l = normalize(inLightDir);
    float3 v = normalize(inViewDir);
    float3 h = normalize(l + v);

	float nDotL = saturate(dot(n, l));
	float nDotH = saturate(dot(n, h));
	float power = (nDotL <= 0.0f) ? 0.0f : pow(nDotH, materialShininess);
			
	float4 ambient = (materialAmbient * (globalAmbient + lightColor));
	float4 diffuse = (materialDiffuse * lightColor * nDotL);
	float4 specular = (materialSpecular * lightColor * power);
	
	float selfShadow = saturate(2.0f * l.z);
	if(atmos)
	{
		selfShadow = saturate(1.0f * l.z);
	}
	float4 landOceanSample = tex2D(landOceanColorGlossMapSampler, inTexCoord);
	float4 day = float4(landOceanSample.rgb, 1.0f) * (ambient + selfShadow * (diffuse + specular * landOceanSample.a));
	float4 night = tex2D(nightColorMapSampler, inTexCoord) * (ambient + selfShadow * diffuse);
		
	if (bClouds)
	{
		float cloud = tex2D(cloudColorMapSampler, inTexCoord - cloudMove).r;
		float cloudShadow = tex2D(cloudColorMapSampler, inTexCoord - cloudShadowOffSet).r;

		float cloudLowAltShadow = tex2D(lowAltCloudColorMapSampler, inTexCoord - cloudShadowOffSet).r;
		float cloudLowAlt = tex2D(lowAltCloudColorMapSampler, inTexCoord - (cloudMove)).r;
		float cloudHiAlt = tex2D(highAltCloudColorMapSampler, inTexCoord - (cloudMove * 1.7)).r;

		float cloudDiffuse = saturate(dot(normalize(inNormal), normalize(-lightDir.xyz)));
		

		day = day * (1.0f - cloudLowAltShadow) + (cloudLowAltShadow * cloudDiffuse * .01);
		day = day * (1.0f - cloudLowAlt) + (cloudLowAlt * cloudDiffuse * cloudStrength);
		day = day * (1.0f - cloudHiAlt) + (cloudHiAlt * cloudDiffuse * cloudStrength);

		night = night * (1.0f - cloud) * cloudStrength;
	}
		
	outColor = day;

	if (nDotL < 0.1f)
	{
		outColor = MixDayNight(night, day, (nDotL + 0.1f) * 5.0f);
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function
////////////////////////////////////////////////////////////////////////////////
float4 MixDayNight(in const float4 x, in const float4 y, in const float a)
{
	return x * (1.0f - a) + y * a;
}

////////////////////////////////////////////////////////////////////////////////
// Techniques
////////////////////////////////////////////////////////////////////////////////
technique Atmosphere
{
	pass
	{
		VertexShader = compile vs_4_0_level_9_1 ParticleVertexShader();
		PixelShader = compile ps_4_0_level_9_1 ParticlePixelShader(false, true);
	}
}

technique PlanetWithoutClouds
{
	pass
	{
		VertexShader = compile vs_4_0_level_9_1 ParticleVertexShader();
		PixelShader = compile ps_4_0_level_9_1 ParticlePixelShader(false, false);
	}
}

technique PlanetWithClouds
{
	pass
	{
		VertexShader = compile vs_4_0_level_9_1 ParticleVertexShader();
		PixelShader = compile ps_4_0_level_9_1 ParticlePixelShader(true,false);
	}
}

The compile issue it has is sending parameters to the ParticlePixelShader method. For whatever reason it does not like me doing that and throws the following errors:

…\effects\planet.fx(198,62) : Unexpected token ‘f’ found. Expected CloseParenthesis
…\effects\planet.fx(198,62) : Unexpected token ‘f’ found. Expected CloseBracket
…\effects\planet.fx(198,62) : Unexpected token ‘f’ found. Expected CloseBracket
…etc there are error each time I send parameters

I’m guessing the syntax has changed from the XNA version; does anyone know what it needs to be so I can send the values correctly? And if anyone see other issues let me know so I can get those correct. I could simply make 3 different function with no parms but I would hate to duplicate code like that…

Any help is GREATLY Appreciated!!!

I’m sure I will run into a lot more issues during runtime but just need to get it compiling for now.

For fun here are some other pics of the game:


1 Like

This is the normal way now… that’s how I fixed those errors.

Default parameters in the techniques are not supported unfortunately.

Thank you both for the information!

Now that I have made the changes I get the following error:

Compiled shader code uses too many arithmetic instruction slots (73). Max. allowed by the target (ps_2_0) is 64.

why does the pipepine tool it say the target is ps_2_0 when I’m using ps_4_0? and does ps_4_0 allow more instructions? Or is my only choice to cut back the detail of the shader?

I found going to ps_4_0_level_9_3 works but I guess that will cut some hardware out? Does anyone know who would not be able to use it?

ps_4_0_level_9_1 was devices such as the first Microsoft Surface tablet with an earlier Tegra SoC.

This game looks awesome! Keep us posted on progress please! :smiley:

1 Like

Be happy to keep everyone posted… once I get this ported over and working correctly in mono I plan to go public with it and setup the website etc.

1 Like

Thanks again for everyone’s help, and speaking of help can someone tell me which Content.mgcb should be in the content folder?

I have one that is there by default when the project is made, then I have one that is created by the pipeline tool. Currently I’m using the one that was created in the content folder by default and I set Build Action: to MonogameContentReference.

Currently the application is crashing in Game Initialize on the base.Initialize();
An unhandled exception of type ‘System.NullReferenceException’ occurred in MonoGame.Framework.dll

I did some testing and its where I go to use the Content for the first time when my engine Initializes while it does not break in the engine initialize code it will break on the base.Initialize. If I remove that code that uses the content it will no longer crash but nothing runs since the engine is not setup. So my guess is I need to use a different .mgcb the one I made by the pipeline tool?

Thanks again for any help.

More detail: the error is happening at Microsoft.Xna.Framework.Game.InitializeExistingComponents()

Never mind… I found a null component getting added at my engine initialization… odd thing is code has not changed in the port… weird

If the exact same code did not crash in XNA, that’s a bug in MonoGame.

There are some things that are good to know about content building in MG that might save you some headaches further down. The .mgcb file is not used at runtime. If you open it with a text editor you can see what it actually does. It stores files to build and settings for the content processors. If you build it, it will produce a bin folder with the xnb’s of all built content. If you set the build action to MonoGameContentReference what it will do when you build your project is, it will check if any content changed (so it requires to rebuild) and build that, then copy all output xnb’s to the output folder of the project. So basically it just automates building the content and copying it over.

Thats good information thank you!

Great progress on the game now! got it up and running only failures I see now are every custom effect, and 3D sound. But good thing is everything else looks like its working and is playable again.

main menu is up it works since it only uses basic effects for now… (have not added particles etc to it)

The planet effect is not doing well I copied the updated effect code back to my original xna project and just changed the shader levels and it works fine below it that test.

Should look like:


but currently looks like:

What MonoGame version and what project template are you using?

I’m using version 3.5 from the download page and using the Windows game template

http://www.monogame.net/documentation/?page=Custom_Effects contains some nuggets. Check the input and output parameters and use SV_POSITION in place of POSITION.

I Finally got the planet shader working!!! I don’t have bloom converted correctly yet so the atmosphere is not as soft and fuzzy as it will be but I think its looking good and it works better in a lot of ways.

Thx to everyone for the help; had to do a lot of re-configuring of the shader code in addition to ensuring the Vertex output matching ps input and using SV_POSITION; I also had to redo all my sampler code.

In case anyone is wondering what that change required:

Old:

texture2D textureMap;
sampler myTexture = sampler_state
{
	Texture = <textureMap>;
};

New Had to drop the variable and change how the texture was set

sampler myTexture= sampler_state
{
	Texture = (textureMap);
};

Also had to change my PixilShaders method to no longer use “out” parameters and change them to the following format:

float4 PixelShader(VSOutput input) : SV_Target0

If you don’t have SV_Target0 or COLOR0 it will not work.

here is the shader up and running:

1 Like

Excellent work. Good to see the shader issues were solved. They are one of the areas that are most difficult to handle for cross-platform and cross-device.