Zaokrąglone rogi w XNA?

10

Czy jest jakiś sposób, aby wykonać zaokrąglone rogi na prostokącie renderowanym w XNA przez prymitywy (paski liniowe)? Chcę, aby mój interfejs był nieco bardziej fantazyjny niż obecnie, i chciałbym, aby kod był elastyczny, bez zbyt wielu tekstur.

Mathias Lykkegaard Lorenzen
źródło
Zasadniczo: Użyj jednej tekstury dla linii, jednej tekstury dla okrągłych końców linii. Obracaj i skaluj duszki odpowiednio wykorzystujące te dwie tekstury.
Olhovsky

Odpowiedzi:

8

Możesz wyrenderować prymityw i stworzyć moduł cieniujący, który może tworzyć zaokrąglone rogi.
Oto prosty moduł cieniujący piksele w pseudokodzie, który może narysować zaokrąglony kwadrat:

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)

Wynik tego modułu cieniującego piksele:

wprowadź opis zdjęcia tutaj

Jeśli używasz shaderów, możesz stworzyć naprawdę fantazyjny interfejs użytkownika, nawet animowany.

Dla mnie świetnym prototypem prostych shaderów pikseli jest program EvalDraw

piotrek
źródło
5

Innym sposobem na to jest użycie „rozciągnięcia guzika” (zwanego również „rozciągnięciem pudełka” lub „dziewięciopłatkiem”). Zasadniczo tworzysz obraz, który składa się z 9 części:

Zasób przycisku

Aby narysować ten przycisk w dowolnym rozmiarze, narysuj każdy element (od góry do dołu, od lewej do prawej):

  1. Rysuj nieskalowane w lewym górnym rogu prostokąta docelowego.
  2. Rysuj skalowane poziomo (z width - ((1) + (2)).Width) u góry docelowego prostokąta, z lewym przesunięciem o szerokość (1).
  3. Rysuj nieskalowane w prawym górnym rogu prostokąta docelowego.
  4. Rysuj skalowane pionowo (z height - ((1) + (2)).Height) po lewej stronie prostokąta docelowego, z górnym przesunięciem o wysokość (1).
  5. Rysuj skalowane w obu kierunkach (o szerokości (2) i wysokości (4)), przesunięte o szerokość i wysokość (1).
  6. Rysuj skalowane pionowo (ta sama wysokość co (4)) po prawej stronie docelowego prostokąta, przesunięte o wysokość (1).
  7. Rysuj nieskalowane w lewym dolnym rogu prostokąta docelowego.
  8. Rysuj skalowane w poziomie (na tej samej wysokości co (2)) na dole docelowego prostokąta, z przesunięciem o szerokość (1).
  9. Rysuj nieskalowane w prawym dolnym rogu docelowego prostokąta.

Jeśli spojrzysz na przycisk, zobaczysz, że nie ma znaczenia, czy (2), (5) i (7) są skalowane w poziomie (ponieważ jest to zasadniczo linia prosta); w ten sam sposób (4), (5) i (6) można przeskalować w pionie bez wpływu na jakość obrazu.

Jonathan Dickinson
źródło
Tak, to nie odpowiada bezpośrednio na pytanie - ale ktoś może uznać je za przydatne.
Jonathan Dickinson
4
Nazywa się to dziewięciopłatkiem i jest w rzeczywistości znacznie bardziej elastyczny (i tańszy!) Niż korzystanie z modułu cieniującego, ponieważ dzięki teksturom możesz wyglądać tak, jak chcesz. Następnie możesz umieścić wszystkie obrazy widżetów w jednym atlasie tekstur. Większość GUI robi to w ten sposób.
Elisée
0

Oto kod metody „dziewięciu łatek”:

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);
    }
}

Jest wywoływany jako:

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
źródło
to nie działa dla mnie ... Po prostu dostaję normalny prostokąt. Tak to wykorzystałemTexture2D _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
Twoja tekstura ma tylko jeden niebieski piksel, to podejście zakłada, że ​​zaokrąglone rogi są częścią tekstury.
sdgfsdh
przepraszam - bardzo nowy na platformie ... dzięki za tak szybki powrót do mnie
Leonardo Seccia