アブストラクトとゴール:
ゲーム エディター用の単純なウィンドウ エフェクトを実行するシェーダーを作成しようとしています。この効果は、境界線の色の値が低く、ハイライトの値が高いフレームを描画します。私は多くの方法を試しましたが、全体として、GPU を使用してこれを達成するための可能な解決策は 1 つしか思いつきませんでした。
最初に、ベクトルの XY 座標を画面空間に格納するためのカスタム頂点タイプを作成します。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace WindowsGame1 {
public struct Vertex2D : IVertexType {
public Vector2 Position;
public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration(new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0));
public Vertex2D(float x, float y) {
Position = new Vector2(x, y);
}
VertexDeclaration IVertexType.VertexDeclaration {
get {
return VertexDeclaration;
}
}
}
}
次に、カスタム Window クラスのインスタンスを作成します。コンストラクターは頂点バッファーを設定し、ビュー、投影、および色のパラメーターを効果に設定します。
エフェクトファイルはこちら。
float4x4 view;
float4x4 projection;
float4 color;
float shadowPercent = 0.36893203883495145631067961165049;
float highlightPercent = 1.262135922330097087378640776699;
Texture2D targetTexture;
struct FillVertexShaderInput {
float4 position : POSITION0;
};
struct FillPixelShaderInput {
float4 position : POSITION0;
};
struct BorderPixelShaderInput {
float4 position : SV_Position;
};
// Transforms color component range from 0-255 to 0-1.
float4 ClampColor(float4 color) {
return float4(color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255);
}
// Shifts the value of a color by a percent to get border color and highlight color from a fill color.
float4 ShiftValue(float4 color, float percent) {
return float4(clamp(color[0] * percent, 0, 1), clamp(color[1] * percent, 0, 1), clamp(color[2] * percent, 0, 1), clamp(color[3] * percent, 0, 1));
}
FillPixelShaderInput FillVertexShader(FillVertexShaderInput input) {
FillPixelShaderInput output;
output.position = mul(mul(input.position, view), projection);
return output;
}
float4 FillPixelShader(FillPixelShaderInput input) : COLOR0 {
return color;
}
float4 BorderPixelShader(BorderPixelShaderInput input) : COLOR0 {
// Get color of pixel above?
// float4 tempColor = texture.Sample(sampler, (input.position[0], input.position[1] - width));
return color;
}
technique Frame {
// Store Texture2D, sampler2D, and others to be stored between passes?
/*Texture2D texture;
sampler2D sampler;
float width;
float height;
texture.GetDimensions(width, height);
color = ClampColor(color);
float4 shadowColor = ShiftValue(color, shadowPercent);
float4 highlightColor = ShiftValue(color, highlightPercent);*/
pass Fill {
VertexShader = compile vs_2_0 FillVertexShader();
PixelShader = compile ps_2_0 FillPixelShader();
}
pass Border {
PixelShader = compile ps_4_0 BorderPixelShader();
}
}
パス間でデータを保存できるようにしたいのですが、それが可能かどうかわからないので、レンダー ターゲットを XNA に保存し、次のパスのパラメーターとして使用してみました。
これが Window の Draw コードです。
public void Draw(Game1 game) {
// rectangle is a simple window for this test.
RenderTarget2D target = new RenderTarget2D(game.GraphicsDevice, rectangle.Width, rectangle.Height);
game.GraphicsDevice.SetRenderTarget(target);
game.GraphicsDevice.BlendState = BlendState.AlphaBlend;
game.GraphicsDevice.Clear(Color.Transparent);
game.GraphicsDevice.SetVertexBuffer(vertexbuffer);
effect.Techniques["Frame"].Passes["Fill"].Apply();
game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
game.GraphicsDevice.SetRenderTarget(null);
effect.Parameters["targetTexture"].SetValue(target);
effect.Techniques["Frame"].Passes["Border"].Apply();
}
ピクセル シェーダーで現在のピクセルの周囲のピクセルの位置と色を取得できれば、現在の位置にピクセルを描画する色を決定できます。塗りつぶしは正常に機能します。境界線の影とハイライトを描画する最良の方法がわかりません。また、アルファブレンディングに問題があります。アルファ ブレンディングを設定し、レンダー ターゲット バッファーを透明にクリアしても、ウィンドウ以外はすべてデフォルトの濃い紫色です。
あなたが助けることにした場合は、事前に感謝します。