W poprzedniej części serii poświęconej tematyce WPF 3D, opisane zostały rodzaje materiałów, jakimi można pokrywać figury i bryły w tworzonej scenie 3D, pominięte ciszą zostały natomiast pędzle wykorzystywane do przygotowania odpowiedniego materiału. W tym
wpisie wiadomości dotyczące pokrycia figur zostaną uzupełnione i omówione zostaną pędzle, które są elementem wykorzystanego materiału.
Niniejszy wpis poza prezentacją różnych i niezależnych od konkretnego wykorzystania treści stanowi również opis pewnych zagadnień związanych z projektem Mesh Diagram 3D.Informacje dotyczące projektu oznaczone są etykietą MeshDiagram3D.
Wykorzystanie pędzla jest konieczne do przygotowania materiału dla wybranej figury lub bryły w scenie. W odróżnieniu jednak od opisywanych wcześniej elementów i wykorzystywanych klas wchodzących w skład WPF 3D (czyli przestrzeni nazw: System.Windows.Media.Media3D), pędzle są obiektami klas wchodzących w skład pakietu WPF do wyświetlania „zwykłej”, dwuwymiarowej grafiki. W związku z tym, dla tych, którzy już znają pochodne klasy System.Windows.Media.Brush nie będą one niczym nowym,
natomiast dla tych, którzy jeszcze ich nie znają, polecam
przeczytanie dokumentacji dostępnej pod adresem:
http://msdn.microsoft.com/en-us/library/aa970904.aspx.
W tym wpisie wskażę jedynie pewne efekty, jakie można uzyskać
poprzez wykorzystanie pędzli.
Zacznijmy od najprostszego ....
SolidColorBrush
SolidColorBrush jest wyjątkowo prostym pędzlem i pozwala na
pomalowanie bryły lub figury pewnym, wybranym kolorem. Zobaczmy
prosty przykład, wykorzystując:
Material material = new DiffuseMaterial(new SolidColorBrush( Colors.Blue ) );
otrzymujemy:
LinearGradientBrush i RadialGradientBrush (GradientBrush)
LinearGradientBrush i RadialGradientBrush, to pędzle
trochę bardziej zaawansowane. Dziedziczą po pędzlu GradientBrush
i pozwalają pokryć obiekt gradientem. Poza definicją samego pędzla
należy pamiętać o ustawieniu właściwości TextureCoordinates dla
krytej pędzlem siatki/figury (MeshGeometry3D).
Jako przykład przyjrzyjmy się scenie podobnej do powyższej, ale
pokrytej z wykorzystaniem pędzla LinearGradientBrush,
a więc kod:
mesh.TextureCoordinates = ( (PointCollection)new PointCollectionConverter().ConvertFromString( "0,0 0,1 1,1 1,0" ) ); LinearGradientBrush myBrush = new LinearGradientBrush(); myBrush.GradientStops.Add( new GradientStop( Colors.Yellow, 0.0 ) ); myBrush.GradientStops.Add( new GradientStop( Colors.Red,0.5) ); myBrush.GradientStops.Add( new GradientStop( Colors.Blue, 1 ) ); Material material = new DiffuseMaterial( myBrush );
Da nam w efekcie:
TextureCoordinates
W tym miejscu należy jeszcze wspomnieć o teksturowaniu, czyli
zgodnie z Wikipedią:
„Teksturowanie
- technika stosowana w grafice
trójwymiarowej, której celem jest przedstawienie szczegółów
powierzchni obiektów przestrzennych za pomocą obrazów
bitmapowych (tekstur) lub funkcji
matematycznych (tekstur
proceduralnych). Mapowanie tekstury
określa, w jaki sposób powiązać piksele
lub wartości funkcji z powierzchnią obiektu. Tekstury niosą
informacje o barwie
powierzchni, jak również innych parametrach generowanego obrazu,
związanych np. z modelem oświetlenia: barwa światła odbitego,
rozproszonego, stopień przezroczystości, współczynnik załamania
światła itp.”
Na siatkę (w tym przypadku MeshGeometry3D), tworzącą bryłę
scenie 3D nakładamy więc teksturę. Aby tekstura nałożona była
właściwie (a nawet aby w ogóle było ją widać), należy ustawić
odpowiednie jej koordynaty we właściwości TextureCoordinates
siatki. W ramach tej właściwości ustawiamy współrzędne tekstury
(listę punktów) określających, jak wybrany materiał jest
mapowany na wierzchołki trójkątów, które tworzą siatkę.
VisualBrush
Kolejnym ciekawym pędzlem jest VisualBrush, który pozwala na
„malowanie” elementami GUI wchodzącymi w skład WPF-a, np.
TexBlock'iem, który można użyć do wyprowadzania teksu:
TextBlock textblock = new TextBlock( new Run( "maciek" ) ); textblock.Foreground = new SolidColorBrush( Colors.Green ); textblock.FontFamily = new FontFamily( "Arial" ); Material material = new DiffuseMaterial( new VisualBrush( textblock ) );
Powyższy kod, pozwoli na uzyskanie następującego efektu:
Aby dowiedzieć się więcej na temat wyprowadzania tekstu, polecam
zapoznać się z artykułem: „Tworzenie
napisów dla scen 3D tworzonych przy pomocy WPF”
ImageBrush
ImageBrush jest chyba najciekawszym pędzlem do wykorzystania
w scenie 3D. Pozwala na nanoszenie na obiekty w scenie dowolnych
obrazków (tekstur), np.:
ImageBrush imageBrush = new ImageBrush(); imageBrush.ImageSource = new BitmapImage( new Uri( @".\maciej-progtech-wpf-3d-light-sun.jpg", UriKind.Relative ) ); Material material = new DiffuseMaterial( imageBrush );
W efekcie otrzymamy:
Kafelkowanie
Tutaj należy jeszcze wspomnieć o kafelkowaniu, czyli składaniu
materiału z wielu obrazków. W tym celu należy ustawić
właściwości: TileMode
(jakie kafelkowanie), Viewbox
(jaki fragment tekstury wyświetlamy?), VieboxUnits
(w jakich jednostkach ustawiamy fragment tekstury, który
wyświetlamy), Viewport
(jaki fragment ma zajmować wyświetlana tekstura?), ViewportUnits
( w jakich jednostkach ustawiamy fragment, który ma zajmować
wyświetlana tekstura).
W poniższym przykładzie wykorzystałem pędzel z poprzedniego
przykładu, ale zmieniłem ustawienia „kafelkowania”:
imageBrush.TileMode = TileMode.Tile; imageBrush.Viewport = ( (Rect)new RectConverter().ConvertFromString( "0,0,0.5,0.5" ) );
Dało to w efekcie:
Na koniec chciałbym jeszcze dodać, że warto
zajrzeć na MSDN'a i przeczytać również „MSDN:
Painting
with Images, Drawings, and Visuals”
Mam pytanie a propos ImageBrush.
OdpowiedzUsuńOtóż nie bardzo czaję kwestię ścieżki do grafiki.
Testowo stworzyłem sobie coś takiego:
ImageBrush brush = new ImageBrush(new BitmapImage(new Uri(BaseUriHelper.GetBaseUri(this), "Images/test.png")));
label1.Background = brush;
I powyższy kod działa.
Niestety, gdy ładuję ten sam pędzel w poniższy sposób:
Material material = new DiffuseMaterial(brush);
scena nie jest renderowana.
Czy możesz mi podsunąć pomysł na rozwiązanie problemu?
Z góry dzięki.
Pozdrawiam
Przepraszam za zwłokę. Odpowiedź napisałem tutaj: http://maciej-progtech.blogspot.com/2012/01/wpf-lepiej-umiescic-obrazek-w-resources.html
OdpowiedzUsuńWarto jeszcze doczytać dodatkowe informacje tutaj: WPF: o zasobach (resources) coś więcej.
OdpowiedzUsuńCzesc, mianowicie nie bardzo wiem jak mam ustawic texturecoordinates by obrazek byl rowno na obu trojkatach (tak jak u ciebie przy imagebrush), moj aktualny model wylgada tak http://i.imgur.com/uwkbYU6.jpg, chcialbym by te paski były równo.
OdpowiedzUsuńmocno inspirujący wpis!
OdpowiedzUsuńpomocny wpis!
OdpowiedzUsuńŚwietny tekst! Od roku nie czytałam tak wartościowego artykułu.
OdpowiedzUsuń