Wargamer *Excellent utilisateur*
Messages : 6938 Projet Actuel : Bataille de cake au fruits
| Sujet: [HLSL / XNA] Dessiner une bordure (outline) Jeu 25 Juil 2013 - 2:48 | |
| Voici un bout de code HLSL qui permet d'afficher de contour d'une texture. (Je commence, donc y'a probablement mieux, j'accepte tout commentaire pour améliorer) Le truc n'est pas 100% précis pour une raison que j'ignore mais le résultat est là. - Outline.fx:
// The world transformation float4x4 World;
// The view transformation float4x4 View;
// The projection transformation float4x4 Projection;
float2 TextureOffset; sampler s0;
float2 TextureScale; float2 OffsetScale;
struct VertexInfo { float4 Position : POSITION0; // The position of the vertex float2 TextureCoordinate : TEXCOORD0; // The texture coordinate of the vertex float4 Color : COLOR0; };
struct PixelInfo { float4 Position : POSITION0; float2 UVCoordinateCenter : TEXCOORD0; float2 UVCoordinateNeighborUp : TEXCOORD1; float2 UVCoordinateNeighborDown : TEXCOORD2; float2 UVCoordinateNeighborLeft : TEXCOORD3; float2 UVCoordinateNeighborRight : TEXCOORD4; float4 Color : COLOR0; };
PixelInfo vsGetNeighbor(VertexInfo Input) { PixelInfo Output;
//Get pixel postion. float4 WorldPosition = mul(Input.Position, World); float4 ViewPosition = mul(WorldPosition, View); //Project to Viewport. Output.Position = mul(ViewPosition, Projection);
// Copy over the texture coordinate float2 RealPosition = Input.TextureCoordinate * TextureScale - TextureOffset * OffsetScale;
Output.UVCoordinateCenter = RealPosition; Output.UVCoordinateNeighborUp = RealPosition - float2(0, OffsetScale.y); Output.UVCoordinateNeighborDown = RealPosition + float2(0, OffsetScale.y); Output.UVCoordinateNeighborLeft = RealPosition - float2(OffsetScale.x, 0); Output.UVCoordinateNeighborRight = RealPosition + float2(OffsetScale.x, 0); // Copy over the vertex color. Output.Color = Input.Color;
return Output; }
float4 psRenderOutline(PixelInfo Input) : COLOR0 { if (Input.UVCoordinateNeighborRight.x < 0 || Input.UVCoordinateNeighborLeft.x > 1 || Input.UVCoordinateNeighborDown.y < 0 || Input.UVCoordinateNeighborUp.y > 1) return float4(0, 0, 0, 0);
float4 Pixel = tex2D(s0, Input.UVCoordinateCenter); float4 PixelUp = tex2D(s0, Input.UVCoordinateNeighborUp); float4 PixelDown = tex2D(s0, Input.UVCoordinateNeighborDown); float4 PixelLeft = tex2D(s0, Input.UVCoordinateNeighborLeft); float4 PixelRight = tex2D(s0, Input.UVCoordinateNeighborRight);
if (Pixel.a == 1 || PixelUp.a == 1 || PixelDown.a == 1 || PixelLeft.a == 1 || PixelRight.a == 1) return Input.Color;
return float4(0, 0, 0, 0); }
technique Technique1 { pass Pass1 { VertexShader = compile vs_2_0 vsGetNeighbor(); PixelShader = compile ps_2_0 psRenderOutline(); } }
- Init:
//Init outline shader. fxOutline = Content.Load<Effect>("Shaders/Outline"); Matrix projectionMatrix = Matrix.CreateOrthographicOffCenter(1, Constants.Width, Constants.Height, 1, 0, -1f); fxOutline.Parameters["World"].SetValue(Matrix.Identity); fxOutline.Parameters["View"].SetValue(Matrix.Identity); fxOutline.Parameters["Projection"].SetValue(projectionMatrix);
Vector2 TextureOffset = new Vector2(1, 1); fxOutline.Parameters["TextureOffset"].SetValue(TextureOffset);
Vector2 TextureRealSize = new Vector2(Sprite.Width, Sprite.Height); Vector2 TextureOuputSize = new Vector2(Sprite.Width + 2, Sprite.Height + 2);
Vector2 PixelSize = new Vector2(1 / TextureOuputSize.X, 1 / TextureOuputSize.Y); Vector2 TextureScale = TextureOuputSize / TextureRealSize;
fxOutline.Parameters["TextureScale"].SetValue(TextureScale); fxOutline.Parameters["OffsetScale"].SetValue(PixelSize * TextureScale);
- Draw:
g.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.None, RasterizerState.CullNone, fxOutline); g.Draw(Sprite, new Rectangle(PosX - (int)TextureOffset.X, PosY - (int)TextureOffset.Y, (int)TextureOuputSize.X , (int)TextureOuputSize.Y), Color); g.End();
Résultat avec du bleu: L'idée de base est de créer des vertex plus gros pour afficher la bordure, créer un décalage(OffsetScale) pour compenser puis redimensionner(TextureScale) pour éviter qu'il soit étiré sur la totalité de la surface. _________________ Règle #1 du CBNA, ne pas chercher à faire dans la subtilité; personne comprend |
|