GRK/cw 7/zadanie_2_eng.html

159 lines
14 KiB
HTML
Raw Normal View History

2022-01-12 16:07:16 +01:00
<!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_2_eng</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 */
</style>
<link rel="stylesheet" href="style.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
<!--[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="quaternion-interpolation">Quaternion interpolation</h1>
<p>Goal of this exercise is to practice implement the interpolation of rotations using quaternions.</p>
<h2 id="description-of-main-project-file">Description of main project file</h2>
<p>After attaching <code>main10_2</code> to the project it renders a futuristic city with flying cars. The flying cars start from at a skyscraper and fly around in the city. If drawing is too demanding for your computer, then in the function <code>initModels</code> replace city model with a less complex one, lowering multisampling values should also help (ine <code>glutSetOption(GLUT_MULTISAMPLE, 4);</code>). The Assimp library with simple material implementation is used for fbx object loading.</p>
<p>Cars move on a curve created by <code>keyPoints</code> interpolation with the Catmull-Rom spline. They dont have changes of orientations defined, your task is to compute their rotations in time.</p>
<p>For easier debugging following features were implemented for camera:</p>
<ul>
<li>quaternion rotation<br />
</li>
<li>buttons <strong>q</strong> and <strong>e</strong> move camera to next/previous control point</li>
<li>button <strong>0</strong> moves to the first control point</li>
<li>button <strong>1</strong> pins camera to the car.</li>
</ul>
<p>Most work will be done in the function <code>animationMatrix</code>. It contains a variable <code>speed</code>, that can be useful for debugging.</p>
<h2 id="direction-computation">Direction computation</h2>
<p>First we need to calculate quaternions that are responsible for the ship rotation between consecutive control points. We want the ship to be rotated in the direction of the next control point. For this we need to acquire the normalized direction vector for every two sequential control points as in the picture bellow.</p>
<p><img src="vectors.jpg" alt="wektory" /> Next you have to compute the quaternion that describes the starting rotation (it is (0,0,1)) and defined by a direction vector. To calculate the rotation between one vector and another one, calculate the axis of rotation, using the cross product, and angle of rotation, using the dot product. It might be tempting to calculate rotations between starting direction and all the direction vectors, but this can lead to undesired behavior like spinning. Thus it is better to calculate rotation between consecutive vectors and acumulate those rotations.</p>
<h3 id="task">Task</h3>
<p>Fill in the missing code in function <code>initKeyRoation</code> so that it will provide <code>std::vector&lt;glm::quat&gt; keyRotation</code> with the correct quaternions.</p>
<ol type="1">
<li>Initialize variable <code>glm::vec3 oldDirection</code> with vector (0,0,1), which is the initial direction.</li>
<li>Initialize variable <code>glm::quat oldRotationCamera</code> with identity rotation (1,0,0,0).</li>
<li>iterate from 0 to keyPoints-1 with i as index:
<ol type="1">
<li>Calculate new direction: subtract starting point: <code>keyPoints[i]</code> from ending point: <code>keyPoints[i+1]</code>.</li>
<li>Calculate new rotation, use function <code>glm::rotationCamera</code> multiply results with <code>oldRotationCamera</code> from right and normalize.</li>
<li>add this new rotation to <code>keyRotation</code> vector.</li>
<li>Overwrite <code>oldRotationCamera</code> with new rotation and <code>oldDritection</code> with new direction.</li>
</ol></li>
<li>After the loop there is one less quaternion than control points add one more with values (1,0,0,0).</li>
</ol>
<h2 id="interpolation">Interpolation</h2>
<p>For interpolation we will use the function <code>slerp</code> described by equation</p>
<p><span class="math display">\[ slerp(\hat{q_i},\hat{q}_{i+1},t) = \frac{\sin(\phi(1-t))}{\sin(\phi)}\hat{q_i}+\frac{\sin(\phi t)}{\sin(\phi)}\hat{q}_{i+1}\]</span></p>
<p>where <span class="math inline">\(\hat{q_i},\hat{q}_{i+1}\)</span> are interpolated quaternions, <span class="math inline">\(t\)</span> is parameter from 0 to 1 and <span class="math inline">\(\phi\)</span> can be acquired from equation: <span class="math inline">\(cos\phi = q_xr_x+q_yr_y+q_zr_z+q_wr_w\)</span>. dla <span class="math inline">\(t\in\left[0,1\right]\)</span> <code>slerp</code> calculates closest path from quaternions p and q in space of unitary quaternions. You dont have to calculate it manually, instead use function <code>glm::slerp</code>.</p>
<h3 id="task-1">Task</h3>
<p>In function <code>animationMatrix</code> add quaternion interpolation.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>glm::mat4 animationMatrix(<span class="dt">float</span> time) {</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> ...</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="co">//index of first keyPoint</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> index = <span class="dv">0</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> (distances[index] &lt;= time) {</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> time = time - distances[index];</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> index += <span class="dv">1</span>;</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> }</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="co">//t coefitient between 0 and 1 for interpolation</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">float</span> t = time / distances[index];</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> ...</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="co">//implement corect animation</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">auto</span> animationRotation = glm::quat(<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>,<span class="dv">0</span>);</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> glm::mat4 result = glm::translate(pos) * glm::mat4_cast(animationRotation);</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> result;</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Acquire from <code>keyRotation</code> quaternions of index equal to <code>index</code> and <code>index+1</code> call <code>glm::slerp</code> with them as arguments. Third parameter is supposed to be value <code>t</code>.</p>
<blockquote>
<p>While acquiring values from <code>keyRotation</code> remember not to get outside of its scope. One idea is to clamp with 0 and size of vector.</p>
</blockquote>
<p>The resulting animation would be continuous but not smooth at control points. It happens because the function is not smooth with <code>t</code> equal to 0 and 1. To mitigate this effect we will use function <code>glm::squat</code>.</p>
<p>Squat function similarly like Catmull-Rom takes 4 values but instead taking four consecutive vectors, it takes two consecutive quaternions and two intermediate quaternions. It is described by the equation:</p>
<p><span class="math display">\[squad(\hat{q}_{i},\hat{q}_{i+1},\hat{a}_{i},\hat{a}_{i+1},t)=slerp(slerp(\hat{q}_{i},\hat{q}_{i+1},t),slerp(\hat{a}_{i},\hat{a}_{i+1},t),2t(1-t))\]</span></p>
<p>where <span class="math inline">\(\hat{q}_{i},\hat{q}_{i+1}\)</span> are interpolated quaternions, <span class="math inline">\(t\)</span> is parameter from 0 to 1 and <span class="math inline">\(\hat{a}_{i},\hat{a}_{i+1}\)</span> are described by equation:</p>
<p><span class="math display">\[\hat{a}_i = \hat{q}_i\exp\left[-\frac{\log(\hat{q}_i^{-1}\hat{q}_{i-1})+\log(\hat{q}_i^{-1}\hat{q}_{i+1})}{4}\right].\]</span></p>
<h3 id="task-2">Task</h3>
<p>Change <code>slerp</code> interpolation to <code>squat</code> interpolation. First acquire <span class="math inline">\(\hat{q}_{i-1}\)</span>, <span class="math inline">\(\hat{q}_{i}\)</span>, <span class="math inline">\(\hat{q}_{i+2}\)</span>, <span class="math inline">\(\hat{q}_{i+2}\)</span> from <code>keyRotation</code> (<span class="math inline">\(i\)</span> refers to <code>index</code> as before), calculate <span class="math inline">\(\hat{a}_i\)</span>, <span class="math inline">\(\hat{a}_{i+1}\)</span>, functions <code>glm::inverse</code>, <code>glm::exp</code>, <code>glm::log</code> will be useful. finally replace <code>slerp</code> to <code>squat</code>.</p>
<p>Now transitions between rotations should be smooth. One remaining problem is to fix landing of the flying cars. Set manually the last few quaternions in such a way that the ship appears to land horizontally.</p>
</body>
</html>