Woops amendment Dx with Hi Def profile version.
I should note the mouse Y is reversed again for dx.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
namespace RefractExampleDx
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont font;
Effect refractionEffect;
Texture2D tex2dForground;
Texture2D tex2dRefractionTexture;
Texture2D tex2dXnaUkImage;
Texture2D tex2dMgLogo;
Texture2D tex2dRefractionImg;
// some default control values for the refractions.
float speed = .02f;
float waveLength = .08f;
float frequency = .2f;
float refractiveIndex = 1.3f;
Vector2 refractionVector = new Vector2(0f, 0f);
float refractionVectorRange = 100;
// To alter the size and position on the screen of all the image squares.
// Change the w h values.
public int StW { get; set; }
public int StH { get; set; }
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1200;
graphics.PreferredBackBufferHeight = 800;
Window.AllowUserResizing = true;
Content.RootDirectory = "Content";
IsMouseVisible = true;
StW = graphics.PreferredBackBufferWidth / 4;
StH = graphics.PreferredBackBufferHeight / 3;
graphics.GraphicsProfile = GraphicsProfile.HiDef; // << profile hi def DX
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("MgGenFont");
//Reqisite images.
tex2dRefractionImg = Content.Load<Texture2D>("RefactionTexture");
tex2dXnaUkImage = Content.Load<Texture2D>("XnaUkImage");
// extra images for testing.
tex2dMgLogo = Content.Load<Texture2D>("MG_Logo_Small_exCanvs");
// the primary two textures used for all the tests.
tex2dForground = tex2dXnaUkImage;
tex2dRefractionTexture = tex2dRefractionImg;
refractionEffect = Content.Load<Effect>("RefractShader");
//refractionEffect = Content.Load<Effect>("RefractEffects");
}
protected override void UnloadContent()
{
}
float pauseTimer = 1.0f;
float pauseDelay = .5f;
int choice = 0;
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (pauseTimer > 0f)
pauseTimer = pauseTimer - (float)gameTime.ElapsedGameTime.TotalSeconds;
else
{
if (Keyboard.GetState().IsKeyDown(Keys.Space))
{
choice++;
if (choice > 3)
choice = 0;
switch (choice)
{
case 1:
tex2dForground = tex2dXnaUkImage;
break;
case 2:
tex2dForground = tex2dMgLogo;
break;
//case 3:
// tex2dForground = tex2dfire01;
// break;
default:
tex2dForground = tex2dXnaUkImage;
break;
}
pauseTimer = pauseDelay;
}
if (Keyboard.GetState().IsKeyDown(Keys.Up))
waveLength += .001f;
if (Keyboard.GetState().IsKeyDown(Keys.Down))
waveLength -= .001f;
if (Keyboard.GetState().IsKeyDown(Keys.Right))
frequency += .001f;
if (Keyboard.GetState().IsKeyDown(Keys.Left))
frequency -= .001f;
}
refractionVector = Mouse.GetState().Position.ToVector2();
refractionVector.Y = graphics.GraphicsDevice.Viewport.Bounds.Size.ToVector2().Y - refractionVector.Y;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// Draw the images well be using.
// row 1 far left we squeeze the regular two images in here that we use.
spriteBatch.Begin();
spriteBatch.Draw(tex2dRefractionTexture, new Rectangle(StW * 0, StH * 0, StW, StH / 2), Color.White);
spriteBatch.Draw(tex2dForground, new Rectangle(StW * 0, StH / 2, StW, StH / 2), Color.White);
spriteBatch.DrawString(font, "wavelength " + waveLength + "\nfrequency " + frequency, new Vector2(10, 10), Color.Wheat);
spriteBatch.DrawString(font, "Mouse: " + refractionVector, new Vector2(10, 60), Color.Moccasin);
spriteBatch.End();
// row 2 and 3 far left
Draw2dRefractionTechnique("RefractMonoCromeClipDarkness", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 0, StH * 1, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
Draw2dRefractionTechnique("RefractDiagnalAverageMonochrome", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 0, StH * 2, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
// row1
Draw2dRefractionTechnique("Refraction2", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 1, StH * 0, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
Draw2dRefractionTechnique("Refraction2", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 2, StH * 0, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), true, gameTime);
Draw2dRefractionTechnique("RefractionSnells", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 3, StH * 0, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
// row 2
Draw2dRefractionTechnique("RefractionMap", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 1, StH * 1, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
Draw2dRefractionTechnique("RefractionMap", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 2, StH * 1, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), true, gameTime);
Draw2dRefractionTechnique("TwoPassTechnique", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 3, StH * 1, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
// row 3
Draw2dRefractionTechnique("RefractGoldenRatioHighlight", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 1, StH * 2, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
Draw2dRefractionTechnique("RefractAntiRefractionArea", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 2, StH * 2, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), false, gameTime);
Draw2dRefractionTechnique("LimitedRefractionArea", tex2dForground, tex2dRefractionTexture, new Rectangle(StW * 3, StH * 2, StW, StH), speed, refractiveIndex, frequency, waveLength, refractionVector, refractionVectorRange, new Vector2(10, 1), true, gameTime);
// Draw to the whole screen for testing.
//Draw2dRefractionTechnique("RefractAntiRefractionArea", tex2dForground, tex2dRefractionTexture, new Rectangle(0, 0, StW * 4, StH * 3), speed, refractiveIndex, frequency, waveLength, new Vector2(10, 1), true, gameTime);
base.Draw(gameTime);
}
/// <summary>
/// Draw a refracted texture using the refraction technique.
/// </summary>
public void Draw2dRefractionTechnique(string technique, Texture2D texture, Texture2D displacementTexture, Rectangle screenRectangle, float refractionSpeed, float refractiveIndex, float frequency, float sampleWavelength, Vector2 refractionVector, float refractionVectorRange, Vector2 windDirection, bool useWind, GameTime gameTime)
{
Vector2 displacement;
double time = gameTime.TotalGameTime.TotalSeconds * refractionSpeed;
if (useWind)
displacement = -(Vector2.Normalize(windDirection) * (float)time);
else
displacement = new Vector2((float)Math.Cos(time), (float)Math.Sin(time));
// Set an effect parameter to make the displacement texture scroll in a giant circle.
refractionEffect.CurrentTechnique = refractionEffect.Techniques[technique];
refractionEffect.Parameters["Texture"].SetValue(texture); // << Requisite for Dx
refractionEffect.Parameters["DisplacementTexture"].SetValue(displacementTexture);
refractionEffect.Parameters["DisplacementMotionVector"].SetValue(displacement);
refractionEffect.Parameters["SampleWavelength"].SetValue(sampleWavelength);
refractionEffect.Parameters["Frequency"].SetValue(frequency);
refractionEffect.Parameters["RefractiveIndex"].SetValue(refractiveIndex);
// for the very last little test.
refractionEffect.Parameters["RefractionVector"].SetValue(refractionVector);
refractionEffect.Parameters["RefractionVectorRange"].SetValue(refractionVectorRange);
spriteBatch.Begin(0, null, null, null, null, refractionEffect);
spriteBatch.Draw(texture, screenRectangle, Color.White);
spriteBatch.End();
DisplayName(screenRectangle, technique, useWind);
}
public void DisplayName(Rectangle screenRectangle, string technique, bool useWind)
{
spriteBatch.Begin();
var offset = screenRectangle;
offset.Location += new Point(20, 20);
spriteBatch.DrawString(font, technique, offset.Location.ToVector2(), Color.White);
if (useWind)
{
offset.Location += new Point(0, 30);
spriteBatch.DrawString(font, "wind on", offset.Location.ToVector2(), Color.White);
}
spriteBatch.End();
}
}
}
Shader
//
// 2d Refraction related shaders
//
#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
#define VS_SHADERMODEL vs_4_0
#define PS_SHADERMODEL ps_4_0
#endif
//-----------------------------------------------------------------------------
//
// Requisite variable and texture samplers
//
//-----------------------------------------------------------------------------
// This vector should be in motion in order to achieve the desired effect.
float2 DisplacementMotionVector;
float SampleWavelength;
float Frequency; // .51 .3
float RefractiveIndex;
// one more little test here.
float2 RefractionVector;
float RefractionVectorRange;
Texture2D Texture : register(t0);
sampler TextureSampler : register(s0)
{
Texture = (Texture);
};
Texture2D DisplacementTexture;
sampler2D DisplacementSampler = sampler_state
{
magfilter = linear;
minfilter = linear;
AddressU = Wrap;
AddressV = Wrap;
Texture = <DisplacementTexture>;
};
//-----------------------------------------------------------------------------
//
// Requisite functions.
//
//-----------------------------------------------------------------------------
// function reflect map pixel grabber my version
float4 FuncMyRefractMap(float4 color, float2 texCoord)
{
// the SampleWavelength grabs a smaller or larger area of texture coordinates.
// the motion moves the uvs over the refraction map to give the feeling of motion.
// the Frequency reduces the manitude of the range the coordinates are grabed from.
texCoord += (tex2D(DisplacementSampler, texCoord * SampleWavelength + DisplacementMotionVector).xy - float2(0.5f, 0.5f)) * Frequency;
return tex2D(TextureSampler, texCoord) * color;
}
// function reflect map pixel grabber the ported version.
float4 FuncGuysRefractMap(float4 color, float2 texCoord)
{
texCoord += tex2D(DisplacementSampler, texCoord * SampleWavelength + DisplacementMotionVector) * 0.2 - 0.15;
return tex2D(TextureSampler, texCoord) * color;
}
// function reflect map pixel grabber hlsl snells
float4 FuncHlslRefractMap(float2 ray, float4 color, float2 texCoord)
{
float2 normalValue = abs(normalize(tex2D(DisplacementSampler, texCoord * SampleWavelength + DisplacementMotionVector).rg));
texCoord = texCoord + refract(ray, normalValue, RefractiveIndex); //* Amplitude;
// Look up into the main textur's pixel and return.
return tex2D(TextureSampler, texCoord) * color;
}
// function monochrome
float4 FuncMonoChrome(float4 col)
{
col.rgb = (col.r + col.g + col.b) / 3.0f;
return col;
}
// function outline
float4 FuncDiagnalAvg(float4 col, float2 texCoord)
{
col -= tex2D(TextureSampler, texCoord.xy - 0.003) * 2.7f;
col += tex2D(TextureSampler, texCoord.xy + 0.003) * 2.7f;
return col;
}
// function outline
float4 FuncDiagnalAvgMonochrome(float4 col, float2 texCoord)
{
col -= tex2D(TextureSampler, texCoord.xy - 0.003) * 2.7f;
col += tex2D(TextureSampler, texCoord.xy + 0.003) * 2.7f;
col.rgb = (col.r + col.g + col.b) / 3.0f;
return col;
}
// function highlight golden ratio steped.
float4 FuncHighlight(float4 col, float2 texCoord)
{
// try to brighten on blue.
float2 temp = texCoord;
float dist = 0.01f;
float gldr = 1.6f;
temp += float2(dist * gldr, 0.00f);
float4 col01 = tex2D(TextureSampler, temp);
temp = texCoord;
temp += float2(0.00f, dist * gldr * 2.0f);
float4 col03 = tex2D(TextureSampler, temp);
temp = texCoord;
temp += float2(-dist * gldr * 3.0f, 0.00f);
float4 col02 = tex2D(TextureSampler, temp);
temp = texCoord;
temp += float2(0.00f, -dist * gldr * 4.0f);
float4 col04 = tex2D(TextureSampler, temp);
float4 tempCol = ((col01 + col02 + col03 + col04) - col) / 2.0f;
tempCol.bg = col.bg;
col.rgb = saturate(col.rgb * tempCol.rgb);
return col;
}
//-----------------------------------------------------------------------------
//
// Requisite Shaders.
//
//-----------------------------------------------------------------------------
//__________________________________________________
// (Tech) refraction map shader mine
//__________________________________________________
float4 PsRefractionMap(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 col = FuncMyRefractMap(color, texCoord.rg);
return col;
}
//__________________________________________________
// (Tech) refraction map shader guys
//__________________________________________________
float4 PsRefraction2(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 col = FuncGuysRefractMap(color, texCoord.rg);
return col;
}
//__________________________________________________
// (Tech) RefractDiagnalAverageMonochrome
//__________________________________________________
float4 PsDiagnalAverageMonochromeShader(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 col = FuncMyRefractMap(color, texCoord.rg);
col = FuncDiagnalAvgMonochrome(col, texCoord.rg);
return col;
}
//__________________________________________________
// (Tech) the golden ratio spiral highlight
//__________________________________________________
float4 PsRefractGoldenRatioHighlight(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 col = FuncMyRefractMap(color, texCoord.rg);
col = FuncHighlight(col, texCoord.rg);
return col;
}
//__________________________________________________
// (Tech) RefractMonoCromeClipDarkness
//__________________________________________________
float4 PsRefractMonoCromeClipDarkness(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float4 col = FuncMyRefractMap(color, texCoord.rg);
col = FuncMonoChrome(col);
clip(col.r - 0.4f);
return col;
}
//__________________________________________________
// (Tech) RefractAntiRefractionArea
// this prevents a area around the point from being refracted
//__________________________________________________
float4 PsRefractAntiRefractionArea(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
// Determine distance to the anti Refract position.
float dist = saturate(distance(position.xy, RefractionVector) / RefractionVectorRange);
float2 warpedCoords = texCoord + (tex2D(DisplacementSampler, texCoord * SampleWavelength + DisplacementMotionVector).xy - float2(0.5f, 0.5f)) * Frequency;
float2 lerpedCoords = (warpedCoords - texCoord) * (dist * dist) + texCoord;
float4 col = tex2D(TextureSampler, saturate(lerpedCoords)) * color;
// Visually highlight effect range.
//col.b += (1.0f - dist) * (1.0f - dist);
//col.r += (dist) * (dist);
return col;
}
//__________________________________________________
// (Tech) LimitedRefractionArea
// this only creates a warped inverse refraction area around the point
//__________________________________________________
float4 PsLimitedRefractionArea(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
// Determine distance to the anti Refract position.
float dist = saturate(distance(position.xy, RefractionVector) / RefractionVectorRange);
float warpedCoords = (tex2D(DisplacementSampler, texCoord * SampleWavelength + DisplacementMotionVector).xy - float2(0.5f, 0.5f)) * Frequency;
float2 lerpedCoords = (warpedCoords) * (1.0f - dist) * (1.0f - dist) + texCoord;
float4 col = tex2D(TextureSampler, saturate(lerpedCoords)) * color;
// Visually highlight effect range.
//col.r += (1.0f - dist) * (1.0f - dist);
//col.b += (dist) * (dist);
return col;
}
//__________________________________________________
// (Tech) TwoPassTechnique uses mine modified.
// this is for the double pass test shader.
//__________________________________________________
float4 PsSecondaryShader(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
// the frequency grabs a smaller area of texture coordinates the motion moves the uvs over the refraction map.
float2 coordRange = texCoord * SampleWavelength + DisplacementMotionVector;
// brightspots and color change well add this last.
float2 brightspots = abs(float2(sin(coordRange.x), cos(coordRange.y)));
// we get the texels from the refraction map and shrink grab range.
texCoord += (tex2D(DisplacementSampler, coordRange).rg - float2(0.5f, 0.5f)) * Frequency;
// Look up into the main texture.
float4 col = tex2D(TextureSampler, saturate(texCoord)) * color * float4(brightspots.x, brightspots.y, 1.0f, 0.5f);
return col;
}
//__________________________________________________
// Unfortunately i cant seem to figure out how to do the 2d one.
// the 3d one seems pretty simple.
// but as it is this ones busted.
//
// (Tech) refraction hlsl call using snells law.
//__________________________________________________
float4 PsRefractionSnells(float4 position : SV_Position, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
float2 ray = float2(0.5f, .5f); // float2(0.707106f, 0.707106f);
float4 col = FuncHlslRefractMap(ray, color, texCoord.rg);
return col;
}
//-----------------------------------------------------------------------------
//
// Requisite Techniques.
//
//-----------------------------------------------------------------------------
technique Refraction2
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefraction2(); // ps_2_0 doesn't error either.
}
}
technique RefractionMap
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefractionMap();
}
}
technique RefractDiagnalAverageMonochrome
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsDiagnalAverageMonochromeShader();
}
}
technique RefractGoldenRatioHighlight
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefractGoldenRatioHighlight();
}
}
technique RefractMonoCromeClipDarkness
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefractMonoCromeClipDarkness();
}
}
technique RefractAntiRefractionArea
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefractAntiRefractionArea();
}
}
technique LimitedRefractionArea
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsLimitedRefractionArea();
}
}
technique RefractionSnells
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefractionSnells();
}
}
technique TwoPassTechnique
{
pass Pass0
{
PixelShader = compile PS_SHADERMODEL
PsRefractionMap();
}
pass Pass1
{
PixelShader = compile PS_SHADERMODEL
PsSecondaryShader();
}
}