There is a little more to it here is a actual working example shader took me a minute to get the bugs out.
game1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game1
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Effect effect;
SpriteFont font;
string message = "";
Rectangle boundryRectangle = new Rectangle(120, 120, 200, 250);
public static Texture2D dotTexture;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.GraphicsProfile = GraphicsProfile.HiDef;
IsMouseVisible = true;
}
protected override void Initialize()
{
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
// load up your stuff
font = Content.Load<SpriteFont>("font");
// load up your effect;
effect = Content.Load<Effect>("effect");
effect.CurrentTechnique = effect.Techniques["ConeTechnique"];
// make a message
message =
" Ok so i had a bit of trouble figuring this out it turns out that it was working after all. " +
"\n I was wrong when spritebatch passes the pos to the pixel shader. " +
"\n It passes the untransformed coordinates so it does a bit of magic under the hood. " +
"\n However its own vertex shader is still lining them up properly even if i pass matrix identity." +
"\n So there we go if you intend however to pass a projection matrix ill bet youll need to do the transform on the boundry" +
"\n +\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+\n+"
;
dotTexture = TextureDotCreate(GraphicsDevice);
}
public Texture2D TextureDotCreate(GraphicsDevice device)
{
Color[] data = new Color[1];
data[0] = new Color(255, 255, 255, 255);
Texture2D tex = new Texture2D(device, 1, 1);
tex.SetData<Color>(data);
return tex;
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
var mouse = Mouse.GetState();
playerLookAtTargetPosition = mouse.Position.ToVector2();
base.Update(gameTime);
}
Vector2 playerPosition = new Vector2(100, 100);
Vector2 playerLookAtTargetPosition = new Vector2(200, 20);
float rangeInDegrees = 35f;
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Moccasin);
Matrix m = Matrix.Identity;
effect.CurrentTechnique = effect.Techniques["ConeTechnique"];
effect.Parameters["visibleBounds"].SetValue(GetVector4Rectangle(boundryRectangle));
effect.Parameters["playerPosition"].SetValue(playerPosition);
effect.Parameters["playerLookAtTarget"].SetValue(playerLookAtTargetPosition);
effect.Parameters["rangeInDegrees"].SetValue(rangeInDegrees);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone, effect, m);
effect.Parameters["TextureA"].SetValue(font.Texture);
spriteBatch.Draw(dotTexture, boundryRectangle, Color.White);
spriteBatch.Draw(font.Texture, new Vector2(150, 320), Color.LightGray);
spriteBatch.DrawString(font, message, new Vector2(100f, 100f), Color.MonoGameOrange);
spriteBatch.End();
base.Draw(gameTime);
}
public Vector4 GetVector4Rectangle(Rectangle r)
{
int h = graphics.GraphicsDevice.Viewport.Height;
// Gl you gotta flip the y
//return new Vector4(r.Left, (h - r.Top), r.Right, (h - r.Bottom));
// Dx dont flip the y.
return new Vector4(r.Left, r.Top, r.Right, r.Bottom);
}
public Vector4 GetVector4GpuRectangle(Rectangle r, Matrix vp)
{
var lt = Vector2.Transform(new Vector2(r.Left, r.Top), vp);
var rb = Vector2.Transform(new Vector2(r.Right, r.Bottom), vp);
return new Vector4(lt.X, lt.Y, rb.X, rb.Y);
}
}
}
shader
// effect.fx
//
#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
#define PS_SHADERMODEL ps_4_0
#endif
float4 visibleBounds;
float2 playerPosition;
float2 playerLookAtTarget;
float rangeInDegrees;
Texture2D TextureA;
sampler2D TextureSamplerA = sampler_state
{
Texture = <TextureA>;
};
// pixel shader
float4 MyPixelShader(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 col = tex2D(TextureSamplerA, texCoord) * color;
float2 pos = position.xy;
// i could probably mathematically boolean this down get rid of the ifs in a few ways but im tired.
float dx = (pos.x - visibleBounds.x) * (visibleBounds.z - pos.x);
float dy = (pos.y - visibleBounds.y) * (visibleBounds.w - pos.y);
if (dx < 0.0f)
clip(-1);
if (dy < 0.0f)
clip(-1);
return col;
}
// pixel shader
float4 ConePixelShader(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float2 playerToScreenPixelNormal = normalize(position.xy - playerPosition.xy);
float2 playerLookAtDirection = normalize(playerLookAtTarget.xy - playerPosition.xy);
float theta = saturate(dot(playerLookAtDirection, playerToScreenPixelNormal));
float acos = theta * theta;
float pixelDegreesToLineOfSight = acos * 90.0f;
float4 resultingPixelColor = tex2D(TextureSamplerA, texCoord) * color;
// clips out anything not within the specified range to the line of site.
clip(pixelDegreesToLineOfSight - (90 - rangeInDegrees / 2.0));
return resultingPixelColor;
}
technique BasicColorDrawing
{
pass P0
{
PixelShader = compile PS_SHADERMODEL
MyPixelShader();
}
}
technique ConeTechnique
{
pass P0
{
PixelShader = compile PS_SHADERMODEL
ConePixelShader();
}
}