Obliczenia w 3D

WileCoyote
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Poznań
  • Postów:20
0

Witajcie,

Od jakiegoś czasu, po godzinach piszę prosty silnik 3D, jednak pojawił się problem z którym nie mogę sobie poradzić. Założeniem było napisanie prostego programu w którym mogę w 3d obracać sześciany. Program jest napisany w C# i problemem jest sposób, w jaki określić współrzędne kursora w tym trójwymiarowym świecie. ;/
Fragment programu wygląda tak:
Program
Nic skomplikowanego, rysownica, kilka suwaków do obrotu kamery, etykiety z aktualnymi wartościami. Na rysownicy niebieskie linie są na współrzędnych o wysokości 0, skrzyżowanie dwóch pomarańczowych linii o punkt 0,0, dwóch czerwonych to środek ekranu.
Program działa w taki sposób, że każdyz punktów jest klasą Vector3D z zmiennymi X,Y,Z Przed ich rysowaniem jest wykonywana funkcja generująca dla każdego punktu współrzędne 2D, które potem są widoczne na rysownicy.
Do wykonywania obrotu geometrii stosuję taki kod:

Kopiuj
           if (cam.RotateZ.Value != 0)
           {
               var x = input.X * cam.RotateZ.ValueCosinus + input.Y * cam.RotateZ.ValueSinus;
               var y = input.X * -cam.RotateZ.ValueSinus + input.Y * cam.RotateZ.ValueCosinus;
               input.X = x;
               input.Y = y;
           } 
           if (cam.RotateY.Value != 0)
           {
               var x = input.X * cam.RotateY.ValueCosinus + input.Z * cam.RotateY.ValueSinus;
               var z = input.X * -cam.RotateY.ValueSinus + input.Z * cam.RotateY.ValueCosinus;
               input.X = x;
               input.Z = z;
           }
           if (cam.RotateX.Value != 0)
           {
               var y = input.Y * cam.RotateX.ValueCosinus + input.Z * cam.RotateX.ValueSinus;
               var z = input.Y * -cam.RotateX.ValueSinus + input.Z * cam.RotateX.ValueCosinus;
               input.Y = y;
               input.Z = z;
           }

cam - to inaczej klasa kamery w której mam zapisane wartości sinusów i cosinusów aby ich nie liczyć co chwile tylko podczas zmiany kąta, input, to punkt który jest przeliczany i następnie z niego jest brana współrzędna X,Y która jest rysowana. I to działa. :)

Jak wspomniałem wcześniej, problem jest wyliczenie współrzędnych kursora w 3D.
Robię to w taki sposób:

Kopiuj
            if (cam.RotateX.Value != 0)
            {
                input.Y /= cam.RotateX.ValueCosinus;
            }
            if (cam.RotateY.Value != 0)
            {
                input.X /= cam.RotateY.ValueCosinus;
            }
            if (cam.RotateZ.Value != 0)
            {
                var x10 = input.X * cam.RotateZ.InverseValueCosinus + input.Y * cam.RotateZ.InverseValueSinus;
                var y20 = input.X * -cam.RotateZ.InverseValueSinus + input.Y * cam.RotateZ.InverseValueCosinus;
                input.X = x10;
                input.Y = y20;
            }

Ten kod działa, pod warunkiem że nie ma jednoczesnego obrotu w osi X i Y, w przeciwnym wypadku pojawiają się dziwne liczby. Jako dane wejściowe są współrzędne XY kursora z formatki (przez co input.Z = 0). "Inverse" to inaczej wartość kąta w stopniach pomnożona -1.

Czy ktoś mógłby mi podpowiedzieć jak zmienić ten fragment kodu aby wyliczyć poprawnie współrzędne kursora? Spodziewam się że problem jest nieuwzględnienie input.Z ale nie wiem jak to zrobić.

LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:2 minuty
  • Postów:8399
0

Ten kod działa, pod warunkiem że nie ma jednoczesnego obrotu w osi X i Y, w przeciwnym wypadku pojawiają się dziwne liczby.

Może w złej kolejności przeprowadzasz te obroty? Kolejność może mieć znaczenie w tym przypadku. A może coś pomyliłeś z obliczeniami (ale to musiałbyś sprawdzić tam skąd bierzesz (albo wyprowadzasz) wzory (wiem, że to żadna porada w tym momencie, ale mimo wszystko jak coś nie działa, to może od strony matematycznej nie ma to sensu, spróbuj to jakoś rozrysować czy sprawdzić na jakichś stronach o matmie czy na StackOverflow).

Ew. możesz poszukać też informacji o tym, jak się robi rotację na macierzach czy kwaternionach, może będzie łatwiej.
Zapewne też do macierzy i kwaternionów znajdziesz mnóstwo przykładów kodu w sieci, bo w silnikach 3D się używa tych technik.

Czyli ja bym poszukał haseł:
rotation 3d, euler rotation, rotation matrix, quaternions


edytowany 4x, ostatnio: LukeJL
katakrowa
  • Rejestracja:około 10 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Chorzów
  • Postów:1670
2

Nie widzę całego programu ale znam problem i w 99% wynika on z tego, że robisz to źle ( wynika to z tego, że optymalizujesz liczenie sinusów, które przy poprawnej implementacji wymagane jest jedynie do obracania kamery a i to tylko w niektórych przypadkach ).

Jeśli możesz wrzucić cały kod programu to zerknę jednak fajnie jak opisałbyś jaką ogólną koncepcję przyjąłeś. Czy chodzisz kamerą po scenie czy np. kręcisz całą sceną o kąty wynikające z parametrów kamery. Niby to samo ale w praktyce wychodzi zupełnie coś innego. Ważne jest także jaki wybrałeś sposób rzutowania na płaszczyznę.

Poprawna metoda to statyczna scena po której rusza się kamera. Przeliczamy tylko te punkty, które mamy w ostrosłupie kamery(+niezbędny margines jeśli mamy trójkąty czyli pozostałe punkty trójkątów, które załapały się na kamerę).
Generalnie tematyka jest z jednej strony bardzo złożona ale jeśli od razu zabierzemy się do tematu jak należy to nie jest tak strasznie.

Jakiś czas temu w poście https://4programmers.net/Forum/Algorytmy/335561-algorytm_bresenhama_z_niezmienna_osia_wiodaca?p=1649661#id1649661 zamieściłem materiały, z którymi warto się zapoznać przed pisaniem czegoś takiego. Najpierw przejrzyj a potem dogłębnie przeanalizuj punkt 2.3 ( rzutowanie ).

Na twoim obrazku nie widzę perspektywy więc wnoszę, że robisz zwykły rzut równoległy a do do silnika gier nie będzie się nadawało. Musisz mieć perspektywę która wynika sama z rzutu ( http://mst.mimuw.edu.pl/lecture.php?lecture=gk1&part=Ch5 ). Ogólnie prowadzisz proste między okiem kamery do punku sceny i wyliczasz punkty przecięcia z płaszczyzną, która jest ekranem.


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
edytowany 2x, ostatnio: katakrowa
WileCoyote
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Poznań
  • Postów:20
0

Poprawione, dzięki @katakrowa za naprowadzenie mnie na materiały które są bardzo wartościowe!.
Jeśli chodzi o perspektywę... no tutaj nie ma nie ma jeszcze szału, ale myślę ze za jakiś czas coś się uda ciekawego zrobić ;)

Perspektywa

Przyjąłem taką zasadę że cała scena obraca się aktualnie na środku ekranu (oczywiście uwzględniając przesunięcie całej sceny w osi XYZ), ale docelowo chce aby np. ctrl + scroll myszki za to odpowiadał. Obecnie scrollowanie mam do punktu gdzie jest kursor lub do środka ekranu. Przesuwanie też jest za pomocą myszki (lub przycisków w prawym górnym rogu). Pierwotnie miało to być 2D, ale że apetyt rośnie w miarę jedzenia to rozbudowuję to na 3D ;)

katakrowa
Teraz się przyjrzałem i widzę, że masz perspektywę. Pytanie czy wynika ona z rzutowania na płaszczyznę czy z mnożenia x i y przez "1/z"?
katakrowa
  • Rejestracja:około 10 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Chorzów
  • Postów:1670
2

@WileCoyote: Przyjąłem taką zasadę że cała scena obraca się aktualnie na środku ekranu
To bardzo bardzo bardzo źle.
Każdorazowe przeliczanie punktów sceny powoduje, że podczas obliczeń zmieniasz ich wartości na nowe. Każda taka zamiana powoduje powstawanie małych błędów wynikających z obliczeń na liczbach typu float. Te błędy niestety się sumują i scena zacznie Ci się rozlatywać. krawędzie ścian przestaną być równoległe, wierzchołki wielokątów przestaną się pokrywać.

Przesuwanie po osiach X,Y,Z to kolejny błąd. Jak scenę będziesz miał dużą to przy większych odległościach od środka sceny błędy precyzji liczb typu float są coraz większe doprowadzając to tego samego co ich wielokrotne "obracanie/przeliczanie".

Do każdej klatki musisz brać dane z oryginalnej sceny. Gorąco polecam Ci zaimplementować opcję z ruchomą kamerą po stałej scenie. Nie wiem ile masz lat i przypuszczam, że to może być dla Ciebie z punktu widzenia matematyki nieco trudniejsze niż obracanie wokół osi sinusami i cosinusami ale uwierz mi warto poświęcić te 2 dni na analitykę.
Metoda, której używasz jest dobra jedynie do prezentacji pojedynczych obiektów ale już nie nadaje się do zrobienia silnika do gry ( chyba, że to będzie gra w kostkę Rubika albo szachy ).

Kolejne zalety wynikające z proponowanego podejścia:

  • praktycznie brak użycia funkcji trygonometrycznych;
  • możliwość umieszczenia na scenie kilku kamer;
  • tworzenia kamer o różnej perspektywie t.j. żaba albo rybie oko ( to wszystko potem jest już banalne ).
  • ułatwienie przygotowania danych dalszych obliczeń związanych z wypełnianiem trójkątów itp ...
  • łatwiejsze umieszczanie obiektów na scenie ( w końcu będzie statyczna ).

Jeśli będziesz miał problemy śmiało zapytaj a ja postaram się pomóc


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
WileCoyote
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Poznań
  • Postów:20
0

@katakrowa - taki obrót jest naprawdę zły? Przecież uwzględniam przesunięcie kamery co uważam daje pożądany efekt. Może po prostu źle to opisałem, ale uważam że jest możliwość umieszczenia kilku kamer (tzn. późniejszej wersji umieszczę kilka kolorowych obiektów i kilka kamer aby było to widoczne że to kamera się obraca a nie scena).
W prywatnej wiadomości wysłałem Ci linka gdzie możesz pobrać ten program i zobaczyć jak to wygląda :)

Jeśli chodzi o materiały - to tak, w tym tygodniu chce lepiej je poznać. Dodatkowo znalazłem jeden projekt w C#
https://www.codeproject.com/Articles/36868/Quaternion-Mathematics-and-3D-Library-with-C-and-G
któremu tez się przyjże.

Jeśli chodzi o perspektywę... to raczkuje. Ale mam nadzieje zrobić coś dobrego

katakrowa
  • Rejestracja:około 10 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Chorzów
  • Postów:1670
1
WileCoyote napisał(a):

@katakrowa - taki obrót jest naprawdę zły? Przecież uwzględniam przesunięcie kamery co uważam daje pożądany efekt. Może po prostu źle to opisałem, ale uważam że jest możliwość umieszczenia kilku kamer (tzn. późniejszej wersji umieszczę kilka kolorowych obiektów i kilka kamer aby było to widoczne że to kamera się obraca a nie scena).

W prywatnej wiadomości wysłałem Ci linka gdzie możesz pobrać ten program i zobaczyć jak to wygląda :)

Jeśli chodzi o materiały - to tak, w tym tygodniu chce lepiej je poznać. Dodatkowo znalazłem jeden projekt w C#
https://www.codeproject.com/Articles/36868/Quaternion-Mathematics-and-3D-Library-with-C-and-G
któremu tez się przyjże.

Jeśli chodzi o perspektywę... to raczkuje. Ale mam nadzieje zrobić coś dobrego

Na ekranie na początku zabawy wygląda podobnie i wydaje się, że to jest to samo ale w praktyce sumują się błędy, które w końcu ( po określonej licznie obrotów ) zaczną mieć wpływ na poprawność obliczeń i kształty obiektów zaczną się rozlatywać.

Niestety do końca nie wiem jak to jest u Ciebie rozwiązane. Powinno być tak:

screenshot-20201130170227.png

To co robisz nie jest błędem. Jedynie metoda, którą wybrałeś nie nadaje się do zastosowania jako silnik do 3D. Silnik 3D nie powinien być pisany wiedząc, że długie poruszanie się po scenie spowoduje nieuniknione problemy. Dlatego właśnie wymyślono inne metody, które na wymienione problemy są odporne. Owszem trzeba poznać 2 lub dodatkowe wzory no ale to nie jest jakaś tajemna wiedza.

screenshot-20201130170720.png


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)