I am drawing an isometric tilemap and need to have different shading for each level, so I need to pass extra data like tile position to get level in the pixel shader and apply shading.
This is 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 WorldViewProjection;
float2 MinMaxLevel;
Texture2D Texture;
sampler2D TextureSampler = sampler_state
{
Texture = <Texture>;
};
// Daytime.
//0 - 00:00
//0.25 - 06:00
//0.5 - 12:00
//0.75 - 18:00
//1 - 24:00
float1 DayTime;
float4 SunRiseColor;
float4 SunSetColor;
float4 AmbientColor = float4(1, 1, 1, 1);
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TextureCoordinates : TEXCOORD0;
float4 Color : COLOR0;
float3 BlockPosition : POSITION1;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TextureCoordinates : TEXCOORD0;
float4 Diffuse : COLOR0;
float3 BlockPosition : POSITION1;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
output.Position = mul(input.Position, WorldViewProjection);
output.TextureCoordinates = input.TextureCoordinates;
output.Diffuse = input.Color;
output.BlockPosition = input.BlockPosition;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : SV_Target0
{
// get pixel color
float4 color = tex2D(TextureSampler, input.TextureCoordinates) * input.Diffuse;
// clip pixel if too opakue
clip((color.a < 0.1) ? -1 : 1);
// calc and apply light
float1 light = 1 - abs(DayTime * 2 - 1);
// light darken
//color.rgb = color.rgb * light;
// light desaturation
float luminance = dot(color.rgb, float3(0.2126, 0.7152, 0.0722));
float3 grayScale = float3(luminance, luminance, luminance)/2;
color.rgb = lerp(grayScale, color.rgb, float3(light,light,light));
// level shading
//color.rgb *= (1- (MinMaxLevel.y - input.BlockPosition.z) * 0.01);
if (input.BlockPosition.z == 0)
color.rgb = float3(0, 0, 0);
return color;
}
technique MainTech
{
pass MainPass
{
VertexShader = compile VS_SHADERMODEL VertexShaderFunction();
PixelShader = compile PS_SHADERMODEL PixelShaderFunction();
}
}
This is my custom vertex declaration
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct VertexPositionColorTextureBlock : IVertexType
{
public Vector3 Position;
public Color Color;
public Vector2 TextureCoordinate;
public Vector3 BlockPosition;
public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration(
new VertexElement(VertexElementByteOffset.PositionStartOffset(), VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(VertexElementByteOffset.OffsetColor(), VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement(VertexElementByteOffset.OffsetVector2(), VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(VertexElementByteOffset.OffsetVector3(), VertexElementFormat.Vector3, VertexElementUsage.TextureCoordinate, 0));
VertexDeclaration IVertexType.VertexDeclaration => VertexDeclaration;
public VertexPositionColorTextureBlock(Vector3 position, Color color, Vector2 textureCoordinate, Vector3 blockPosition)
{
Position = position;
Color = color;
TextureCoordinate = textureCoordinate;
BlockPosition = blockPosition;
}
public override int GetHashCode()
{
throw new NotImplementedException();
return (((Position.GetHashCode() * 397) ^ Color.GetHashCode()) * 397) ^ TextureCoordinate.GetHashCode();
}
public override string ToString()
{
string[] obj = new string[7] { "{{Position:", null, null, null, null, null, null };
Vector3 position = Position;
obj[1] = position.ToString();
obj[2] = " Color:";
Color color = Color;
obj[3] = color.ToString();
obj[4] = " TextureCoordinate:";
Vector2 textureCoordinate = TextureCoordinate;
obj[5] = textureCoordinate.ToString();
obj[6] = "}}";
return string.Concat(obj);
}
public static bool operator ==(VertexPositionColorTextureBlock left, VertexPositionColorTextureBlock right)
{
if (left.Position == right.Position && left.Color == right.Color)
{
return left.TextureCoordinate == right.TextureCoordinate;
}
return false;
}
public static bool operator !=(VertexPositionColorTextureBlock left, VertexPositionColorTextureBlock right)
{
return !(left == right);
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj.GetType() != GetType())
{
return false;
}
return this == (VertexPositionColorTextureBlock)obj;
}
/// <summary>
/// This is a helper struct for tallying byte offsets
/// </summary>
public struct VertexElementByteOffset
{
public static int currentByteSize = 0;
//[STAThread]
public static int PositionStartOffset()
{ currentByteSize = 0; var s = sizeof(float) * 3; currentByteSize += s; return currentByteSize - s; }
public static int Offset(int n)
{ var s = sizeof(int); currentByteSize += s; return currentByteSize - s; }
public static int Offset(float n)
{ var s = sizeof(float); currentByteSize += s; return currentByteSize - s; }
public static int Offset(Vector2 n)
{ var s = sizeof(float) * 2; currentByteSize += s; return currentByteSize - s; }
public static int Offset(Color n)
{ var s = sizeof(int); currentByteSize += s; return currentByteSize - s; }
public static int Offset(Vector3 n)
{ var s = sizeof(float) * 3; currentByteSize += s; return currentByteSize - s; }
public static int Offset(Vector4 n)
{ var s = sizeof(float) * 4; currentByteSize += s; return currentByteSize - s; }
public static int OffsetInt()
{ var s = sizeof(int); currentByteSize += s; return currentByteSize - s; }
public static int OffsetFloat()
{ var s = sizeof(float); currentByteSize += s; return currentByteSize - s; }
public static int OffsetColor()
{ var s = sizeof(int); currentByteSize += s; return currentByteSize - s; }
public static int OffsetVector2()
{ var s = sizeof(float) * 2; currentByteSize += s; return currentByteSize - s; }
public static int OffsetVector3()
{ var s = sizeof(float) * 3; currentByteSize += s; return currentByteSize - s; }
public static int OffsetVector4()
{ var s = sizeof(float) * 4; currentByteSize += s; return currentByteSize - s; }
}
}
Now it causes the error ‘Shader Compilation Failed’. But I changed the semantics and the vertex transfer type method, but then it passed 0, that is, all pixels were painted black as if input.BlockPosition.z == 0 always worked.
I checked different lessons, guides, and docs. But didn’t find any solutions.
UPD. I know I can make level global variable and change it every level i draw, but i need BlockPosition for future light system.