Autor Wątek: graphics.GraphicsDevice.Clear dziwne wyniki  (Przeczytany 3284 razy)

Offline michal_2

  • Użytkownik

# Kwiecień 09, 2013, 15:25:23
Mam taki kod:

graphics.GraphicsDevice.Clear(new Color(255, 0, 0, 0));
// lub
graphics.GraphicsDevice.Clear(new Color(255, 0, 0, 255));
// lub
graphics.GraphicsDevice.Clear(new Color(255, 0, 0, 127));

Problem polega na tym, że nie zmienia mi wartości alfy przy czyszczeniu ekranu. Ekran jest zawsze tak samo czyszczony bez względu na wartość alfy. O cóż tu chodzi?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Karol

  • Użytkownik

# Kwiecień 09, 2013, 15:30:04
A jak ta alfa ma działać, jeżeli czyścisz ekran? Wszystkie piksele zastępowane są nowymi, a pod spodem nie ma żadnej warstwy więc nie ma co blendować.

Offline michal_2

  • Użytkownik

# Kwiecień 09, 2013, 15:39:26
Jak w gimpie utworzę kolor z alfą, to widać, że jest mniej intensywny. Poza tym mam inny przykład:

private void applyColorToRect(ref Texture2D tex, int w, int h)
        {
            Color[] col = new Color[w * h];

            for (int i = 0; i < w * h; i++)
                col[i] = new Color(255, 0, 0, 127);

            tex.SetData<Color>(col);
        }

mam taką funkcję. Tworzę teksturę 50x50 px i koloruję ją tą funkcją (kolor: 255, 0, 0, 127)

rect = new Texture2D(graphics.GraphicsDevice, 50, 50);
applyColorToRect(ref rect, 50, 50);

po czym wyświetlam teksturę po wyczyszczeniu ekranu kolorem czarnym.

protected override void Draw(GameTime gameTime)
{
    graphics.GraphicsDevice.Clear(Color.Black);

    spriteBatch.Begin();
    spriteBatch.Draw(rect, Vector2.Zero, Color.White);
    spriteBatch.End();

    // TODO: Add your drawing code here

    base.Draw(gameTime);
}

A na ekranie nadal jest tak samo czerwony rect. W ogóle nie uwzględnia alfy. Dlaczego?

Offline Avaj

  • Użytkownik

# Kwiecień 09, 2013, 15:41:55
Włączyłeś blending w odpowiednim trybie?

Offline michal_2

  • Użytkownik

# Kwiecień 09, 2013, 15:45:53
Chyba nie, pisałem wcześniej na wielu forach, głównie anglojęzycznych, żeby mi wytłumaczyli jak używać zmiennej BlendState, ale bez większego odzewu. Eksperymentowałem indywidualnie, ale pomimo iż uzyskałem prawie zadowalające rezultaty, to i tak za bardzo nie rozumiem dlaczego.

Offline Pawelx156

  • Użytkownik

  • +1
# Kwiecień 09, 2013, 16:32:24
Domyślnie wywołując   spriteBatch.Begin(); nie podając parametrów Blendingu Blend jest ustawiany na :
 BlendState.AlphaBlend;

Co zakłada ten typ Blending?
Ano to że kolory jakie masz w texturze wyświetlanej oraz kolor przez jaki mnożysz muszą być według schematu Premultiplied Alpha.
czyli-
Color wynik = jakiś_kolor * alpha.
Więc jeśli masz R,G,B,A to prawidłowy kolor ma postać  (R*A, G*A,B*A,A). Więc przeźroczystością sterujesz poprzez mnożenie wszystkich składowych koloru przez wartość alpha.

Do twojego trybu : "Tworzę teksturę 50x50 px i koloruję ją tą funkcją (kolor: 255, 0, 0, 127)"
pasuje blending BlendState.NonPremultiplied.
W nim wartoścą przeźroczystości danego koloru steruje się tylko zmieniając wartość pola przechowującego Alpha.
W twoim przypadku textura będzie w połowie przeźroczysta, zakładając że liczba 127 odpowiada alpha.

Domyślnie XNA stosuje Premultiplied Alpha i każdą texture tworzoną przez content procesor zamienia na ten format. Jest opcja od stosowania NonPremultiplied Alpha.

I jedno i drugie ma swoje wady i zalety.
Premultiplied Alpha przy nakładaniu wielu przeźroczystych textur nie powoduje poczerniania krawędzi przeźroczystych, no ale wymaga "teoretycznie" odpowiednio przygotowanej textury. Jest też bardziej intuicyjne bo kolor wynikowy to Color * Alpha.

NonPremultiplied Alpha nie wymaga niczego specjalnego.  Textury są zazwyczaj w tym formacie kolorów ( są wyjątki np DXT4 ).  Minusem jest to, że przeźroczystość przy nakładaniu textur czernieje.

Z tego własnie powodu twórcy XNA wybrali jako tryb domyślny Premultiplied Alpha.




 

Offline michal_2

  • Użytkownik

# Kwiecień 09, 2013, 17:25:26
Tak, zmieniłem na BlendState.NonPremultiplied i działa. Ale zgodnie z tym co napisałeś, Promultiplied powinno też zadziałać, bo jak alfa jest 127 (rozumiem, że w takim wypadku mnożymy przez 0.5?) to po pomnożeniu powinno o połowę zmniejszyć wartości wszystkich kolorów, a więc, dać kolor ciemniejszy. Ale tak nie jest, dlaczego?

Offline Pawelx156

  • Użytkownik

  • +1
# Kwiecień 09, 2013, 18:51:24
Jeśli twój kolor masz w byte ( 255,0,0,127) to jest on błędny dla Premultiplied Alpha gdyż max value może wynieść 127 czyli kolor powinien wyglądać tak ( 127,0,0,127)  co oznacza że ( przy kolorze RGBA ) dostaniesz  czerwoną przeźroczystość o wartość 50%.

Jeśli więc ( o ile dobrze ciebie rozumiem ) chcesz wykonać taką operacje Color(255,0,0,127) * 0.5f to i tak powstanie tobie zły kolor dla Premultiplied Alpha.
Premultiplied Alpha określa maksymalną wartość koloru  równą wartości alpha.
Przykłady:
Color(255,0,0,127) *0.5f - żle powstanie (127,0,0,63) <- wartość koloru R jest ponad wartością alpha.
Color(255,0,0,255) * 0.5F - dobrze. powstanie (127,0,0,127) <- wartości koloru (RGB) są mniejsze równe alpha.
Color(127,0,0,255) * 0.5f - dobrze. powstanie (63,0,0,127) <- to samo co wyżej.

Musisz zrozumieć że Premultiplied Alpha wymaga żeby składowe koloru (RGB) nie przekraczały samej wartości alpha (A).

« Ostatnia zmiana: Kwiecień 09, 2013, 18:55:15 wysłana przez Pawelx156 »