ZL31ARM: funkcje graficzne 3D

W artykule przedstawiamy zbiór procedur umożliwiających testowanie na STM32F103 procedur rysujących proste grafiki trójwymiarowe (3D) – doskonały wstęp do własnych, bardziej zaawansowanych ćwiczeń.

Użytkowników portalu zainteresowanych podobnymi funkcjami dla 2D odsyłamy do artykułu.
Do przygotowania przykładowych procedur wykorzystano modułu z wyświetlaczem LCD (KAmodTFT2 firmy KAMAMI.pl) oraz komputerek zintegrowany z programatorem JTAG – ZL31ARM z wbudowanym mikrokontrolerem STM32F103RB. Schemat elektryczny połączeń linii we/wy mikrokontrolera STM32 i modułu KAmodTFT2 pokazano na rysunku 1.

 

Rys. 1. Schemat podłączenia przycisków i wyświetlacza (zestawy ZL31ARM+KAmodTFT2)

Rys. 1. Schemat podłączenia przycisków i wyświetlacza (zestawy ZL31ARM+KAmodTFT2)

 

Wygląd połączonych ze sobą elementów zestawu testowego (ZL31ARM oraz KAmodTFT2) pokazano na fotografii 2.

 

Fot. 2. Wygląd zestawu testowego

Fot. 2. Wygląd zestawu testowego

 

Na fotografii 3 przedstawiono w jaki sposób związano układ współrzędnych, w którym operuje się standardowo (w zakresie od 1 do 130), z powierzchnią wyświetlacza.

 

Fot. 3. Standardowy układ współrzędnych

Fot. 3. Standardowy układ współrzędnych

 

Programy opisane w artykule powstały na bazie bibliotek opisanych w książce „Mikrokontrolery STM32 w praktyce”, dlatego przed rozpoczęciem ich testowania należy pobrać pliki źródłowe przykładów z tej książki (dostępne m.in. na stronie Wydawnictwa BTC).
Dodatkowe informacje o sposobie użycia tych bibliotek są dostępne w artykule.

Rysowanie sześcianu

Sześcian jest bryłą posiadającą 8 wierzchołków oraz 12 krawędzi. Aby ją narysować należy wyznaczyć 8 punktów charakterystycznych w przestrzeni 3D, rzutować te punkty na płaszczyznę (x,y) i połączyć je za pomocą linii. W danym projekcie zostanie to zrealizowane w sposób pośredni, czyli będą wyznaczone punkty końcowe linii tworzących krawędzie, które następnie zostaną narysowane.

 

 

Na początku pliku graphics.c jest zdefiniowana struktura zawierająca współrzędne początku i końca linii w przestrzeni 3D:

Zostanie ona wykorzystana w tablicy typu line3D[] przechowującej krawędzie sześcianu:

gdzie CWH to CUBE_WIDTH_HALF, czyli połowa długości boku, zdefiniowana na początku pliku jako:

Właściwie to są tworzone dwie tablice, z których cube[] zawiera stałe wartości wykorzystywane podczas transformacji, a rotatedCube[] będzie zawierał wynik tychże transformacji, które mogą się zmieniać w czasie działania programu.
Aby teraz narysować bryłę należy wykonać poniższe instrukcje:

Obrót i przesunięcie sześcianu

W celu dokonania obrotu bryły należy obrócić wszystkie linie tworzące krawędzie, które potem zostaną narysowane. Jest to robione za pomocą funkcji rotateLine() w pętli for:

Funkcja ta przyjmuje jako argumenty: strukturę wartości współrzędnych końcowych linii do obrócenia, wskaźnik do struktury w której zostaną zapisane przetransformowane współrzędne, oraz 3 kąty obrotu względem kolejnych osi układu OXYZ. Jej definicja wygląda następująco:

Ostatnia funkcja, która realizuje elementarny obrót punktów, o zadany kąt, wykorzystuje dwie zależności matematyczne:

i jest zaimplementowana następująco:

Pierwsze dwa argumenty funkcji to wartości aktualne współrzędnych punktu na określonej powierzchni, kolejny parametr to zadany kąt obrotu, a ostatnie dwa to wskaźniki na zmienne typu float do których zostaną zapisane nowe, przetransformowane wartości współrzędnych.
Efekt działania takiego kodu można sprawdzić za pomocą wywołania funkcji drawCube(), której struktura wygląda następująco:

Aby przez cały czas wyświetlać obracającą się bryłę wraz z możliwością przełączania względem której osi dokonywać obrót należy wykonać poniższy kod:

Tetrahedron, dodekahedron…

Opierając się na przedstawionym dotychczas materiale wraz z opisaną metodą realizacji rysowania prostej bryły nic nie stoi na przeszkodzie wyświetlania innych brył. Dla przykładu można narysować tetrahedron, który ma 4 wierzchołki i 6 krawędzi. W tym celu wystarczy zdefiniować 2 tablicy (tak jak w przypadku sześcianu):

oraz dodać dodatkową funkcję:

W podobny sposób można budować bardziej skomplikowane figury, poprzez podanie tylko tablicy z określonymi krawędziami oraz funkcji rysującej te krawędzie. Tutaj zostaje już tylko wyobraźnia użytkownika.

Lokalny układ współrzędnych

Czasem podczas animacji jakiegokolwiek obiektu pomocnym może okazać się widok na lokalny układ współrzędnych związany z danym obiektem i obracający się razem z nim. W tym celu należy dodać poniższą funkcję w pliku graphics.c:

oraz strukturę na początku:

Teraz można wywoływać tę funkcją podając dwie współrzędne na płaszczyźnie (x,y), 3 kąty obrotu oraz to czy ma być widoczny czy nie.

Ukrywanie niewidocznych krawędzi sześcianu

Jednym ze sposobów nadania bryle solidnej formy jest usunięcie tych krawędzi, które znajdują się z „tyłu”. Zrealizowana tutaj metoda ukrywania tych elementów działa dość dobrze tylko dla sześcianu. W przypadku innych brył należałoby zmodyfikować kod, jednak możliwe, że nie ze wszystkimi rodzajami brył ta metoda będzie współpracować.
Idea polega na tym, aby po obróceniu sześcianu i przed jego wyświetleniem, wyrzucić niepotrzebne krawędzie. Jako, że przyjęty globalny układ jest nieruchomy i jego oś z jest prostopadła i skierowana w stronę wyświetlacza, to zawsze przynajmniej jedna krawędź będzie miała ujemne współrzędne początku i końca w osi z. Przy wyznaczaniu wszystkich takich linii są znajdowane pewne wartości graniczne, dolne i górne w osi x i y. Dzięki nim będzie można określić czy dana krawędź jest widoczna czy nie. Ilustruje to poniższy kod:

Następnie należy wyszukać niewidocznych krawędzi:

Nowy zbiór krawędzi jest zapamiętywany w tablicy tempBUF[], która zostanie następnie wyświetlona:

Jan Szemiet

Do pobrania

Autor: varhyid@o2.pl