rm zad
This commit is contained in:
parent
0446a2bfe3
commit
81e5a55669
133
zadanie.html
133
zadanie.html
@ -1,133 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="generator" content="pandoc" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
|
||||||
<title>zadanie</title>
|
|
||||||
<style>
|
|
||||||
code{white-space: pre-wrap;}
|
|
||||||
span.smallcaps{font-variant: small-caps;}
|
|
||||||
span.underline{text-decoration: underline;}
|
|
||||||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
|
||||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
|
||||||
ul.task-list{list-style: none;}
|
|
||||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
|
||||||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
|
||||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
|
||||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
|
||||||
div.sourceCode { margin: 1em 0; }
|
|
||||||
pre.sourceCode { margin: 0; }
|
|
||||||
@media screen {
|
|
||||||
div.sourceCode { overflow: auto; }
|
|
||||||
}
|
|
||||||
@media print {
|
|
||||||
pre > code.sourceCode { white-space: pre-wrap; }
|
|
||||||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
|
||||||
}
|
|
||||||
pre.numberSource code
|
|
||||||
{ counter-reset: source-line 0; }
|
|
||||||
pre.numberSource code > span
|
|
||||||
{ position: relative; left: -4em; counter-increment: source-line; }
|
|
||||||
pre.numberSource code > span > a:first-child::before
|
|
||||||
{ content: counter(source-line);
|
|
||||||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
|
||||||
border: none; display: inline-block;
|
|
||||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
|
||||||
-khtml-user-select: none; -moz-user-select: none;
|
|
||||||
-ms-user-select: none; user-select: none;
|
|
||||||
padding: 0 4px; width: 4em;
|
|
||||||
color: #aaaaaa;
|
|
||||||
}
|
|
||||||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
|
||||||
div.sourceCode
|
|
||||||
{ }
|
|
||||||
@media screen {
|
|
||||||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
|
||||||
}
|
|
||||||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
|
||||||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
|
||||||
code span.at { color: #7d9029; } /* Attribute */
|
|
||||||
code span.bn { color: #40a070; } /* BaseN */
|
|
||||||
code span.bu { } /* BuiltIn */
|
|
||||||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
|
||||||
code span.ch { color: #4070a0; } /* Char */
|
|
||||||
code span.cn { color: #880000; } /* Constant */
|
|
||||||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
|
||||||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
|
||||||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
|
||||||
code span.dt { color: #902000; } /* DataType */
|
|
||||||
code span.dv { color: #40a070; } /* DecVal */
|
|
||||||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
|
||||||
code span.ex { } /* Extension */
|
|
||||||
code span.fl { color: #40a070; } /* Float */
|
|
||||||
code span.fu { color: #06287e; } /* Function */
|
|
||||||
code span.im { } /* Import */
|
|
||||||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
|
||||||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
|
||||||
code span.op { color: #666666; } /* Operator */
|
|
||||||
code span.ot { color: #007020; } /* Other */
|
|
||||||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
|
||||||
code span.sc { color: #4070a0; } /* SpecialChar */
|
|
||||||
code span.ss { color: #bb6688; } /* SpecialString */
|
|
||||||
code span.st { color: #4070a0; } /* String */
|
|
||||||
code span.va { color: #19177c; } /* Variable */
|
|
||||||
code span.vs { color: #4070a0; } /* VerbatimString */
|
|
||||||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
|
||||||
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="style.css" />
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1 id="wstęp">1 Wstęp</h1>
|
|
||||||
<p>Celem tych zadań jest zapoznanie się z biblioteką assimp służącą do wczytywania modeli 3d w różnych formatach.</p>
|
|
||||||
<p>Projekt VS do nich dołączony jest dobrym punktem wyjścia do zaczęcia projektu zaliczeniowego, ponieważ zawiera wszystkie wymagane biblioteki.</p>
|
|
||||||
<h1 id="ładowanie-pliku">2 Ładowanie pliku</h1>
|
|
||||||
<h2 id="export-z-blendera">2.1 Export z blendera</h2>
|
|
||||||
<p>Internet jest pełen wszelakiej maści modeli 3d (na końcu jest zbiór linków gdzie szukać modeli). Wiele z nich jest dostępnych za darmo, jednak jak to bywa z rzeczami za darmo zazwyczaj nie będą przygotowane pod nasze potrzeby dlatego, trzeba je chociaż w podstawowym zakresie obrobić i wyeksportować do odpowiedniego formatu. W tym celu najlepiej użyć Blendera, który jest darmowy i posiada szeroką grupę pasjonatów udostępniających modele i poradniki za darmo.</p>
|
|
||||||
<p>W folderze model znajdują się pliki <code>arm.blend</code> oraz <code>arm.fbx</code>. Niestety assimp nie obsługuje plików blend z wersji >2.79 (nie polecam używać blendera poniżej 2.80, interfejs jest wyjątkowo nieczytelny), dlatego modele trzeba eksportować do innego formatu, na nasze potrzeby odpowiedni będzie format <strong>fbx</strong>. Otwórz plik <code>arm.blend</code> w Blenderze (w oknie ładowania pod kołem zębatym jest opcja <strong>load ui</strong> polecam ją wyłączyć, gdy ładujemy nieswoje projekty), zawiera on proste ramie robota. ma ono strukturę hierarchiczną: przykładowo ramie jest dzieckiem kuli, więc jeśli obrócisz kulę, to ramie za nią podąży. Zachowując tą hierarchię będziemy mogli animować ramie za pomocą grafu sceny. Opcja eksportu znajduje się w File->Export->FBX, w <strong>Include</strong> w object types zaznacz tylko opcję <strong>Mesh</strong>. Upewnij się, że w zakładce <strong>Transform</strong> opcja <strong>Apply Scalinng</strong> jest ustawiona na <strong>FBX Units Scale</strong>. zapisz plik w folderze models. ## 2.2 Import przez assimp Modele importuje się za pomocą klasy <code>Assimp::Importer</code> i metody <code>ReadFile</code>. Przyjmuje ona ścieżkę do modelu oraz flagi, które określają jakie kroki ma wykonać importer w postprocesingu, może być to obliczenie przestrzeni stycznej czy triangularyzacja. Metoda zwraca wskaźnik na <code>aiScene</code>, jeżeli import się powiódł. Jeżeli nie błąd można pobrać za pomocą <code>importer.GetErrorString()</code>. Zmienna <code>aiScene</code> zawiera dane o scenie, takie jak <em>mesh</em>, informację o materiałach czy hierarchię obiektów w postaci drzewa. Korzeniem drzewa jest <code>scene->mRootNode</code>. W naszym przypadku <code>RootNode</code> będzie miał jednego syna, czyli <strong>base</strong> w pliku <code>blend</code>, on z kolei będzie miał syna <strong>ball</strong> itd. każdy węzęł zawiera informację o konkretnym modelu jak liczba meshy i ich indeksy w scenie, materiały itd. Przykładowo wczytanie samej bazy będzie wyglądać następująco:</p>
|
|
||||||
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a> Assimp::Importer importer;</span>
|
|
||||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="at">const</span> aiScene* scene = importer.ReadFile(<span class="st">"models/arm.fbx"</span>, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace);</span>
|
|
||||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// check for errors</span></span>
|
|
||||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) <span class="co">// if is Not Zero</span></span>
|
|
||||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> {</span>
|
|
||||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> <span class="bu">std::</span>cout << <span class="st">"ERROR::ASSIMP:: "</span> << importer.GetErrorString() << <span class="bu">std::</span>endl;</span>
|
|
||||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span>;</span>
|
|
||||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> }</span>
|
|
||||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">auto</span> node = scene->mRootNode->mChildren[<span class="dv">0</span>];</span>
|
|
||||||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> aiMesh* mesh = scene->mMeshes[node->mMeshes[<span class="dv">0</span>]];</span>
|
|
||||||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> armContext.initFromAssimpMesh(mesh);</span></code></pre></div>
|
|
||||||
<p>By przejść po całej scenie potrzebujemy funkcję rekurencyjną <code>loadRecusive</code>, która załaduje meshe z danego węzła, doda je do vectora <code>armContexts</code>, następnie wywoła się dla wszystkich jego synów. Napisz taką funkcję i wyświetl wszystkie obiekty z vectora z macierzą modelu ustawioną na identyczność. Otrzymaliśmy na obiekty, ale są one wyświetlane jeden na drugim, ponieważ nie wczytaliśmy macierzy opisujących ich położenie. Rozwiążemy to w następnym etapie # 3 Graf Sceny Każdy węzeł zawiera atrybut <code>mTransformation</code>, który jest macierzą transformacji względem ojca. By na jej podstawie uzyskać macierz modelu zbudujemy prosty graf sceny. Użyjemy do tego vektora. W <code>RenderUtils.h</code> znajduje się struktura <code>Node</code>, która zawiera: * <code>vector<RenderContext></code>, w którym będziemy umieszczać dane jego meshy, * macierz modelu * <code>int parent</code>, który będzie zawierał indeks modelu lub -1 jeżeli jest korzeniem.</p>
|
|
||||||
<p>Przerób funkcję <code>loadRecusive</code>. Dodaj argument parent, w którym będziemy przesyłać rekurencyjnie indeks ojca. Zmodyfikuj tak, żeby każde wywołanie dodawało element do <code>vector<Node> arm</code> i uzupełniał go o meshe, indeks ojca i macierz transformacji. <code>node->mTransformation</code> ma typ <code>aiMatrix4x4</code>, musisz ją konwertować za pomocą <code>Core::mat4_cast</code>.</p>
|
|
||||||
<p>Do wyświetlenia wykorzystaj poniższy kod</p>
|
|
||||||
<div class="sourceCode" id="cb2"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a></span>
|
|
||||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (<span class="kw">auto</span> part : arm) {</span>
|
|
||||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> glm::mat4 transformation=part.matrix;</span>
|
|
||||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> parent = part.parent;</span>
|
|
||||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> (parent != -<span class="dv">1</span>) {</span>
|
|
||||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> transformation = arm[parent].matrix * transformation;</span>
|
|
||||||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> parent = arm[parent].parent;</span>
|
|
||||||
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> }</span>
|
|
||||||
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (<span class="kw">auto</span> context : part.renderContexts) drawObject(program, context, transformation, glm::vec3(<span class="fl">0.6</span><span class="bu">f</span>));</span>
|
|
||||||
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> }</span></code></pre></div>
|
|
||||||
<h1 id="animacja">4 Animacja</h1>
|
|
||||||
<p>Dodamy ruch ramienia na klawisze <strong>o</strong> i <strong>p</strong>. By ramie się obracało zgodnie z intuicją wystarczy, że dodamy rotację do kuli (<em>Ball</em>) a graf sceny załatwi resztę. Po pierwsze potrzebujemy znać pozycję kuli w vectorze. Dodaj do <code>loadRecusive</code> sprawdzenie czy nazwa (znajduje się w <code>node->mName</code>) to <code>aiString("Ball")</code>, jeżeli tak, przypisz do zmiennej globalnej ballIndex indeks węzła w vectorze <code>arm</code>. Pozostaje dodać obsługę przycisków w funkcji <code>keyboard</code>. By wykonać obrót przemnóż od prawej macierz kuli o macierz obrotu o mały kąt. Możesz też wykorzystać wejście myszki i obroty za pomocą kwaternionów z najnowszych ćwiczeń</p>
|
|
||||||
<h1 id="linki">linki</h1>
|
|
||||||
<ul>
|
|
||||||
<li>https://assimp-docs.readthedocs.io/ dokumentacja assimp</li>
|
|
||||||
<li>https://learnopengl.com/Model-Loading/Assimp tutorial w learnopengl</li>
|
|
||||||
<li>https://www.blender.org/download/ blender</li>
|
|
||||||
</ul>
|
|
||||||
<h2 id="modele-3d">modele 3d</h2>
|
|
||||||
<ul>
|
|
||||||
<li>https://www.blendswap.com</li>
|
|
||||||
<li>https://sketchfab.com</li>
|
|
||||||
<li>https://www.cgtrader.com/</li>
|
|
||||||
<li>https://www.turbosquid.com/</li>
|
|
||||||
<li>https://open3dmodel.com/</li>
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
66
zadanie.md
66
zadanie.md
@ -1,66 +0,0 @@
|
|||||||
# 1 Wstęp
|
|
||||||
|
|
||||||
Celem tych zadań jest zapoznanie się z biblioteką assimp służącą do wczytywania modeli 3d w różnych formatach.
|
|
||||||
|
|
||||||
Projekt VS do nich dołączony jest dobrym punktem wyjścia do zaczęcia projektu zaliczeniowego, ponieważ zawiera wszystkie wymagane biblioteki.
|
|
||||||
|
|
||||||
# 2 Ładowanie pliku
|
|
||||||
## 2.1 Export z blendera
|
|
||||||
|
|
||||||
Internet jest pełen wszelakiej maści modeli 3d (na końcu jest zbiór linków gdzie szukać modeli). Wiele z nich jest dostępnych za darmo, jednak jak to bywa z rzeczami za darmo zazwyczaj nie będą przygotowane pod nasze potrzeby dlatego, trzeba je chociaż w podstawowym zakresie obrobić i wyeksportować do odpowiedniego formatu. W tym celu najlepiej użyć Blendera, który jest darmowy i posiada szeroką grupę pasjonatów udostępniających modele i poradniki za darmo.
|
|
||||||
|
|
||||||
W folderze model znajdują się pliki `arm.blend` oraz `arm.fbx`. Niestety assimp nie obsługuje plików blend z wersji >2.79 (nie polecam używać blendera poniżej 2.80, interfejs jest wyjątkowo nieczytelny), dlatego modele trzeba eksportować do innego formatu, na nasze potrzeby odpowiedni będzie format **fbx**.
|
|
||||||
Otwórz plik `arm.blend` w Blenderze (w oknie ładowania pod kołem zębatym jest opcja **load ui** polecam ją wyłączyć, gdy ładujemy nieswoje projekty), zawiera on proste ramie robota. ma ono strukturę hierarchiczną: przykładowo ramie jest dzieckiem kuli, więc jeśli obrócisz kulę, to ramie za nią podąży. Zachowując tą hierarchię będziemy mogli animować ramie za pomocą grafu sceny. Opcja eksportu znajduje się w File->Export->FBX, w **Include** w object types zaznacz tylko opcję **Mesh**. Upewnij się, że w zakładce **Transform** opcja **Apply Scalinng** jest ustawiona na **FBX Units Scale**. zapisz plik w folderze models.
|
|
||||||
## 2.2 Import przez assimp
|
|
||||||
Modele importuje się za pomocą klasy `Assimp::Importer` i metody `ReadFile`. Przyjmuje ona ścieżkę do modelu oraz flagi, które określają jakie kroki ma wykonać importer w postprocesingu, może być to obliczenie przestrzeni stycznej czy triangularyzacja. Metoda zwraca wskaźnik na `aiScene`, jeżeli import się powiódł. Jeżeli nie błąd można pobrać za pomocą `importer.GetErrorString()`. Zmienna `aiScene` zawiera dane o scenie, takie jak *mesh*, informację o materiałach czy hierarchię obiektów w postaci drzewa. Korzeniem drzewa jest `scene->mRootNode`. W naszym przypadku `RootNode` będzie miał jednego syna, czyli **base** w pliku `blend`, on z kolei będzie miał syna **ball** itd. każdy węzęł zawiera informację o konkretnym modelu jak liczba meshy i ich indeksy w scenie, materiały itd. Przykładowo wczytanie samej bazy będzie wyglądać następująco:
|
|
||||||
```c++
|
|
||||||
Assimp::Importer importer;
|
|
||||||
const aiScene* scene = importer.ReadFile("models/arm.fbx", aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace);
|
|
||||||
// check for errors
|
|
||||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
|
|
||||||
{
|
|
||||||
std::cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto node = scene->mRootNode->mChildren[0];
|
|
||||||
aiMesh* mesh = scene->mMeshes[node->mMeshes[0]];
|
|
||||||
armContext.initFromAssimpMesh(mesh);
|
|
||||||
```
|
|
||||||
By przejść po całej scenie potrzebujemy funkcję rekurencyjną `loadRecusive`, która załaduje meshe z danego węzła, doda je do vectora `armContexts`, następnie wywoła się dla wszystkich jego synów. Napisz taką funkcję i wyświetl wszystkie obiekty z vectora z macierzą modelu ustawioną na identyczność.
|
|
||||||
Otrzymaliśmy na obiekty, ale są one wyświetlane jeden na drugim, ponieważ nie wczytaliśmy macierzy opisujących ich położenie. Rozwiążemy to w następnym etapie
|
|
||||||
# 3 Graf Sceny
|
|
||||||
Każdy węzeł zawiera atrybut `mTransformation`, który jest macierzą transformacji względem ojca. By na jej podstawie uzyskać macierz modelu zbudujemy prosty graf sceny. Użyjemy do tego vektora. W `RenderUtils.h` znajduje się struktura `Node`, która zawiera:
|
|
||||||
* `vector<RenderContext>`, w którym będziemy umieszczać dane jego meshy,
|
|
||||||
* macierz modelu
|
|
||||||
* `int parent`, który będzie zawierał indeks modelu lub -1 jeżeli jest korzeniem.
|
|
||||||
|
|
||||||
Przerób funkcję `loadRecusive`. Dodaj argument parent, w którym będziemy przesyłać rekurencyjnie indeks ojca. Zmodyfikuj tak, żeby każde wywołanie dodawało element do `vector<Node> arm` i uzupełniał go o meshe, indeks ojca i macierz transformacji. `node->mTransformation` ma typ `aiMatrix4x4`, musisz ją konwertować za pomocą `Core::mat4_cast`.
|
|
||||||
|
|
||||||
Do wyświetlenia wykorzystaj poniższy kod
|
|
||||||
```C++
|
|
||||||
|
|
||||||
for (auto part : arm) {
|
|
||||||
glm::mat4 transformation=part.matrix;
|
|
||||||
int parent = part.parent;
|
|
||||||
while (parent != -1) {
|
|
||||||
transformation = arm[parent].matrix * transformation;
|
|
||||||
parent = arm[parent].parent;
|
|
||||||
}
|
|
||||||
for (auto context : part.renderContexts) drawObject(program, context, transformation, glm::vec3(0.6f));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
# 4 Animacja
|
|
||||||
|
|
||||||
Dodamy ruch ramienia na klawisze **o** i **p**. By ramie się obracało zgodnie z intuicją wystarczy, że dodamy rotację do kuli (*Ball*) a graf sceny załatwi resztę. Po pierwsze potrzebujemy znać pozycję kuli w vectorze. Dodaj do `loadRecusive` sprawdzenie czy nazwa (znajduje się w `node->mName`) to `aiString("Ball")`, jeżeli tak, przypisz do zmiennej globalnej ballIndex indeks węzła w vectorze `arm`. Pozostaje dodać obsługę przycisków w funkcji `keyboard`. By wykonać obrót przemnóż od prawej macierz kuli o macierz obrotu o mały kąt. Możesz też wykorzystać wejście myszki i obroty za pomocą kwaternionów z najnowszych ćwiczeń
|
|
||||||
|
|
||||||
# linki
|
|
||||||
* https://assimp-docs.readthedocs.io/ dokumentacja assimp
|
|
||||||
* https://learnopengl.com/Model-Loading/Assimp tutorial w learnopengl
|
|
||||||
* https://www.blender.org/download/ blender
|
|
||||||
|
|
||||||
## modele 3d
|
|
||||||
* https://www.blendswap.com
|
|
||||||
* https://sketchfab.com
|
|
||||||
* https://www.cgtrader.com/
|
|
||||||
* https://www.turbosquid.com/
|
|
||||||
* https://open3dmodel.com/
|
|
Loading…
Reference in New Issue
Block a user