In [1]:
from IPython.core.display import HTML
from string import Template
def jsConfig():
    src = """
    <script>require.config({ baseUrl: 'https://rawgit.com/kompgraf/course-material/master/assets/' });</script>
    """
    return HTML(src)
def addScript(script, identifier):
    src = Template("""
    <div id="${identifier}-container"></div>
    <script>require(['${script}'], main => main($$("#${identifier}-container"), '${identifier}'));</script>
    """)
    return HTML(src.substitute(script = script, identifier = identifier))
jsConfig()


Out[1]:

Bézier-felület

Áttekintés

A feladat egy bikubikus Bézier-felület kirajzolására képes program elkészítése, mely a felület megjelenítése mellett a kontrollpontok áthelyezését biztosítja. A felület pontjait a gyakorlaton megismert képlet segítségével kell kiszámolni.

Elvárt jellemzők

Általános elvárások

A házi feladat megvédése csak akkor lehet sikeres, ha a program a jellemzőit tekintve hiánytalan. Az elvárt jellemzőket teljesítő program

  • megjeleníti a kontrollpontokat,
  • megjeleníti a kontrollhálót,
  • a már elhelyezett kontrollpontok mozgatását lehetővé teszi,
  • által kirajzolt felület valós időben követi a kontrollpontok mozgását,
  • a felület pontjainak kiszámításához a gyakorlaton megismert képletet használja,
  • lehetőséget biztosít a felület körbejárására egy hengeren mozgó kamera segítségével,
  • a felületet láthatóság szerint helyesen rajzolja ki,
  • a felületet alkotó háromszögeket felváltva különböző színnel rajzolja ki,
  • a megfelelő transzformációkat alkalmazza.

A kontrollpontok elhelyezése

A kontrollhálót alkotó $16$ pontot nem a felhasználónak kell elhelyeznie, hanem a program elindításakor megjelenik a szükséges számú kontrollpont és velük együtt a felület is. A kontrollpontok kezdeti elhelyezkedése tetszőleges.

A kontrollpontok mozgatása

A már elhelyezett kontrollpontok koordinátáinak módosítása tetszőleges módszerrel megvalósítható. A kattintás helyén található kontrollpont azonosítása a legegyszerűbben úgy történhet, hogy a kontrollpontok mindegyikét beszorozzuk a transzformációs mátrixszal, és az így kapott pontokat már kétdimenzióban hasonlítjuk a kattintás helyéhez.

Egymást fedő pontok esetén lehet csak nemdeterminisztikus az így kapott pont kiválasztása. Ezt úgy előzhetjük meg, hogy még háromdimenzióban a festő algoritmus alkalmazásával rendezzük a pontokat.

Transzformációk és láthatóság

A megjelenítéshez a Bevezetés a számítógépi grafikába tárgy keretein belül megismert technikákat kell alkalmazni. Szükséges

  • Window to Viewport transzformáció,
  • hengeren mozgó kamera,
  • centrális vetítés,
  • festő algoritmus

használata. Fontos, hogy az úgynevezett hátsó lapokat nem kell eldobni!

A kamera, a láthatóság és a transzformációs lánc megvalósítását a következő kiírásban szereplő módon tegyük:

https://arato.inf.unideb.hu/kunkli.roland/hf6.pdf

A kontrollhálót és a kontrollpontokat nem szükséges láthatóság szerint helyesen megjeleníteni.

Színek

A felület elülső és hátulsó lapjait különböző színekkel jelenítsük meg. Ezen felül ahhoz, hogy a felület jól kivehető legyen, a háromszögeket felváltva, különböző színnel rajzoljuk ki. Tehát összesen négy különböző színt kell használnunk, kettőt az elülső, kettőt a hátulsó lapokhoz.

Törekedjünk harmonizáló színkombinációk használatára. Kiindulásként válogathatunk a következő linken találhatóak közül:

https://color.adobe.com/explore/?filter=most-popular&time=all

A felületpontok számításának módja

Legyen adott $16$ darab kontrollpont:

$$ Q_{ij} \qquad i,j = 0,1,2,3 $$

Ezek alkotják a kontrollhálót. A felületet alkotó pontokat a következő függvény segítségével számolhatjuk

$$ S(s, t) = \sum_{j = 0}^{3}\sum_{i = 0}^{3}Q_{ij}b_i(s)b_j(t) \qquad s, t \in [0, 1], $$

ahol $b_j$ és $b_i$ a harmadfokú Bézier-bázisfüggvények, melyek a következőképpen adottak:

$$ \begin{align*} b_0(t) &= -t^3 + 3t^2 - 3t + 1 \\ b_1(t) &= 3t^3 -6t^2 + 3t \\ b_2(t) &= -3t^3 + 3t^2 \\ b_3(t) &= t^3 \end{align*} $$

A felület háromszögelése

A felület pontjait az előzőleg definiált $S(s, t)$ függvényt alkalmazva fogjuk számolni. Mind az $s$, mind a $t$ paramétert a $[0, 1]$ tartományon kell végigfuttatni. Azonban $s$ minden egyes értéke esetén a $t$ paramétert újra végig kell vinni az egész $[0, 1]$ tartományon. Tehát minden rögzített $s$ érték esetén $t$ végigfut a teljes $[0, 1]$ tartományon. Ez praktikusan egy duplaciklus segítségével implementálható.

Ezzel még csak meghatároztunk néhány, a felületen fekvő pontot; ezekből még azonban háromszögeket kell képezni. Jelölje $\Delta$ mind $s$, mind $t$ irányában a növekményt, mellyel a ciklusokat léptetjük. Vegyünk egy rögzített $s$ és $t$ értéket. Ekkor egy-egy háromszöget a következő $s$ és $t$ értékek által meghatározott felületpontok fognak alkotni:

$$ (s, t), (s, t + \Delta), (s + \Delta, t + \Delta) $$

és

$$ (s, t), (s + \Delta, t + \Delta), (s + \Delta, t) $$

Figyeljünk arra, hogy a háromszögek csúcsai konzisztensen, az óramutató járásával ellentétesen legyenek felsorolva!

Demonstráció

A demonstráció egy bikubikus Bézier-felületet jelenít meg. Ha rákattintunk a kék téglalapra, akkor az megkapja a fókuszt, és el tudja kapni a billentyűeseményeket. A kamera mozgatását a következő billentyűkkel vezérelhetjük:

  • W - a kamera mozgatása fölfele a henger palástján,
  • S - a kamera mozgatása lefele a henger palástján,
  • D - a kamera mozgatása jobbra a henger palástján,
  • A - a kamera mozgatása balra a henger palástján,
  • Numpad+ - a henger sugarának növelése (ha nincs kijelölt kontrollpont),
  • Numpad- - a henger sugarának csökkentése (ha nincs kijelölt kontrollpont).

Kattintással tudunk kontrollpontot kijelölni. Az éppen kijelölt kontrollpont zöld színnel lesz kirajzolva. Ha üres területre kattintunk, akkor eltűnik a kijelölés. Amennyiben van kiválasztott kontrollpont, akkor az X, Y és Z billentyűkkel tudjuk kijelölni a tengelyt, amelynek mentén mozgatni szeretnénk a pontot, és a Numpad+, Numpad- billentyűk használatával tudjuk a kontrollpontot a kijelölt tengely mentén elmozgatni.


In [3]:
addScript("js/bezier-surface-homework", "bezier-surface-homework")


Out[3]:

In [2]:
def styling():
    styles = open("../../styles/custom.html", "r").read()
    return HTML(styles)
styling()


Out[2]: