Grafika 3D
 
  Zarejestruj się
::  Newsy  ::  Pliki  ::  Twoje Konto  ::  Forum  ::
Menu
· Strona główna
· Forum
· Linki
· Lista u?ytkowników
· O nas...
· Pliki
· Statystyki
· Twoje Konto
Tutoriale
· API
· Matematyka
· Teoria
· Direct3D
· OpenGL
· Techniki
Kto Jest Online
Aktualnie jest 46 gość(ci) i 0 użytkownik(ów) online.

Jesteś anonimowym użytkownikiem. Możesz się zarejestrować za darmo klikając tutaj
Tutoriale - OpenGL - Blending

Siema ludziska :). Dzisiaj zajmiemy się blendingiem. Jest to bardzo fajny, choć w sumie dziwny temat. Pozwala na różne ciekawe efekty. I chociaż w niektórych książkach (czytaj w "OpenGL - księga eksperta" - no księga to to może i jest, ale eksperta ?? Kto czytał, ten wie czym to śmierdzi ;)) został usadowiony w dziale "Efekty specjalne", to jednak zapewniam, że nie jest wcale taki znowu specjalny - ot kolejny wzorek matematyczny i to wcale nie za bardzo skomplikowany W sumie powinno być w miarę krótko i zwięźle, tym bardziej że zmian w kodzie jest niewiele.

Jakkolwiek większości blending kojarzy się nieodzownie tylko z przezroczystością, to jednak ma on zastosowanie przy wielu innych efektach. Wszystko powinno być jasne, kiedy przetłumaczymy sobie ten zwrot na Polski. Otóż oznacza on nie tyle przezroczystość, co raczej mieszanie. I tak powinniśmy właśnie traktować to pojęcie - jako mieszanie barw (choć i tak wszyscy nazywają to przezroczystością :)). Na pewno wszystko się do końca wyjaśni w miarę czytania.
Zapewne wielu(-e) z was zastanawiało się zawsze po co istnieją funkcje typu glColor4f(). Przecież kolor, to wypadkowa kolorów czerwonego, zielonego i niebieskiego (czyli RGB). I owszem jest właśnie tak, jednakże komuś kiedyś nie wystarczyły tylko te trzy składowe, aby osiągnąć jakiś efekt i wpadł na pomysł składowej czwartej, którą nazwał kanałem alfa (ciekawe dlaczego wszyscy tak się uparli na te litery greckie - jakby symbol A był rzeczywiście czymś szczególnym :P ). Jak już powiedziałem jest to dodatkowa składowa koloru. Służy ona do określenia stopnia mieszania kolorów. Nie definiuje ona przezroczystości, ani innych efektów - do tego służą specjalne funkcje, których działanie trzeba zrozumieć, aby móc się pobawić mieszaniem barw bez ciągłego irytowania się i przeklinania na OpenGL czy jakikolwiek inny system graficzny. Funkcja (a właściwie wzór), która wykonuje mieszanie barw wygląda następująco :

RGBA_końcowe = RGBA_bufora * Ws + RGBA_obiektu * Wd

RGBA_końcowe to kolor piksela po przeprowadzeniu operacji mieszania kolorów, czyli tego, który ostatecznie pojawi się na ekranie. RGBA_bufora to kolor piksela aktualnie znajdującego się w buforze, który normalnie byłby po prostu zastąpiony pikselem obiektu (lub nie zależnie od Z-buffera). RGBA_obiektu to kolor piksela, który został wcześniej obliczony dla naszej bryły poprzez połączenie kolorów tekstury, oświetlenia, materiału. Natomiast Ws i Wd to pewne współczynniki od których zależy jaki efekt otrzymamy - to właśnie one zawierają naszą składową alfa. Możemy więc napisać, że:

Rs, Gs, Bs, As - składowe RGBA koloru piksela obiektu (source color)
Rd, Gd, Bd, Ad - składowe RGBA koloru piksela bufora (destination color)
WRs, WGs, WBs, WAs - składowe RGBA współczynnika dla pikseli obiektu
WRd, WGd, WBd, WAd - składowe RGBA współczynnika dla pikseli bufora

Tak więc każdą składową koloru wynikowego możemy zapisać analogicznie do np. czerwonej czyli:

R_wynikowe = Rd * WRd + Rs * WRs

Widzimy więc że wszystko zależy od naszych współczynników. Są one zdefiniowane wewnętrznie w OpenGL. Możliwe wartości dla każdego ze współczynników przedstawię w tabeli:

Typ
WRs
WGs
WBs
WAs
GL_ZERO
0
0
0
0
GL_ONE
1
1
1
1
GL_DST_COLOR
Rd
Gd
Bd
Ad
GL_ONE_MINUS_DST_COLOR
1-Rd
1-Gd
1-Bd
1-Ad
GL_SRC_ALPHA
As
As
As
As
GL_ONE_MINUS_SRC_ALPHA
1-As
1-As
1-As
1-As
GL_DST_ALPHA
Ad
Ad
Ad
Ad
GL_ONE_MINUS_DST_ALPHA
1-Ad
1-Ad
1-Ad
1-Ad
GL_SRC_ALPHA_SATURATE
ii
ii
ii
ii

gdzie ii = min( As, 1 - Ad ).

Te same wartości, oprócz ostatniej, dostępne są także dla współczynnika Wd. Mam nadzieje, ze jak trochę popatrzycie na to wszystko to coś wam się wyjaśni. Ale nie przejmujcie się zupełnie, jeśli za jakiś czas będziecie chcieli zrobić jakiś efekt za pomocą blendingu, ale wyjdzie wam nie to co chcieliście, albo w ogóle nic się nie pojawi. Blending ma to do siebie, że nie jest zbyt oczywisty (w ogóle nie jest oczywisty :P) i dopiero jak zapamiętacie jak wygląda wzór i co on tak naprawdę oznacza będziecie mogli się tym jako tako posługiwać. Ja też miałem z tym problem, pamiętam :))).

No dobra czas przejść w końcu do tego jak ten cały badziew można zrobić w OpenGL'u. Otóż po pierwsze należy mieszanie kolorów włączyć. Służy do tego ta sama funkcja co zawsze, tyle że z parametrem GL_BLEND. Czyli:
glEnable( GL_BLEND );
Po takiej operacji mieszanie kolorów zostanie włączone. Ale żeby móc ostro zamieszać potrzebujemy jeszcze ustalić nasze współczynniki. Robimy to za pomocą funkcji:
glBlendFunc( Ws, Wd );
Gdzie Ws i Wd przyjmują jedną z wartości wymienionych w tabeli. My używamy:
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
choć warto nadmienić, że nie jest to jedyna kombinacja dająca taki wynik (a przynajmniej bardzo zbliżony ). Pozostało już tylko jedno, czyli ustalić wartość kanału alfa. Moglibyśmy to zrobić na dwa sposoby. Pierwszy to dodanie do naszej struktury opisującej wierzchołek koloru, czyli zapisanie jej tak:
struct Vertex
{
    float         tex[2];
    unsigned char color[4];
    float         xyz[3];
};
Zapytacie zapewne dlaczego dla koloru jest unsigned char, a nie float? Otóż wynika to z tego, że jak pamiętacie renderujemy za pomocą VertexArrays, ale dane przesyłamy za pomocą glInterleavedArrays(). To właśnie z tego powodu jest unsigned char - OpenGL ma zdefiniowany tylko jeden typ danych który umożliwia przesłanie takiej ilości danych jaką chcemy, czyli 3xtekstura, 4xkolor, 3xwspółrzędne. Tym typem jest GL_T2F_C4UB_V3F. Jak więc pewnie już zauważyliście zmusza nas to do definiowania koloru za pomocą unsigned byte, czyli w C++ unsigned char, czyli inaczej mówiąc liczby 8 bitowej bez znaku ;)). Problem ten nie występuje, jeśli definiujemy osobne tablice dla wierzchołków, koloru, tekstury, itd. Zastanówmy się jakie byłyby konsekwencje dodania do naszej struktury składowych koloru? Otóż musielibyśmy do każdego wierzchołka dodać kolor, czyli każdy wierzchołek miałby o 32 bity więcej (4*8 bitów). Tyle razy już mówiłem, że najważniejsze jest zwiększanie prędkości i oszczędność pamięci, że nie będę już nawet pisał nad bezsensownością takiego postępowania w naszym przypadku. Miałoby to sens jeśli każdy wierzchołek byłby innego koloru, albo mniej lub bardziej przezroczysty. Ponieważ my jednak chcemy mieć jednakowego koloru kostkę, która wygląda jak ze szkła, wiec nie potrzebujemy dodawać koloru do każdego wierzchołka. Cóż zatem zrobimy? Skorzystamy z jednej ważnej cechy OpenGL'a, czyli z tego, że jeśli raz podamy kolor, to będzie on tak długo używany, jak długo nie podamy innego koloru. Wniosek z tego taki, że wystarczy przed wywołaniem naszej funkcji glDrawArrays() napisać:
glColor4f( 1.0f, 1.0f, 1.0f, 0.5f );
Czyli ustawić kolor na biały, a składową alfa na 0.5f, czyli w naszym przypadku na półprzezroczystą. Pozostaje jeszcze wyłączyć Z-buffor i ukrywanie niewidocznych powierzchni (jak zastanawiacie się po co je wyłączamy, to włączcie i spróbujcie ;)) i koniec - reszta kodu nie uległa zmianie (no może poza nazwą wczytywanej tekstury :)))))

Pozostało mi tylko powiedzieć jedną ważną rzecz, a mianowicie kiedy jest używana nasz wzór mieszający. Otóż OpenGL używa mieszania, w tym samym momencie, w którym normalnie przeprowadza buforowanie Z (no właściwie to tuż przed, ale my i tak mamy wyłączony Z-buffor :)). Jest to taka chwila, kiedy program dysponuje już obliczonym kolorem piksela, który ma umieścić na ekranie, czyli kiedy piksel obiektu (ale równie dobrze tekstury) przeszedł już obliczenia dla koloru światła, materiału itd. Wtedy to właśnie nasze API dochodzi do momentu, kiedy musi się zastanowić co zrobić z pikselem. Normalnie skorzystałby z bufora Z i albo zastąpił piksel na ekranie albo nie ;). Tym razem jednak w takim momencie zostaje zapuszczony nasz wzór wraz ze wszystkimi parametrami i dopiero na tej podstawie obliczany jest kolor piksela, który ostatecznie znajdzie się a ekranie.

A to, co powinniście dostrzec na ekranie po uruchomieniu progsa wyglądałoby mniej więcej tak:



Kod źródłowy

©Copyright by Domino   



Tutoriale - OpenGL
Nasze newsy s� w RSS: backend.php
PHP-Nuke Copyright © 2005 by Francisco Burzi. This is free software, and you may redistribute it under the GPL. PHP-Nuke comes with absolutely no warranty, for details, see the license.
Tworzenie strony: 0.47 sekund

:: Layout strony został stworzony przez www.nukemods.com w oparciu o styl phpbb2 Helius, którego autorem jest Cyberalien ::