rotate.html 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]--><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="Asciidoctor 1.5.4"><title>3-D Rotation</title><link rel="stylesheet" href="./twemoji-awesome.css">
  2. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css">
  3. <link rel="stylesheet" href="./coderay-asciidoctor.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css"><link rel="stylesheet" href="/home/travis/build/jMonkeyEngine/wiki/build/asciidoc/html5/jme3/twemoji-awesome.css"></head><body class="article toc2 toc-left"><div id="header"><div id="toolbar"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/src/docs/asciidoc/jme3/rotate.adoc"><i class="fa fa-pencil-square" aria-hidden="true"></i></a><a href="https://github.com/jMonkeyEngine/wiki/new/master/src/docs/asciidoc/jme3/"><i class="fa fa-plus-square" aria-hidden="true"></i></a><input dir="auto" style="position: relative; vertical-align: top;" spellcheck="false" autocomplete="off" class="searchbox__input aa-input" id="doc-search" name="search" placeholder="Search in the doc" required="required" type="search"></div><h1>3-D Rotation</h1><div class="details"><span class="author" id="author"></span><br><span id="revnumber">version ,</span> <span id="revdate">2016/03/17 20:48</span></div><div id="toc" class="toc2"><div id="toctitle">Table of Contents</div><ul class="sectlevel1"><li><a href="#using-quaternions-for-rotation">Using Quaternions for Rotation</a></li><li><a href="#code-sample">Code Sample</a></li><li><a href="#interpolating-rotations">Interpolating Rotations</a></li><li><a href="#adding-rotations">Adding Rotations</a></li><li><a href="#troubleshooting-rotations">Troubleshooting Rotations</a></li><li><a href="#tip-matrix">Tip: Matrix</a></li></ul></div></div><div id="content"><div id="preamble"><div class="sectionbody"><div class="paragraph"><p><em>Bad news: 3D rotation is done using matrix calculus.<br>
  4. Good news: If you do not understand calculus, there are two simple rules how you get it right.</em></p></div>
  5. <div class="paragraph"><p><strong>3D rotation</strong> is a crazy mathematical operation where you need to multiply all vertices in your object by four floating point numbers; the multiplication is referred to as concatenation, the array of four numbers {x,y,z,w} is referred to as <a href="../jme3/quaternion.html">quaternion</a>. Don&#8217;t worry, the 3D engine does the tough work for you. All you need to know is:</p></div>
  6. <div class="paragraph"><p><strong>The Quaternion</strong> is an object capable of deep-freezing and storing a rotation that you can apply to a 3D object.</p></div></div></div>
  7. <div class="sect1"><h2 id="using-quaternions-for-rotation">Using Quaternions for Rotation</h2><div class="sectionbody"><div class="paragraph"><p>To store a rotation in a Quaternion, you must specify two things: The angle and the axis of the rotation.</p></div>
  8. <div class="ulist"><ul><li><p>The rotation angle is defined as a multiple of the number PI.</p></li><li><p>The rotation axis is defined by a vector: Think of them in terms of &#8220;pitch&#8221;, &#8220;yaw&#8221;, and &#8220;roll&#8221;.</p></li></ul></div>
  9. <div class="paragraph"><p>Example:</p></div>
  10. <div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">/* This quaternion stores a 180 degree rolling rotation */</span>
  11. Quaternion roll180 = <span class="keyword">new</span> Quaternion();
  12. roll180.fromAngleAxis( FastMath.PI , <span class="keyword">new</span> Vector3f(<span class="integer">0</span>,<span class="integer">0</span>,<span class="integer">1</span>) );
  13. <span class="comment">/* The rotation is applied: The object rolls by 180 degrees. */</span>
  14. thingamajig.setLocalRotation( roll180 );</code></pre></div></div>
  15. <div class="paragraph"><p>So how to choose the right numbers for the Quaternion parameters? I&#8217;ll give you my cheat-sheet:</p></div>
  16. <table class="tableblock frame-all grid-all spread"><colgroup><col style="width: 33.3333%;"><col style="width: 33.3333%;"><col style="width: 33.3334%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top"><strong>Rotation around Axis?</strong></th><th class="tableblock halign-left valign-top"><strong>Use this Axis Vector!</strong></th><th class="tableblock halign-left valign-top"><strong>Examples for this kind of rotation</strong></th></tr></thead><tbody><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>X axis</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>(1,0,0)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>A plane pitches. Nodding your head.</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Y axis</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>(0,1,0)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>A plane yaws. A vehicle turns. Shaking your head.</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>Z axis</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>(0,0,1)</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>A plane rolls or banks. Cocking your head.</p></div></div></td></tr></tbody></table>
  17. <div class="admonitionblock note"><table><tr><td class="icon"><i class="fa icon-note" title="Note"></i></td><td class="content"><div class="paragraph"><p>These are the three most common examples – technically you can rotate around any axis expressed by a vector.</p></div></td></tr></table></div>
  18. <table class="tableblock frame-all grid-all spread"><colgroup><col style="width: 33.3333%;"><col style="width: 33.3333%;"><col style="width: 33.3334%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top"><strong>Angle?</strong></th><th class="tableblock halign-left valign-top"><strong>Use Radians!</strong></th><th class="tableblock halign-left valign-top"><strong>Examples</strong></th></tr></thead><tbody><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>45 degrees</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>FastMath.PI / 4</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>eighth of a circle</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>90 degrees</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>FastMath.PI / 2</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>quarter circle, 3 o&#8217;clock</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>180 degrees</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>FastMath.PI</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>half circle, 6 o&#8217;clock</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>270 degrees</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>FastMath.PI * 3 / 2</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>three quarter circle, 9 o&#8217;clock</p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>360 degrees</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>FastMath.PI * 2</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>full circle, 12 o&#8217;clock <i class="twa twa-wink"></i></p></div></div></td></tr><tr><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p><code>g</code> degrees</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>FastMath.PI * g / 180</p></div></div></td><td class="tableblock halign-left valign-top"><div><div class="paragraph"><p>any angle <code>g</code></p></div></div></td></tr></tbody></table>
  19. <div class="admonitionblock important"><table><tr><td class="icon"><i class="fa icon-important" title="Important"></i></td><td class="content"><div class="paragraph"><p>You must specify angles in <a href="http://en.wikipedia.org/wiki/Radian">Radian</a>s (multiples or fractions of PI). If you use degrees, you will just get useless results.</p></div></td></tr></table></div>
  20. <div class="paragraph"><p>How to use these tables to speficy a certain rotation:</p></div>
  21. <div class="olist arabic"><ol class="arabic"><li><p>Pick the appropriate vector from the axis table.</p></li><li><p>Pick the appropriate radians value from the angle table.</p></li><li><p>Create a Quaternion to store this rotation. <code>… fromAngleAxis( radians , vector )</code></p></li><li><p>Apply the Quaternion to a node to rotate it. <code>… setLocalRotation(…)</code></p></li></ol></div>
  22. <div class="paragraph"><p>Quaternion objects can be used as often as you want, so give them meaningfull names, like <code>roll90, pitch45, yaw180</code>.</p></div>
  23. <div class="paragraph"><p><a href="http://moddb.wikia.com/wiki/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation">More about Quaternions</a>…</p></div></div></div>
  24. <div class="sect1"><h2 id="code-sample">Code Sample</h2><div class="sectionbody"><div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">/* We start out with a horizontal object */</span>
  25. Cylinder cylinder = <span class="keyword">new</span> Cylinder(<span class="string"><span class="delimiter">&quot;</span><span class="content">post</span><span class="delimiter">&quot;</span></span>, <span class="integer">10</span>, <span class="integer">10</span>, <span class="integer">1</span>, <span class="integer">10</span>);
  26. cylinder.setModelBound(<span class="keyword">new</span> BoundingBox());
  27. <span class="comment">/* Create a 90-degree-pitch Quaternion. */</span>
  28. Quaternion pitch90 = <span class="keyword">new</span> Quaternion();
  29. pitch90.fromAngleAxis(FastMath.PI/<span class="integer">2</span>, <span class="keyword">new</span> Vector3f(<span class="integer">1</span>,<span class="integer">0</span>,<span class="integer">0</span>));
  30. <span class="comment">/* Apply the rotation to the object */</span>
  31. cylinder.setLocalRotation(pitch90);
  32. <span class="comment">/* Update the model. Now it's vertical. */</span>
  33. cylinder.updateModelBound();
  34. cylinder.updateGeometry();</code></pre></div></div></div></div>
  35. <div class="sect1"><h2 id="interpolating-rotations">Interpolating Rotations</h2><div class="sectionbody"><div class="paragraph"><p>You can specify two rotations, and then have jme calculate (interpolate) the steps between two rotations:</p></div>
  36. <div class="ulist"><ul><li><p>com.jme3.math.Quaternion, slerp() – store an interpolated step between two rotations</p><div class="ulist"><ul><li><p><a href="https://javadoc.jmonkeyengine.org/v3.3.2-stable/com/jme3/math/Quaternion.html">com.jme3.math.Quaternion</a></p></li></ul></div></li></ul></div></div></div>
  37. <div class="sect1"><h2 id="adding-rotations">Adding Rotations</h2><div class="sectionbody"><div class="paragraph"><p>You can concatenate (add) rotations: This means you turn the object first around one axis, then around the other, in one step.<br>
  38. <code>Quaternion myRotation = pitch90.mult(roll45); /* pitch and roll */</code></p></div></div></div>
  39. <div class="sect1"><h2 id="troubleshooting-rotations">Troubleshooting Rotations</h2><div class="sectionbody"><div class="paragraph"><p>Does the object end up in an unexpected location, or at an unexpected angle? If you are getting weird results, check the following:</p></div>
  40. <div class="olist arabic"><ol class="arabic"><li><p>3-D transformations are non-commutative! This means it often makes a huge difference whether you first move a node and then rotate it around an axis, or first rotate the node around an axis and then move it. Make sure you code does what you mean to do.</p></li><li><p>Are you intending to rotate around the object&#8217;s origin along an axis, or around another pivot point outside the object? If you are trying to <em>rotate an object around a pivot point</em>, you have to create an (invisible) pivot node first, and attach the object to it. Then apply the rotation to the <em>parental pivot node</em>, not to the child object itself!</p></li><li><p>Did you enter the angle in degrees (0 - 360°) or radians (0 - 2*PI)? A 3D engine expects radians, so make sure to convert your values! Formula: <code>g° = FastMath.PI * g / 180</code></p></li><li><p>Did you modify one of the pre-made constants like this?</p><div class="openblock"><div class="content"><div class="listingblock"><div class="content"><pre class="CodeRay highlight"><code data-lang="java"><span class="comment">//Never do things like this!!!</span>
  41. Quaternion.IDENTITY.fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X);</code></pre></div></div>
  42. <div class="paragraph"><p>This looks normal enough, after-all, this is a constant right? Sorta, what you are really doing is setting a value to the static final constant <code>Quaternion.IDENTITY</code>.</p></div>
  43. <div class="paragraph"><p>To quote one of the core team members.</p></div>
  44. <div class="sidebarblock"><div class="content"><div class="quoteblock"><div class="title">Do not modify the &#8220;constants&#8221;. You will have a shit-ton of really messed up errors.</div>
  45. <blockquote>You gain NOTHING by doing this, either. Just use new Quaternion().fromAngles() like a sane person.</blockquote><div class="attribution">&#8212; pspeed<br><cite>Core Team Member</cite></div></div></div></div>
  46. <div class="paragraph"><p>For a deeper explaination, see this forum thread: <a href="https://hub.jmonkeyengine.org/t/quaternion-bug/39060">Quaternion bug?</a></p></div></div></div></li></ol></div></div></div>
  47. <div class="sect1"><h2 id="tip-matrix">Tip: Matrix</h2><div class="sectionbody"><div class="paragraph"><p>This here is just about rotation, but there are three types of 3-D transformation: rotate, scale, and translate.</p></div>
  48. <div class="paragraph"><p>You can do all transformations in individual steps (and then update the objects geometry and bounds), or you can combine them and transform the object in one step. If you have a lot of repetitive movement going on in your game it&#8217;s worth learning more about <a href="../jme3/matrix.html">Matrix4f</a> for optimization. JME can also help you interpolate the steps between two fixed transformations.</p></div>
  49. <div class="ulist"><ul><li><p>com.jme3.math.Transform, interpolateTransforms() – interpolate a step between two transformations</p><div class="ulist"><ul><li><p><a href="https://javadoc.jmonkeyengine.org/v3.3.2-stable/com/jme3/math/Transform.html">com.jme.math.Transform</a></p></li></ul></div></li><li><p>In case you missed it, see also <a href="../jme3/quaternion.html">Quaternion</a>.</p></li></ul></div></div></div></div><div id="footer"><div id="footer-text">Version <br>Last updated 2020-05-21 00:29:23 +00:00</div></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script><script>docsearch({
  50. apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
  51. indexName: 'jmonkeyengine',
  52. inputSelector: '#doc-search',
  53. debug: false // Set debug to true if you want to inspect the dropdown
  54. });</script></body></html>