Coins arrondis dans XNA?

10

Existe-t-il un moyen de faire des coins arrondis sur un rectangle rendu en XNA par le biais de primitives (lignes)? Je veux rendre mon interface utilisateur un peu plus sophistiquée qu'elle ne l'est déjà, et je voudrais que le code soit flexible, sans trop de textures.

Mathias Lykkegaard Lorenzen
la source
Fondamentalement: utilisez une texture pour la ligne, une texture pour les extrémités arrondies de la ligne. Faites pivoter et redimensionnez les sprites qui utilisent ces deux textures de manière appropriée.
Olhovsky

Réponses:

8

Vous pouvez rendre votre primitive et créer un shader qui peut créer ces coins arrondis.
Voici un pixel shader simple en pseudocode qui peut dessiner un carré arrondi:

xDist = abs(x-0.5)
yDist = abs(y-0.5)
xD = xDist*xDist*4
yD = yDist*yDist*4
alpha = floor((1-xD)*(1-yD)*5)

Résultat de ce pixel shader:

entrez la description de l'image ici

Si vous utilisez des shaders, vous pouvez créer une interface utilisateur vraiment fantaisiste, même animée.

Pour moi, le programme EvalDraw est un excellent prototype de pixel shaders simple.

piotrek
la source
5

Une autre façon de procéder consiste à utiliser un «boutonnage boutonné» (également appelé «bout droit extensible» ou «patch neuf»). Essentiellement, vous créez une image composée de 9 parties:

Ressource de bouton

Afin de dessiner ce bouton à n'importe quelle taille, vous dessinez chaque pièce (de haut en bas, de gauche à droite):

  1. Dessinez sans échelle en haut à gauche du rectangle de destination.
  2. Dessinez mis à l'échelle horizontalement (avec width - ((1) + (2)).Width) en haut du rectangle de destination, la gauche étant décalée de la largeur de (1).
  3. Dessinez sans échelle en haut à droite du rectangle de destination.
  4. Dessinez à l'échelle verticale (avec height - ((1) + (2)).Height) à gauche du rectangle de destination, le haut étant décalé de la hauteur de (1).
  5. Dessinez à l'échelle dans les deux directions (avec la largeur de (2) et la hauteur de (4)), décalées par la largeur et la hauteur de (1).
  6. Tracez une échelle verticale (même hauteur que (4)) à droite du rectangle de destination, décalée de la hauteur de (1).
  7. Dessinez sans échelle en bas à gauche du rectangle de destination.
  8. Dessinez à l'échelle horizontale (même hauteur que (2)) au bas du rectangle de destination, décalé de la largeur de (1).
  9. Dessinez sans échelle en bas à droite du rectangle de destination.

Si vous regardez le bouton, vous verrez que cela n'a pas d'importance si (2), (5) et (7) sont mis à l'échelle horizontalement (car il s'agit essentiellement d'une ligne droite); de la même manière (4), (5) et (6) peuvent être mis à l'échelle verticalement sans affecter la qualité de l'image.

Jonathan Dickinson
la source
Oui, cela ne répond pas directement à la question - mais quelqu'un pourrait toujours la trouver utile.
Jonathan Dickinson
4
Cela s'appelle un patch neuf et est en fait beaucoup plus flexible (et moins cher!) Que d'utiliser un shader car vous pouvez lui donner l'apparence que vous voulez avec une texture. Vous pouvez ensuite mettre toutes vos images de widget dans un seul atlas de texture. La plupart des interfaces graphiques le font de cette façon.
Elisée
0

Voici le code de l'approche "neuf patchs":

public static class SpriteBatchExtensions
{
    public static void DrawRoundedRect(this SpriteBatch spriteBatch, Rectangle destinationRectangle, 
        Texture2D texture, int border, Color color)
    {
        // Top left
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location, new Point(border)), 
            new Rectangle(0, 0, border, border), 
            color);

        // Top
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(border, 0), 
                new Point(destinationRectangle.Width - border * 2, border)), 
            new Rectangle(border, 0, texture.Width - border * 2, border), 
            color);

        // Top right
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(destinationRectangle.Width - border, 0), new Point(border)), 
            new Rectangle(texture.Width - border, 0, border, border), 
            color);

        // Middle left
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(0, border), new Point(border, destinationRectangle.Height - border * 2)), 
            new Rectangle(0, border, border, texture.Height - border * 2), 
            color);

        // Middle
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(border), destinationRectangle.Size - new Point(border * 2)), 
            new Rectangle(border, border, texture.Width - border * 2, texture.Height - border * 2), 
            color);

        // Middle right
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(destinationRectangle.Width - border, border), 
                new Point(border, destinationRectangle.Height - border * 2)), 
            new Rectangle(texture.Width - border, border, border, texture.Height - border * 2), 
            color);

        // Bottom left
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(0, destinationRectangle.Height - border), new Point(border)), 
            new Rectangle(0, texture.Height - border, border, border), 
            color);

        // Bottom
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + new Point(border, destinationRectangle.Height - border), 
                new Point(destinationRectangle.Width - border * 2, border)), 
            new Rectangle(border, texture.Height - border, texture.Width - border * 2, border), 
            color);

        // Bottom right
        spriteBatch.Draw(
            texture, 
            new Rectangle(destinationRectangle.Location + destinationRectangle.Size - new Point(border), new Point(border)), 
            new Rectangle(texture.Width - border, texture.Height - border, border, border), 
            color);
    }
}

Il est invoqué comme:

spriteBatch.DrawRoundedRect(
    dest, // The coordinates of the Rectangle to be drawn
    rectangleTexture, // Texture for the whole rounded rectangle
    16, // Distance from the edges of the texture to the "middle" patch
    Color.OrangeRed);
sdgfsdh
la source
cela ne fonctionne pas pour moi ... Je reçois juste un rectangle normal. Voici comment je l'ai utiliséTexture2D _texture = new Texture2D(GraphicsDevice, 1, 1); _texture.SetData(new Color[] { Color.Blue }); SpriteBatch sb = new SpriteBatch(GraphicsDevice); sb.Begin(); //sb.Draw(_texture, new Rectangle(100, 100, 100, 100), Color.White); sb.DrawRoundedRect(_texture, new Rectangle(100, 100, 100, 100), Color.Pink, 16); sb.End();
Leonardo Seccia
Votre texture n'est qu'un pixel bleu, cette approche suppose que les coins arrondis font partie de votre texture.
sdgfsdh
désolé - très nouveau sur la plate-forme ... merci de me revenir si rapidement
Leonardo Seccia