|
|
|
Using shaders was on my to-do list. Partly because it's a good introduction to GPU computation, and partly because it should make the game look better. So I went for it last weekend, and this is the log of what worked and what didn't, and the difficulties involved. A word of caution: I am not really following the normal way to build things: There's no content project, there's no build pipeline for effects. I am doing this quite manually. Therefore this guide might be useful to someone completely stuck, but it might not be helpful if you're a design studio who need to do things "properly". Having said that, I have now got a series of scripts that build this all quite easily, so I don't think my way comes with big disadvantages either. The first thing is that it's hard to know where to start.
float4x4 World;
float4x4 View;
float4x4 Projection;
struct VertexShaderInput
{
float4 TexCoord : TEXCOORD0;
float4 Position : POSITION0;
float4 Normal : NORMAL;
float4 Color :COLOR0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
float2 TextureCordinate : TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.Color = input.Color;
output.TextureCordinate = input.TexCoord;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
return input.Color;
}
technique Ambient
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
Note that the language that this is written in is called HLSL : High Level Shader Language.
"C:\Program Files (x86)\MSBuild\MonoGame\v3.0\Tools\2MGFX.exe\" Effect1.fx Effect1.mgfxoWhen I first tried this, it didn't work. The reason was that I had an old version of monogame. I then used nuget to install monogame 3.4. (latest as of 2016-01-23). That still didn't work. I then went to the monogame website (http://www.monogame.net/2015/04/29/monogame-3-4/) and ran the monogame setup.
Effect1.fx(27,26): warning X3206: implicit truncation of vector type
Effect1.fx(27,26): warning X3206: implicit truncation of vector type
Compiled 'Effect1.fx' to 'Effect1.mgfxo'.
As far as I am aware, the warnings aren't important.
foreach (EffectPass pass in E.basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
gd.Indices = b.ib;
gd.SetVertexBuffer(b.vb);
gd.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, b.vblen, 0, b.iblen / 3);
}
After (myEffect):
Effect ef = Game1.MyEffect;
ef.Parameters["World"].SetValue(basicEffect.World);
ef.Parameters["View"].SetValue(basicEffect.View);
ef.Parameters["Projection"].SetValue(basicEffect.Projection);
foreach (EffectPass pass in ef.CurrentTechnique.Passes)
{
pass.Apply();
gd.Indices = b.ib;
gd.SetVertexBuffer(b.vb);
gd.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, b.vblen, 0, b.iblen / 3);
}
The only changes there were that firstly when we applied a pass, we used the new shader, and secondly, we set the parameters of the shader
to what the old shader used: World, View, and Projection. Note that these three variables are the three global variables in Effect.fx.
float4x4 World;
float4x4 View;
float4x4 Projection;
float4 AmbientColor;
float4 LightDirection;
texture Texture;
sampler TextureSampler = sampler_state
{
Texture = <Texture> ;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float4 Normal : NORMAL;
float4 Color :COLOR0;
float2 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Normal : TEXCOORD2;
float4 Color : COLOR0;
float2 TextureCordinate : TEXCOORD0;
float4 Pos2 : TEXCOORD1;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.Color = input.Color;
output.TextureCordinate = input.TexCoord;
float4 n = input.Normal;
n[3] = 0; // this prevents translation.
output.Normal = = mul(n, World); //not input.Normal, because that wouldn't be rotated.
output.Pos2 = worldPosition;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
float4 color = tex2D(TextureSampler, input.TextureCordinate);
color = color * 1.0 + input.Color*0.7 - 0.6;
float lighting = clamp(-dot(input.Normal, LightDirection), 0,1) * 0.7;
float3 n = (float3)input.Normal;
float3 l = (float3)LightDirection;
float3 p = normalize((float3)input.Pos2);
float3 a = n + l;
float3 b = p + n;
float delta = 0.5 / (1.0 + 3*length(b-a)) + 0.5 / (0.5 + 10*length(b-a));
float c = clamp((delta-0.2)/(1.0-0.2),0,1) * 0.8;
return float4(
clamp(color[0] * (lighting + c*0.7 + AmbientColor[0]),0,1),
clamp(color[1] * (lighting + c + AmbientColor[1]),0,1),
clamp(color[2] * (lighting + c*1.5 + AmbientColor[2]),0,1),0
);
}
technique Ambient
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
Since this has a few extra global variables, we should set them:
ef.Parameters["World"].SetValue(basicEffect.World);
ef.Parameters["View"].SetValue(basicEffect.View);
ef.Parameters["Projection"].SetValue(basicEffect.Projection);
ef.Parameters["Texture"].SetValue(basicEffect.Texture);
ef.Parameters["LightDirection"].SetValue(basicEffect.DirectionalLight0.Direction);
ef.Parameters["AmbientColor"].SetValue(basicEffect.AmbientLightColor);
It's worth pointing out that if you have a global variable in the effects file, but you don't use it, then the compiler will remove it from the
compiled effect. Then when you try to set it, you get a runtime error.
|
|
|
|
|
How to simulate fractal ice crystal growth in PythonThis presents python code to draw snowflakes, simulating a diffusion process with Fourier transforms. |
© Hugo2015. Session @sessionNumber