<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Join My Conversation &#187; Animation</title>
	<atom:link href="http://www.jmckell.com/category/animation/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jmckell.com</link>
	<description>Conversation and news topics</description>
	<lastBuildDate>Thu, 02 Sep 2010 23:53:50 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Recording Animation</title>
		<link>http://www.jmckell.com/recording-animation/</link>
		<comments>http://www.jmckell.com/recording-animation/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 01:09:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[math lingo]]></category>

		<guid isPermaLink="false">http://www.jmckell.com/?p=127</guid>
		<description><![CDATA[In recorded animation, model           variables are set from stored values. A few  uses          are recording human motion (mouse movement) and  recording          incremental  animation.  [...]]]></description>
			<content:encoded><![CDATA[<p>In recorded animation, <a href="http://www.jmckell.com/separation.html">model           variables</a> are set from <strong>stored values</strong>. A few  uses          are recording <strong>human motion</strong> (mouse movement) and  recording          <strong><a href="http://www.jmckell.com/incremental.html">incremental  animation</a></strong>.          Recording incremental animation would then let you play it back  with the          kind of control parametric animation gives. You could also get  ahold of          some <strong>motion-capture data</strong> and massage it into a  form that          can be used for playback within Director.</p>
<p>The recording of the animation may be done as <strong>part           of the program</strong>, or done <strong>beforehand</strong>. If  it is          done beforehand, the data needs to be saved, most conveniently  in a field          or text cast member, and then retrieved at run-time. For saving  lists          in text form, see the Lingo functions string() and value().</p>
<p>Playback of recorded motion is essentially a <strong><a href="http://www.jmckell.com/parametric.html">parametric           animation</a></strong>, with the parameter driving an index into  the list          of recorded values.</p>
<p><a name="demo"></a>This demo allows the user to  record          a piece of incremental animation, and then play it back with a  slider          driver. The animation is a <a href="http://www.jmckell.com/combiningforces.html">combination</a> of <a href="http://www.jmckell.com/collisionspring.html">collision</a> and <a href="http://www.jmckell.com/generalgravity.html">general           gravity</a>.</p>
<div>on  startRecording()<br />
recordList = [:]<br />
repeat with sp in          instanceList<br />
recordList[sp] = []<br />
end repeat<br />
state = #recording<br />
end</p>
<p>on record()<br />
repeat with sp in          instanceList<br />
recordList[sp].add([#x:          sp.x, #y: sp.y])<br />
end repeat<br />
end</p>
<p>on playBack(p) &#8212; p:0-&gt;1<br />
totalPos = recordList[1].count<br />
index = integer(p * (totalPos          &#8211; 1) + 1)          &#8211;index:1-&gt;totalPos<br />
repeat with sp in          instanceList<br />
pos = recordList[sp][index]<br />
sp.x = pos.x<br />
sp.y = pos.y<br />
end repeat<br />
end</p></div>
<p>Methods from script &#8220;modelManager&#8221;</p>
<p>In this demo the recording is done by a script  adapted          from the <strong>modelRate</strong> script in <a href="http://www.jmckell.com/modelrate.html">Independent           Model Rate</a>, and renamed <strong>modelManager</strong>. The  three methods          above show how it does recording and playback.</p>
<p>Notice that the variables recorded are the <strong>animation           model variables</strong>, not the sprite properties. This is  generally          the best way to go, for several reasons:</p>
<ul>
<li><strong>less information to record</strong>.  For example,            in <a href="http://www.jmckell.com/3Dcues.html">3D</a> the x, y, and z coordinates are used            to set more than three sprite properties. Of course, this  means that            during playback a rendering algorithm will still be needed.</li>
<li>more importantly, at playback you still have <strong>control             over rendering</strong>.</li>
</ul>
<p>The variables are recorded once each movie frame  in this          demo, rather than once each <a href="http://www.jmckell.com/modelrate.html">model  frame</a>.          In this demo the model rate is about 20 times the movie rate. If  you wanted          to do <strong>&#8220;super slo-mo&#8221;</strong> playback, you could record           the variables based on <strong>model frames</strong>, and at  slow playback          you&#8217;ll get a smoother motion.</p>
<p>To record the <strong>movement of the mouse</strong>,  use          a script that keeps its x and y animation model variables at the  mouse          location, and pass the script instance to modelManager&#8217;s  addInstance()          method.</p>
<p>Miscellaneous Points<br />
<em><strong>recordList</strong></em><br />
This is the property list used by modelManager to record the x  and y variables          of each recorded object. The unusual thing about it is that the <strong>keys</strong> in the list are <strong>object references</strong>. recordList  associates          each object reference with the linear list of recorded position  settings          for that object.</p>
<p>Usually in sample code the keys are symbols, but  the property          list can be used to <strong>associate values of any data type  with each          other</strong>. This is generally called a <strong>hash table</strong>,           and most likely property lists are implemented in Director using  a hash          table of some sort.</p>
<p>If recordList is saved in a text cast member,  retrieving          the list using value() will not recreate object references. To  save recordList,          use something like sprite numbers for the keys instead of  references.</p>
<p><strong><em>Animation Anomalies</em></strong><br />
If you watch the animation long enough you&#8217;ll notice some  interesting          anomalies in the behavior of the objects. When I have time I&#8217;ll  try to          pinpoint what is happening. There may or may not be a perfect  fix.</p>
<p>Things To Try<br />
Make the playback &#8220;instant replay&#8221; style by using a <a href="http://www.jmckell.com/drivingp.html">time           driver</a> instead of a slider to control the playback. You  might use          a slider to control the speed of the replay.</p>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=127&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/recording-animation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Collision Using Spring Force</title>
		<link>http://www.jmckell.com/collision-using-spring-force-2/</link>
		<comments>http://www.jmckell.com/collision-using-spring-force-2/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 18:49:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[Lingo]]></category>
		<category><![CDATA[collision spring force]]></category>

		<guid isPermaLink="false">http://www.heathersych.com/?p=91</guid>
		<description><![CDATA[Collision Using Spring Force
When two objects rebound after colliding with each other,          it is due to a spring force, even though it may not look          like it. When two billiard balls collide, the compression of the ball [...]]]></description>
			<content:encoded><![CDATA[<p>Collision Using Spring Force</p>
<p>When two objects rebound after colliding with each other,          it is due to a <strong>spring force</strong>, even though it may not look          like it. When two billiard balls collide, the compression of the ball          is limited to a miniscule fraction of its width but it still happens.</p>
<p>Using a spring force requires <strong>higher model rates</strong> to realistically collide faster, harder objects. The <strong>fps</strong> display in the demo shows the <strong>actual frame rate</strong>. The          <a name="demo"></a> movie itself is set to 999 fps. On a 1.3 GHz P3 it          averages about 980 actual fps.</p>
<p><span>repeat with </span>s = <span>1</span> <span>to</span> <span>4</span><br />
<span>if</span> s &lt;&gt; <span>me</span>.spritenum          <span>then</span><br />
spOther = <span>sprite</span>(s)</p>
<p><span>&#8211;distance components</span><br />
distX = (spOther.x) &#8211; x<br />
distY = (spOther.y) &#8211; y</p>
<p><span>&#8211;pythagorean theorem          to get distance</span><br />
dist = <span>sqrt</span>(<span>power</span>(distX,<span>2</span>)          + <span>power</span>(distY,<span>2</span>))</p>
<p><span>&#8211;spring force</span><br />
xSpring = <span>0</span><br />
ySpring = <span>0</span><br />
minDist = (sp.<span>width</span> + spOther.<span>width</span>) / <span>2.0</span> -<span> 10</span><br />
<span>if</span> dist &lt;          minDist <span>then</span><br />
springF = (minDist &#8211; dist) * <span>.02</span><br />
xSpring = springF * -(distX/dist)<br />
ySpring = springF * -(distY/dist)<br />
<span>end if</span></p>
<p>xTotalForce = xTotalForce + xSpring<br />
yTotalForce = yTotalForce + ySpring<br />
<span> end if<br />
end repeat </span></p>
<p>The algorithm is <strong>almost identical to <a href="http://www.jmckell.com/generalgravity.html#demo2">general          gravity</a></strong>, so only the repeat loop is shown. Instead of calculating          gravity, it calculates spring force. Spring force only acts when the objects          are within a certain distance of each other, expressed as <strong>dist          &lt; minDist</strong>.</p>
<p>The magnitude of the spring force is given by <strong>minDist          &#8211; dist</strong>. This is the <strong>restPosition &#8211; position </strong>equation          from the <a href="http://www.jmckell.com/springforces.html">Spring Forces</a> section. <strong>Scaling          by .02</strong> puts the force into proportion with other values in the          animation. It can be considered the <strong>stiffness of the object</strong>,          the higher it is the stiffer the object.</p>
<p>This demo gives each object a <strong><a href="http://www.jmckell.com/mass.html">mass</a></strong>,          and uses the mass in the<br />
<strong>accel = force / mass</strong> equation. The behavior of the large          object shows how mass affects acceleration. When two objects collide,          each experiences the same amount of force, acting in opposite directions.          This force translates into a <strong>smaller acceleration for more massive          objects</strong>.</p>
<p>Mass can be set however you&#8217;d like. In this demo it is          set to the cube of the sprite width, which would roughly correspond to          its mass if it was a<br />
3-dimensional sphere.</p>
<p>The type of collision modelled in this demo is for <strong>round          objects with no friction</strong> between them. Friction or non-round          shape would cause part of the energy in the collision to go into rotational          velocity, making the objects spin.</p>
<p>For comments on the rest of the script, see <a href="http://www.jmckell.com/generalgravity.html">General                Gravity</a>.</p>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=91&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/collision-using-spring-force-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Data Structures and Recursion</title>
		<link>http://www.jmckell.com/data-structures-and-recursion/</link>
		<comments>http://www.jmckell.com/data-structures-and-recursion/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 01:12:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[Blogging]]></category>
		<category><![CDATA[restrucutre data]]></category>

		<guid isPermaLink="false">http://www.jmckell.com/?p=129</guid>
		<description><![CDATA[Intro
Trees
Intro
Data structures store data in a way that reflects some  relationship between          the data, and is easily useable in a program. Lingo provides  some built-in          data structures such as lists. This section  describes  [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jmckell.com">Intro</a></p>
<p><a href="http://www.jmckell.com/">Trees</a><a name="intro"></a></p>
<p>Intro<br />
Data structures store data in a way that reflects some  relationship between          the data, and is easily useable in a program. Lingo provides  some built-in          data structures such as <strong>lists</strong>. This section  describes          how data structures are created using <strong>objects</strong>,  and some          of their <strong>common uses in animation</strong>. Make sure  you&#8217;re familiar          with the material in <a href="http://www.jmckell.com/OOfun.html">Object-Oriented  Fundamentals</a>.</p>
<p>The two types of structures covered here are <strong>lists           and trees</strong>, which are both very common and useful. Lingo  provides          an implementation of lists already; this section shows how to  make lists          using objects as an intro to making trees.</p>
<p>Uses for lists are fairly obvious. Some uses for  trees:</p>
<ul>
<li><a href="http://www.jmckell.com/3Dworld.html"><strong>3D  world hierarchy</strong></a></li>
<li>working with <strong>XML, HTML</strong>, etc,  which            are hierarchical document formats</li>
<li>hierarchical displays (such as a file system  display)</li>
<li>decision trees</li>
<li>and many others<a name="terminology"></a></li>
</ul>
<p>Terminology<br />
An object data structure is made of objects  that are          created from the <strong>same script (class)</strong>. When  these objects          are assembled into a data structure they are often called <strong>nodes</strong> of the data structure.</p>
<p>Each node will have properties that are <strong>references           to other nodes</strong>. These object references are what bind  the data          structure together and are called <strong>pointers</strong>. How  the nodes          are arranged using these pointers determines the type of data  structure          created.</p>
<p>In the diagrams of this section, a <strong>square  represents          a node</strong> and an <strong>arrow represents a pointer</strong>.  <a name="lists"></a></p>
<p>Lists<br />
A list is a <strong>sequence of nodes</strong>. Each node has a  pointer          to the next node in the list. The nodes in this diagram are  created from          a script called &#8220;listNode&#8221;.</p>
<p><img src="http://www.jmckell.com/images/datastruct1.gif" alt="" width="489" height="96" /></p>
<p>To <strong>store data in a list</strong>,           each node has a property or properties that store the data.</p>
<p>The script shown below can be used  for the          nodes of a list data structure. It has methods for <strong>adding  a node</strong> to the end of the list, and for <strong>getting a node</strong> at a given          position. The property key stores  some          type of data.</p>
<div>property  nextNode<br />
property key</p>
<p>on new(me,          _key)<br />
key = _key<br />
return me<br />
end</p>
<p>on addNode(me, _key)<br />
if nextNode = void          then<br />
nextNode = script(&#8220;listNode&#8221;).new(_key)<br />
else<br />
nextNode.addNode(_key)<br />
end if<br />
end</p>
<p>on getNodeAt(me, index)<br />
if index = 1 then          return me<br />
if nextNode = void          then return void           &#8211;index out of range<br />
return  nextNode.getNodeAt(index          &#8211; 1)<br />
end if</p>
</div>
<p><strong>script &#8220;listNode&#8221;</strong> <a name="recursion"></a></p>
<p>Recursion<br />
It might appear strange that the addNode() and getNodeAt()  methods in          the listNode script actually <strong>call themselves</strong>.  This programming          technique is known as <strong>recursion</strong>, and is  essential for          making efficient use of lists and trees.</p>
<p>To understand what is happening, <strong>trace  the execution</strong> from when the method is called on the first node in the list.  Each time          the method calls itself it moves one node down the list, which  is called          <strong>&#8220;traversing&#8221;</strong> the list. Eventually, the  execution          reaches what is called a <strong>base case</strong> at which  point there          are no further recursive method calls.</p>
<p>In the <strong>addNode()</strong> method the base  case          is <strong>nextNode = void</strong>, which means the end of the  list has          been reached and the new node can be added.</p>
<p>In the <strong>getNodeAt()</strong> method there  are two          base cases. Either the desired node is reached (index = 1) or  the end          of the list is reached before finding the desired node (nextNode  = void).          When the getNodeAt() method reaches its base case, the <strong>result           is returned back through the stack of recursive method calls</strong>.</p>
<p>Recursion is useful for working with lists  because a list          is a recursive data structure. That is, a list is <strong>defined  in terms          of itself</strong>. The recursive definition of a list is: &#8220;a  list          is a node followed by a list, or void.&#8221;</p>
<p>Try writing recursive methods for the listNode  script that:</p>
<ul>
<li>delete the last node in the list</li>
<li>delete a node at a given position</li>
<li>add a node at a given position</li>
<li>return the node whose key matches a given  value</li>
<li>return the number of nodes in the list</li>
<li>return a string that contains the keys of the  nodes</li>
<li>return the sum of the keys of the nodes (if  key is numeric)</li>
</ul>
<p>Some of these methods are easier to write if each  node          also has a <strong>pointer to the previous node in the list</strong>.           Such a list is called a <strong>&#8220;double-linked&#8221; list</strong>.          A listNode script that contains the methods above can be  downloaded <a href="http://www.jmckell.com/zip/datastruct.zip">here</a>.           It doesn&#8217;t support deleting the first node in the list for the  sake of          simplicity (how would you do it? Hint: it requires a list  implementation          using two scripts).<a name="trees"></a></p>
<p>Trees<br />
A tree is also a recursive data structure. It&#8217;s similar to a  list, except          that it can have <strong>more than one &#8220;next node&#8221;</strong>.          Usually it is drawn vertically to emphasize its <strong>heirarchical  nature</strong>,          with next nodes called <strong>&#8216;children&#8217;</strong> and the  previous node          called the <strong>&#8216;parent&#8217;</strong>.</p>
<p><img src="http://www.jmckell.com/images/datastruct2.gif" alt="" width="309" height="202" /></p>
<p>The top node of the tree is usually called the<strong> &#8216;root&#8217;</strong>, and is the only node that has no parent. The  bottom nodes,          which have no children, are called <strong>&#8216;leaves&#8217;</strong>.  Following          successive parent pointers from a node will eventually reach the  root,          and the nodes on this path are the <strong>ancestors</strong> of  the node          (not to be confused with the script <em>ancestor</em> property  used for          <a href="http://www.jmckell.com/OOfun.html">inheritance</a>).</p>
<p>Each node in the tree is the root of a sub-tree. A  sub-tree          can be described as &#8220;the sub-tree rooted at this node&#8221;.</p>
<div>property  parent<br />
property child<br />
property a   &#8211;numerical</p>
<p>on new(me,          _a)<br />
child = []<br />
a = _a<br />
return me<br />
end</p>
<p>on addChild(me,          node)<br />
child.add(node)<br />
node.parent = me<br />
end</p>
<p>on addTo(me, b)<br />
a = a + b<br />
repeat with ch in          child<br />
ch.addTo(b)<br />
end repeat<br />
end</p>
<p>on sumTree()<br />
sum = a<br />
repeat with          ch in child<br />
sum = sum + ch.sumTree()<br />
end repeat<br />
return sum<br />
end</p>
</div>
<p><strong>Sample tree node script that  stores a single        number</strong></p>
<p>The script above can be used for the nodes of a  tree that          stores a single number at each node. Like the methods that  traverse the          list data structure, a recursive method can be written to <strong>traverse           and process a tree data structure</strong>. The example methods <strong>addTo() </strong>and <strong>sumTree() </strong> both traverse the tree.</p>
<p><strong>n.addTo(num)</strong> increments by num  the value          in each node in the sub-tree rooted at <strong>n</strong>. If <strong>n</strong> is the root of the tree, all nodes in the tree are incremented.</p>
<p><strong>n.sumTree()</strong> returns the sum of  the values          stored in the nodes in the sub-tree rooted at <strong>n</strong>.  If <strong>n</strong> is the root of the tree, the sum of all nodes in the tree is  returned.</p>
<p>These recursive methods visit the nodes in the  tree in          this order:</p>
<p><img src="http://www.jmckell.com/images/datastruct3.gif" alt="" width="221" height="220" /></p>
<p>This is called a &#8216;depth-first&#8217; traversal since it  travels          to the bottom of the tree first, rather than processing one  level before          going to the next.</p>
<p><a href="http://www.jmckell.com/zip/datastruct.zip">Here</a> is another tree node          script that shows some more recursive tree methods</p>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=129&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/data-structures-and-recursion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>3D Camera Movement</title>
		<link>http://www.jmckell.com/3d-camera-movement/</link>
		<comments>http://www.jmckell.com/3d-camera-movement/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 14:22:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[3d camera]]></category>
		<category><![CDATA[Blogging]]></category>
		<category><![CDATA[Camera]]></category>
		<category><![CDATA[Cartesian coordinate system]]></category>
		<category><![CDATA[Coordinate system]]></category>
		<category><![CDATA[Field of view]]></category>
		<category><![CDATA[Photography]]></category>
		<category><![CDATA[Rendering]]></category>
		<category><![CDATA[Telephoto lens]]></category>
		<category><![CDATA[Wide-angle lens]]></category>

		<guid isPermaLink="false">http://www.heathersych.com/?p=93</guid>
		<description><![CDATA[


3D Camera Movement
Click &#38; drag to arc camera
Ctrl-click &#38; vertical drag to dolly
Ctrl-click &#38; horizontal drag to zoom (field-of-view)   3D Camera Movement &#8211; 1000&#215;700  &#8211; source movieCtrl-dragging upper-left to lower-right gives that &#8220;depth          compression&#8221; effect used occasionally in cinema (Jaws, LOTR Fellowship,  [...]]]></description>
			<content:encoded><![CDATA[<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td align="left" valign="top" width="512"><!-- InstanceBeginEditable name="content" -->3D Camera Movement<a name="demo"></a></p>
<p><span>Click &amp; drag to <strong>arc</strong> camera<br />
Ctrl-click &amp; vertical drag to <strong>dolly</strong><br />
Ctrl-click &amp; horizontal drag to <strong>zoom</strong> (field-of-view) </span> <object classid="clsid:166b1bca-3f9c-11cf-8075-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0" height="300" width="512"><param name="src" value="dir/3Dcamera.dcr"><param name="swRemote" value="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' "><param name="swStretchStyle" value="none"><param name="bgColor" value="#FFFFFF"><param name="bgcolor" value="#FFFFFF"><embed type="application/x-director" src="dir/3Dcamera.dcr" bgcolor="#FFFFFF" swstretchstyle="none" swremote="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' " height="300" width="512"></embed></object> <span><strong>3D Camera Movement</strong> &#8211; <a href="http://www.jmckell.com/3DcameraFull.html">1000&#215;700 </a> &#8211; <a href="http://www.jmckell.com/zip/3Dcamera.zip">source movie</a></span>Ctrl-dragging upper-left to lower-right gives that &#8220;depth          compression&#8221; effect used occasionally in cinema (Jaws, LOTR Fellowship,          etc).</p>
<p><span>Moving the Camera</span><br />
The camera orientation is <strong>specified by a transform</strong>. The          renderer gets the camera transform from the 3Dnode that its &#8220;camNode&#8221;          property points to.</p>
<p>This 3Dnode may or may not be part of the <a href="http://www.jmckell.com/3Dworld.html">3D          world hierarchy</a>. If it is, the camera transform will be affected by          movement in the 3D world. If it isn&#8217;t, it moves independent of the 3D          world.</p>
<p>In this demo the camera is not part of the 3D world tree,          but it does have a few ancestor nodes used for arcing the camera.</p>
<p><span>Rendering from the Camera&#8217;s Point          of View</span><br />
In order to use the <a href="http://www.jmckell.com/3Dcues.html">perspective equation</a> the          3D world is transformed in rendering so that the camera sits at the origin          looking up the z axis:</p>
<p align="center"><img src="http://www.jmckell.com/images/3Dcamera.gif" alt="" height="489" width="492"></p>
<p>The key to finding the right transform to use is that when it is multiplied          by the camera transform it gives the <strong>identity transform</strong> (which positions the camera at the origin looking up the z axis).</p>
<p>Since multiplying a transform by its <strong>inverse</strong> gives the identity transform, the right transform to use is the <strong>inverse          of the camera transform</strong>.</p>
<p>In this demo the 3D world is transformed in this way by          passing the inverse of the camera&#8217;s transform as the initial parent world          transform:</p>
<div><span>on</span> <span>stepframe</span>()<br />
camInverse = camNode.getWorldTransform().<span>inverse</span>()<br />
camInvRot = camInverse.<span>duplicate</span>()<br />
camInvRot.<span>position</span> = <span>vector</span>()<br />
rendLightVec = camInvRot * lightVec<br />
traverseWorld(root, camInverse)<br />
<span>end</span></div>
<p><span><strong>stepFrame() handler of script &#8220;3Drender&#8221;</strong></span>So the camera adjustment is applied <strong>once at the          start</strong> instead of calculating world transforms for each object          then applying the camera.</p>
<p><span>Field of View</span><br />
The &#8220;field of view&#8221; is related to the distance from the focal          point to the projection plane:</p>
<p><img src="http://www.jmckell.com/images/3Dcamera2.gif" alt="" height="354" width="511"></p>
<p>In this demo the view height is the <strong>height of the          stage</strong>. For Shockwave 3D the view height is the <strong>height          of the sw3D sprite</strong>.</p>
<p>As the focal point gets closer to the projection plane,          the field of view increases and more of the 3D world is seen through the          projection plane, giving a <strong>wide-angle lens effect</strong>. When          the focal point is further away the field of view is narrow which gives          a <strong>telephoto lens effect</strong>.</p>
<p><span>Orthographic View</span><br />
In orthographic view the projections from the 3D scene are <strong>orthogonal          to the projection plane</strong> rather than converging on a focal point:</p>
<p align="center"><img src="http://www.jmckell.com/images/3DcameraOrtho.gif" alt="" height="279" width="471"></p>
<p align="left">The word &#8220;orthogonal&#8221; means perpendicular          in <em>n</em> dimensions, hence the name. In orthographic view the <strong>2D          mapping comes straight from the x and y coordinates</strong> of the 3D          model. Just remove the perspective equation from the algorithm, or set          <span>persp</span> equal to 1.</p>
<p align="left">If you remove perspective to get an orthographic          view you&#8217;ll see that<strong> back-face culling</strong> causes some of          the faces to disappear that should be visible, because it is programmed          for the<strong> view from the focal point</strong>. How would you correct          this for orthographic view? A hint: <span>vCent</span><span> is the vector from the focal point (at the origin) to the center of the          face. Find a different vector to use when calculating </span><span>dotCam</span><span>. </span></p>
<p><span>Cube Bounce</span><br />
The programming of the cube bounce is specialized for this demo so it&#8217;s          much simpler than a generalized version. Here is a brief description of          what is going on in the code.</p>
<p>The model behind it is <strong>eight masses</strong>, one          for each cube resource vertex, <strong>connected by <a href="http://www.jmckell.com/springforces.html">springs</a></strong> (<a href="http://www.jmckell.com/physicsmodel.html">physics model</a>). An <a href="http://www.jmckell.com/modelrate.html">independent          model rate</a> is used since the springs are very stiff. The vertices          that exert spring force on <strong>verts[i]</strong> are stored in<strong> spgVerts[i][]</strong>, with initial (resting) spring lengths stored in<br />
<strong>spgLength[i][]</strong>.</p>
<p>Each model frame the forces acting on each vertex combine          to give total force on the vertex. The force <strong>spgVerts[i][j]</strong> exerts on <strong>verts[i]</strong> is given by a <a href="http://www.jmckell.com/vectors.html">vector</a> found like this:</p>
<p align="center"><img src="http://www.jmckell.com/images/3Dcamera3.gif" alt="" height="268" width="282"></p>
<div><span>repeat with </span>j = <span>1</span> <span>to</span> spgVerts[i].<span>count</span><br />
vecDiff = verts[i] &#8211; spgVerts[i][j]<br />
pCompress = <span>1</span> &#8211; (vecDiff.<span>length</span>()          / spgLength[i][j])<br />
vecSpring = vecDiff.<span>getNormalized</span>()          * pCompress * stiffness<br />
vecTotSpring = vecTotSpring + vecSpring<br />
<span>end repeat</span></div>
<p><span><strong>Calculating total spring force on one vertex,        modelFrame() method of script &#8220;cubeBounce&#8221;</strong></span>The force vector is found as a percentage of the original          spring length and scaled according to the stiffness setting.</p>
<p>When a vertex moves out of bounds, it is <strong>repositioned          at the boundary edge</strong>. This <strong>compresses the springs</strong> it is &#8220;attached&#8221; to which exerts force on other vertices and          causes the cube to bounce and spin.</p>
<p>The cube bounce <strong>algorithm can be made more efficient</strong> by only calculating the force between each pair of vertices once,                rather than twice. The forces between the vertices in each pair                are <strong>opposites</strong>, so if vecF is the force on one then                -vecF is the force on the other.</td>
</tr>
</tbody>
</table>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=93&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/3d-camera-movement/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>3D Resource Objects</title>
		<link>http://www.jmckell.com/3d-resource-objects/</link>
		<comments>http://www.jmckell.com/3d-resource-objects/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 00:49:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[Blogging]]></category>
		<category><![CDATA[JMCKELL.com]]></category>

		<guid isPermaLink="false">http://www.heathersych.com/?p=95</guid>
		<description><![CDATA[3D Resource Objects
Related Topics:
3D World Hierarchy
Spring Forces
In this demo, resource geometry is separated from          the 3D hierarchy so that the same resource can be used multiple          times in the 3D world. One advantage to this is animating [...]]]></description>
			<content:encoded><![CDATA[<p>3D Resource Objects</p>
<p><strong>Related Topics:</strong><br />
<a href="http://www.jmckell.com/3Dworld.html">3D World Hierarchy</a><br />
<a href="http://www.jmckell.com/springforces.html">Spring Forces</a></p>
<p>In this demo, resource geometry is <strong>separated from          the 3D hierarchy</strong> so that the same resource can be used multiple          times in the 3D world. One advantage to this is animating the resource          will <strong>animate all appearances of it</strong>—the three discs          in the demo below all use the same disc resource.<a name="demo"></a></p>
<p><span>Drag off objects to rotate group</span><br />
<object classid="clsid:166b1bca-3f9c-11cf-8075-444553540000" width="512" height="300" codebase="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"><param name="src" value="dir/3Dresources.dcr" /><param name="swRemote" value="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' " /><param name="swStretchStyle" value="none" /><param name="bgColor" value="#FFFFFF" /><param name="bgcolor" value="#FFFFFF" /><embed type="application/x-director" width="512" height="300" src="dir/3Dresources.dcr" bgcolor="#FFFFFF" swstretchstyle="none" swremote="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' "></embed></object> <span><strong>3D Resource Objects</strong> -<a href="http://www.jmckell.com/zip/3Dresources.zip"> source movie</a></span></p>
<p>The resources in this demo are programmed as <strong><a href="http://www.jmckell.com/datastruc.html#trees">trees</a></strong>,          and consist of a root node with the faces as its children. To use a resource          in the 3D world, the &#8220;resource&#8221; property of a 3Dnode is made          a <strong>reference to the root of a resource tree</strong>:</p>
<p><img src="http://www.jmckell.com/images/3Dresources.gif" alt="" width="368" height="272" /></p>
<p>With this arrangement rendering involves traversing the          3D world tree, and when a 3Dnode uses a resource, traversing the resource          tree and rendering its nodes.</p>
<p><span>Use of Inheritance</span><br />
The nodes in the two types of trees in this demo, 3D world tree and resource          trees, both need <strong>tree-related properties and methods</strong> but also need properties and methods <strong>unique to each type of tree</strong>.          For example, nodes in the 3D world tree need a <strong>resource property</strong> to point to a resource, while nodes in a resource tree need a <strong>list          of vectors</strong> to store geometry. Programming this using <a href="http://www.jmckell.com/OOfun.html#inheritance">inheritance</a> is a good way to go.</p>
<p>To do that, a script called <strong>&#8220;treeNode&#8221;</strong> is programmed as a <strong>generic tree node</strong>, with parent and          child properties and methods for managing a tree. This script serves as          the <strong>ancestor for 3Dnode and resNode</strong>, the two types of          nodes that make up the 3D world tree and resource trees, respectively.          The 3Dnode and resNode scripts contain the properties and methods <strong>unique          to their respective tree types</strong>.</p>
<p>Inheritance is used again for the scripts that automate          creation of different resources geometries such as cylinders, planes,          cubes, etc. These scripts inherit the resNode script and function as the          root of the resource trees. (They also inherit treeNode via resNode).</p>
<p><span>Animating the Resource</span><br />
This animation uses a <strong>&#8220;spring system&#8221;</strong> which          is a bunch of objects that act on each other with <a href="http://www.jmckell.com/springforces.html">spring          forces</a> (as if they were connected by springs). The objects in this          case are the vectors that specify the outer edge of the disc resource.          These vectors are stored in the <strong>edgeVerts list</strong> of the          resDisc object.</p>
<p>Using forces means using the <a href="http://www.jmckell.com/physicsmodel.html">physics          model</a> (position, velocity, acceleration):</p>
<div><span>&#8211; spring force</span><br />
spring1 = (zInit[i] &#8211; verts[i].<span>z</span>) * <span>.04</span><br />
spring2 = (verts[prevI].<span>z</span> &#8211; verts[i].<span>z</span>)          * <span>.08</span><br />
spring3 = (verts[nextI].<span>z</span> &#8211; verts[i].<span>z</span>)          * <span>.08</span></p>
<p><span>&#8211; acceleration, velocity, position</span><br />
zAccel = spring1 + spring2 + spring3<br />
zVelo[i] = zVelo[i] + zAccel<br />
verts[i].<span>z</span> = verts[i].<span>z</span> + zVelo[i]</p>
<p><span>&#8211; dampen velocity</span><br />
zVelo[i] = zVelo[i] * <span>.9</span></p>
</div>
<p><span><strong>modelFrame() method in script &#8220;discWave&#8221;</strong></span></p>
<p>The disc resource lies in the <strong>x-y plane</strong> so the wave is created by animating the <strong>z coordinates</strong> of the edge vectors.</p>
<p>Three spring forces act on each vector, all given by the          spring formula <strong>(restPosition &#8211; position)</strong>. The first pulls          the vector back to its initial position. The second two cause the vectors          on either side to pull the vector in their direction, which creates the          wave.</p>
<p>The velocity is dampened so the wave <strong>eventually          dies out</strong>.</p>
<p>The wave is started by <strong>setting the velocity</strong> of a vector (zVelo[i]) to a non-zero number.</p>
<p>•What would happen if only the first spring force          was used? What if only the last two were used?</p>
<p>This animation can be done in Shockwave 3D by animating                a <strong>mesh vertexList</strong>.</p>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=95&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/3d-resource-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>3D World Hierarchy</title>
		<link>http://www.jmckell.com/3d-world-hierarchy/</link>
		<comments>http://www.jmckell.com/3d-world-hierarchy/#comments</comments>
		<pubDate>Sat, 13 Mar 2010 00:42:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[3D spacing]]></category>
		<category><![CDATA[JMCKELL.com]]></category>

		<guid isPermaLink="false">http://www.heathersych.com/?p=96</guid>
		<description><![CDATA[3D World Hierarchy
Related Topics:
Data Structures and Recursion
Object Oriented Fundamentals
Depth Cues
 Quad Property
This demo shows how a 3D hierarchy is built using a tree          data structure. It shows how world transforms are calculated from relative transforms, some object-oriented ideas, and        [...]]]></description>
			<content:encoded><![CDATA[<p>3D World Hierarchy</p>
<p><strong>Related Topics</strong>:<br />
<a href="http://www.jmckell.com/datastruc.html">Data Structures and Recursion</a><br />
<a href="http://www.jmckell.com/OOfun.html">Object Oriented Fundamentals</a><br />
<a href="http://www.jmckell.com/3Dcues.html">Depth Cues</a><br />
<a href="http://www.jmckell.com/quad.html"> Quad Property</a></p>
<p>This demo shows how a 3D hierarchy is built using a <a href="http://www.jmckell.com/datastruc.html#trees"><strong>tree          data structure</strong></a>. It shows how <strong>world transforms</strong> are calculated from relative transforms, some object-oriented ideas, and          how to <strong>generate XML</strong> from a tree. It has one directional          light and a fixed camera.<a name="demo"></a></p>
<p><span>Drag on object to scale, drag off objects to          rotate group</span><br />
<object classid="clsid:166B1BCA-3F9C-11CF-8075-444553540000" width="512" height="300" codebase="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"><param name="src" value="dir/3Dworld.dcr" /><param name="swRemote" value="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' " /><param name="swStretchStyle" value="none" /><param name="bgColor" value="#000000" /><embed type="application/x-director" width="512" height="300" src="http://www.jmckell.com/dir/3Dworld.dcr" bgcolor="#000000" swremote="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' " swstretchstyle="none" pluginspage="http://www.macromedia.com/shockwave/download/"></embed></object> <span><strong>3D World Hierarchy -</strong> <a href="http://www.jmckell.com/zip/3Dworld.zip">source          movie</a></span></p>
<p>Trees are used to model 3D worlds because they reflect          how <strong>real-world objects are related to each other</strong>—objects          are composed of smaller objects, which are composed of still smaller objects,          etc. In tree terms, an object is the <strong>parent</strong> of the objects          it is made of, which are its <strong>children</strong>. Each object is          programmed as a <strong>node</strong> in the tree data structure:</p>
<p><img src="http://www.jmckell.com/images/3Dworld.gif" alt="" width="373" height="188" /><br />
In addition, moving an object moves all the parts it is made of. This          is accomplished in the 3D model by storing the orientation of each object          as an <strong>offset of its parent&#8217;s orientation</strong>. Moving the          parent will then move all its children. The absolute orientation of any          object in the 3D world is thus determined by a <strong>combination of          the relative orientations of all its ancestors</strong> up to the root          of the 3D hierarchy.</p>
<p>In Lingo, the <strong>transform</strong> data type can          be used to store the orientation of each node relative to its parent.          It also supports operations that simplify the combining of orientations.</p>
<p>For example, <strong>multiplying the transforms</strong> of the nodes from the root node to a descendant node gives the <strong>world          orientation</strong> of the descendant node. This 3Dnode method shows          how it is done recursively, where <span>trans</span> is the node&#8217;s parent-relative transform:</p>
<div><span>on</span> getWorldTransform()<br />
<span>if</span> parent = <span>void</span> <span>then return</span> trans <span> &#8211;root</span><br />
<span>return</span> parent.getWorldTransform()          * trans<br />
<span>end</span></div>
<p><span><strong>Calculating a node&#8217;s world transform recursively</strong></span></p>
<p>For more on the transform data type, see Director&#8217;s Help.</p>
<p><span>Object Geometry</span><br />
In Shockwave 3D, the geometry of a visible object is determined by what          is called a <strong>&#8220;resource&#8221;</strong> which can be used at          any number of nodes in the hierarchy.</p>
<p>In this demo there is one type of geometry, the <strong>plane</strong>,          which is rendered using the <a href="http://www.jmckell.com/quad.html">quad property</a>. Instead          of using separate resource objects, resource information is included in          each node. Each node is either rendered as a plane or is not visible.</p>
<p>Keeping resource information in the tree has limitations          (ie <strong>can&#8217;t reuse</strong>), but simplifies the code for this introductory          demo. <a href="http://www.jmckell.com/3Dresources.html">3D Resource Objects</a> shows how to          program separate resource geometry.</p>
<p><span>Overview of the code</span><br />
<span>All the code necessary for creating and rendering          the 3D world is contained in the two scripts <strong>&#8220;3Dnode&#8221;</strong> and <strong>&#8220;3Drender&#8221;</strong>. The 3D hierarchy is first built          with nodes created from the &#8220;3Dnode&#8221; script. The root node of          the tree is then passed to a new 3Drender object which starts rendering          the tree. </span></p>
<p>This set up process is shown in the <strong>setup()</strong> handler of the movie script, and is similar to how a Shockwave 3D world          is built:</p>
<div><span>&#8211;build 3D tree</span><br />
root = <span>script</span>(&#8220;3dnode&#8221;).<span>new</span>(<span>&#8220;root&#8221;</span>)<br />
cube1 = <span>script</span>(&#8220;3dcube&#8221;).<span>new</span>(<span>&#8220;cube1&#8243;</span>,<span>&#8220;txtr&#8221;</span>,<span>vector</span>(<span>40</span>,<span>40</span>,<span>40</span>))<br />
cube2 = <span>script</span>(&#8220;3dcube&#8221;).<span>new</span>(<span>&#8220;cube2&#8243;</span>,<span>&#8220;txtr&#8221;</span>,<span>vector</span>(<span>40</span>,<span>40</span>,<span>40</span>))<br />
cube3 = <span>script</span>(&#8220;3dcube&#8221;).<span>new</span>(<span>&#8220;cube3&#8243;</span>,<span>&#8220;txtr&#8221;</span>,<span>vector</span>(<span>40</span>,<span>40</span>,<span>40</span>))</p>
<p>root.addChild(cube1)<br />
root.addChild(cube2)<br />
root.addChild(cube3)<br />
<span><br />
&#8211;adjust transforms</span><br />
root.trans.<span>rotation</span> = <span>vector</span>(<span>75</span>,<span>0</span>,<span>0</span>)<br />
cube1.trans.<span>position</span> = <span>vector</span>(<span>0</span>,<span>150</span>,<span>0</span>)<br />
cube2.trans.<span>position</span> = <span>vector</span>(<span>100</span>,-<span>50</span>,<span>0</span>)<br />
cube3.trans.<span>position</span> = <span>vector</span>(-<span>100</span>,-<span>50</span>,<span>0</span>)<br />
cube2.trans.<span>scale</span> = <span>vector</span>(<span>1.5</span>,<span>1.5</span>,<span>1.5</span>)<br />
cube3.trans.<span>scale</span> = <span>vector</span>(<span>2</span>,<span>2</span>,<span>2</span>)<br />
<span><br />
&#8211;start rendering</span><br />
objRender = <span>script</span>(&#8220;3Drender&#8221;).<span>new</span>(root)</div>
<p><span><strong>Setting up the 3D hierarchy</strong></span></p>
<p>The <strong>&#8220;3Dcube&#8221;</strong> script shows how          a 3Dnode can be <strong>extended</strong> to make geometry creation easier.          3Dcube isn&#8217;t a resource, it is a 3Dnode with a few extra properties and          methods added to automate cube creation (notice 3Dcube&#8217;s ancestor is 3Dnode).</p>
<p>3Dnode<span> </span><br />
<span>Most of the properties and methods of 3Dnode are <strong>tree-related          methods</strong> for adding, finding, and removing nodes. In addition          it has <strong>four vectors, a transform, and a sprite</strong> which          store the node&#8217;s 3D-related properties.</span></p>
<p>If a cast member is passed when creating a new 3Dnode,          the node will be rendered as a quad (sprite with quad property set). If          no member is passed, the node won&#8217;t be rendered and only acts to <strong>group          the nodes beneath it</strong> in the tree.</p>
<p>The <strong>getWorldTransform()</strong> method shows how          world transforms are calculated. The world transform of each node is the          <strong>product of the parent-relative transforms</strong> of the nodes          in the path from the root to the node.</p>
<p>The <strong>toXml()</strong> method recursively generates          an<strong> XML representation of the tree</strong>. This is a simple version          that lists the names of the nodes, useful for testing and debugging. The          method can be modified to write out enough of the 3D world information          that the world can be <strong>saved as XML and recreated later</strong>.</p>
<div><span>on</span> toXML(<span>me</span>,          _tab)<br />
<span>if</span> _tab = <span>void</span> <span>then</span> _tab = <span>&#8220;&#8221;</span><br />
str = <span>return</span> &amp; _tab &amp;          <span>&#8220;&lt;&#8221;</span> &amp; name<br />
<span>if</span> child.<span>count</span> = <span>0</span> <span>then</span><br />
str = str &amp; <span>&#8220;/&gt;&#8221;</span><br />
<span>else</span><br />
str = str &amp; <span>&#8220;&gt;&#8221;</span><br />
<span>repeat with</span> c          = 1 <span>to</span> child.<span>count</span><br />
str = str &amp; child[c].toXML(_tab          &amp; <span>&#8221; &#8220;</span>)<br />
<span>end repeat</span><br />
str = str &amp; <span>return</span> &amp; _tab &amp; <span>&#8220;&lt;/&#8221;</span> &amp;          name &amp; <span>&#8220;&gt;&#8221;</span><br />
<span>end if<br />
return</span> str<br />
<span>end</span></div>
<p><span><strong>Encoding the tree as XML</strong></span></p>
<p><span>3Dcube</span><br />
3Dcube <strong>extends 3Dnode</strong> to make creation and manipulation          of cubes easier. Since 3Dcube&#8217;s <strong><a href="http://www.jmckell.com/OOfun.html#inheritance">ancestor</a></strong> is 3Dnode, it inherits the properties and methods of 3Dnode. It can be          considered a 3Dnode with some extra properties and methods for making          cubes.</p>
<p>When a new 3Dcube is created, it <strong>automatically          creates the 3Dnodes for the cube faces</strong> and adds them as its children.          The dimensions of the cube are determined by the vector passed to the          new() method.</p>
<p>The way it is programmed in the demo shows how object-oriented          techniques can be used to make cube manipulation easier. Notice that changing          a cube vertex (cuVert) will <strong>alter all three faces that share that          vertex</strong>, because those faces all point to the same vector object          for that cube vertex.</p>
<p>One note about altering a cube vertex. The statement</p>
<p>cuNode.cuVert.LTF = cuNode.cuVert.LTF * 2</p>
<p>looks like it should stretch the left-top-front corner          of the cube, but doesn&#8217;t. What happens is it <strong>creates a new vector          object</strong> (vector() * 2) and stores it in cuNode.cuVert.LTF. This          doesn&#8217;t affect the vector object that the faces point to. To do that,          operate on the x, y, and z values of the vector object separately:</p>
<p>cuNode.cuVert.LTF.x = cuNode.cuVert.LTF.x * 2<br />
etc.</p>
<p>After the cube is created, calling <strong>setCorners()</strong> will resize the cube to the dimensions of the passed vector.</p>
<p><span>3Drender</span><br />
This object provides the<strong> render method</strong>, and stores the          <strong>camera and light information</strong>. The render method traverses          the tree and sets the properties of each node&#8217;s sprite. The sprite rendering          is taken from <a href="http://www.jmckell.com/quad.html">The Quad Property</a>, with lighting,          <a href="http://www.jmckell.com/3Dcues.html">z-axis blocking</a>, and clipping added.</p>
<p>Instead of using each node&#8217;s getWorldTransform() method,          the world transforms are calculated <strong>as the tree is traversed</strong>.          If getWorldTransform() were used each node&#8217;s world transform would be          recalculated for each node in its sub-tree, which is less efficient.</p>
<p><span>Things To Try</span> <span><br />
</span><span><strong><em>New geometries</em></strong><br />
Extend 3Dnode (a la 3Dcube) to make different geometries.</span></p>
<p><strong><em>Separate resources from 3Dnodes</em></strong><br />
To reuse resources, separate the resource information from the 3D hierarchy.          Each resource would be a separate tree, and each 3Dnode would have a resource          property that would point to the root of a resource tree (or void).</p>
<p>This would allow the same resource to be used more than          once in the 3D hierarchy, and modifying the resource would modify all          appearances of it in the 3D world. <a href="http://www.jmckell.com/3Dresources.html">3D Resource          Objects</a> shows how to program separate resource objects.</p>
<p><strong><em>Mobile camera</em></strong><br />
This can be done by performing one more transform in rendering,                based on the camera&#8217;s transform. For an example see <a href="http://www.jmckell.com/3Dcamera.html">3D                Camera Movement</a>.</p>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=96&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/3d-world-hierarchy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Space Viewport 1.0</title>
		<link>http://www.jmckell.com/space-viewport-1-0/</link>
		<comments>http://www.jmckell.com/space-viewport-1-0/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 00:53:24 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[Lingo]]></category>
		<category><![CDATA[modeling]]></category>

		<guid isPermaLink="false">http://www.heathersych.com/?p=83</guid>
		<description><![CDATA[Case Study: Space Viewport
Related Topics:
Model/Display Separation
Object Oriented Fundamentals
Direction using Sine &#38; Cosine: of Force          and Acceleration



View controls:
Drag in viewport to pan
Drag on &#8216;radar&#8217; to pan
Alt-drag in viewport to zoom
Click &#8216;follow&#8217; to follow ship
Ship controls:
left/right arrows to turn
ctrl to thrust



 Space Viewport &#8211; source    [...]]]></description>
			<content:encoded><![CDATA[<p>Case Study: Space Viewport</p>
<p><strong>Related Topics:</strong><br />
<a href="http://www.jmckell.com/separation.html">Model/Display Separation</a><br />
<a href="http://www.jmckell.com/OOfun.html">Object Oriented Fundamentals</a><br />
<a href="http://www.jmckell.com/directionaccel.html">Direction using Sine &amp; Cosine: of Force          and Acceleration</a><a name="demo"></a></p>
<table border="0" width="100%">
<tbody>
<tr valign="top">
<td width="32%"><span><strong>View controls:</strong><br />
Drag in viewport to pan<br />
Drag on &#8216;radar&#8217; to pan<br />
Alt-drag in viewport to zoom<br />
</span><span>Click &#8216;follow&#8217; to follow ship</span></td>
<td width="68%"><strong>Ship controls:</strong><br />
left/right arrows to turn<br />
ctrl to thrust</td>
</tr>
</tbody>
</table>
<p><object classid="clsid:166B1BCA-3F9C-11CF-8075-444553540000" width="512" height="255" codebase="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"><param name="src" value="dir/spaceView.dcr" /><param name="swRemote" value="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' " /><param name="swStretchStyle" value="none" /><param name="bgColor" value="#000000" /><param name="progress" value="FALSE" /><param name="logo" value="FALSE" /><embed type="application/x-director" width="512" height="255" src="http://www.jmckell.com/dir/spaceView.dcr" bgcolor="#000000" progress="FALSE" logo="FALSE" swremote="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' " swstretchstyle="none" pluginspage="http://www.macromedia.com/shockwave/download/"></embed></object> <span><strong>Space Viewport</strong> &#8211; <a href="http://www.jmckell.com/zip/spaceView.zip">source        movie</a></span></p>
<p>The Space Viewport shows how <a href="http://www.jmckell.com/separation.html">model/display          separation</a> makes <strong>panning/zooming of a 2D &#8216;camera&#8217;</strong> possible, and also an <strong>object-oriented design</strong> for implementing          it. This design can be built upon to make a variety of games or &#8216;edutainment.&#8217;</p>
<p><span>Object-Oriented Design for the          Model</span><br />
The model for this simple universe consists of <strong>variables</strong> that store all aspects of the universe as well as the <strong>algorithms</strong> that act on those variables. For example, the position of each star and          sun as well as the algorithm that makes the ship move.</p>
<p>Organizing these variables and algorithms into a number          of scripts that work together is an exercise in <strong>object-oriented          design</strong>. The variables are the <strong>properties</strong> of          objects, and the algorithms are written as <strong>methods</strong> of          objects. (Make sure you&#8217;re familiar with the material in <a href="http://www.jmckell.com/OOfun.html">Object          Oriented Fundamentals</a>.)</p>
<p><strong><em>The Objects</em></strong><br />
Each type of element in the universe is programmed as a script (class).          So there is one for <strong>suns</strong>, one for<strong> stars</strong>,          and one for the <strong>ship</strong>. In addition, there is a script          for the <strong>universe</strong> itself which holds all the elements.</p>
<p align="center"><img src="http://www.jmckell.com/images/spaceView1.gif" alt="" width="198" height="134" /></p>
<p><span><strong>Script &#8220;universe&#8221;</strong></span></p>
<div><span>property</span> width    <span>&#8211; width of universe          (in universe units)</span><br />
<span>property</span> height   <span>&#8211;          height of universe (in universe units)</span><br />
<span>property</span> elements <span>&#8211;          contains all objects in universe</span><br />
<span>property</span> ship     <span>&#8211;          ship object</span></p>
<p><span>on new</span>(<span>me</span>)<br />
width = <span>250.0</span><br />
height = <span>250.0</span><br />
elements = []<br />
<span>repeat with</span> i = <span>1</span> <span>to</span> <span>100</span><br />
elements.<span>add</span>(<span>script</span>(&#8220;star&#8221;).<span>new</span>(width,          height))<br />
<span>end repeat<br />
repeat with </span>i = <span>1</span> <span>to</span> <span>7</span><br />
elements.<span>add</span>(<span>script</span>(&#8220;sun&#8221;).<span>new</span>(width,          height))<br />
<span>end repeat</span><br />
ship = <span>script</span>(&#8220;ship&#8221;).<span>new</span>(<span>me</span>)<br />
elements.<span>add</span>(ship)<br />
<span> return me<br />
end</span></div>
<p><strong><em>Use of Inheritance</em></strong><br />
When you take a look at the properties that the stars, suns, and ship          need you notice that they all have some <strong>in common</strong>. For          one, they all need to store their position within the universe, because          <strong>each <em>is a</em> universe element</strong>. These common properties          can be <a href="http://www.jmckell.com/OOfun.html#inheritance">inherited</a> from one ancestor          script. <strong>Inheritance</strong> indicates an <em>&#8216;is a&#8217;</em> relationship.</p>
<p>So in this demo the star, sun, and ship scripts all have          as an ancestor the <strong>universeElement</strong> script. This saves          having to <strong>duplicate common properties and methods</strong> in          each of these scripts, which becomes more significant as more scripts          and functionality are added to the model.</p>
<p><strong><em>Public and Private Methods</em></strong><br />
The methods of the objects are divided into &#8216;public&#8217; and &#8216;private&#8217; sections.          Public methods are meant to be <strong>called from outside the object</strong>,          while private methods are only <strong>called from within</strong>. In          Lingo this makes it easier to tell how an object is to be used. In formal          OO languages like Java these declarations are an integral part of the          language.</p>
<p><span>The Model</span><br />
The model for this simple universe consists of:</p>
<p>•Dimensions of the 2D space<br />
•Position and dimensions of each element in the universe<br />
•Algorithm to animate ship<br />
•Algorithm to animate suns</p>
<p>Not really much to it. The ship movement algorithm comes          from <a href="http://www.jmckell.com/directionaccel.html">Direction using Sine &amp; Cosine:          of Force and Acceleration</a>. In this demo, however, the ship&#8217;s position,          velocity, and acceleration values are <strong>relative to the model coordinate          system rather than the screen</strong>.</p>
<p>The model coordinate system is not explicitly programmed;          there isn&#8217;t a block of code that you can point to and say &#8216;this is the          model coordinate system.&#8217; But it is implied in that the properties of          the elements in the universe are <strong>relative to the same coordinate          system</strong> and handled as such. These include position, size, velocity,          acceleration, etc.</p>
<p>It is also implied in the functions that map model coordinates          to screen coordinates. These functions are part of the <strong>rendering          process</strong>, so here I&#8217;ll just note that these functions are written          so that the model coordinate system is similar to the stage coordinate          system. That is, all the universe elements lie in the lower-right quadrant          with the positive-y axis downward. This <strong>simplifies rendering functions</strong>.</p>
<p>In this demo, positions within the model coordinate system          use the <strong>3D vector data type</strong> even though only the x and          y coordinates are used. This makes it easier to differentiate between          <strong>model versus screen coordinates (which uses point data type)</strong> and also makes it easier to later <strong>add depth to the model</strong> if desired.</p>
<p><span>Rendering</span><br />
The bulk of the code in the demo deals with rendering, not the model.          The scripts for the universe elements contain <strong>code for both model          and rendering</strong>. The rendering code consists of anything <strong>relating          to the sprite</strong> that represents the model element.</p>
<p>The render script renders the model by <strong>setting          the location and other properties of the sprites</strong> that represent          the elements in the model.</p>
<p><strong><em>The Camera</em></strong><br />
The &#8216;camera&#8217; in this demo consists of a <strong>location in the model</strong> (camVec) and a <strong>zoom level</strong> (zoomLevel). These values are          used in mapping universe coordinates to screen coordinates, with the <strong>camera          location centered</strong> in the view area.</p>
<p>The <strong>camera is constrained</strong> in a few ways.          If <strong>&#8216;follow&#8217;</strong> is turned on, the camera follows the ship          by simply setting the camera location equal to the ship location. Imagine          how much more complicated this would be to do if a model/display technique          was not used!</p>
<p>A <strong>minimum zoom level</strong> keeps the camera          from zooming out to where the universe is smaller than the viewport. And          the camera&#8217;s <strong>location is kept a certain margin</strong> from the          edge of the universe so that space outside the universe is not seen within          the viewport. The size of this margin changes with the zoomLevel.</p>
<p><strong><em>Mapping between coordinate systems</em></strong><br />
The universe coordinate system is <strong>mapped to both the viewport          and the radar</strong>. In addition, the <strong>viewport is mapped to          the universe</strong> in order to get the universe dimensions for the          &#8216;view area&#8217; box in the radar. And the <strong>radar is mapped to the universe</strong> in order to position the camera based on a click on the radar.</p>
<p>The mapping functions consist of <strong>&#8217;shifting and          scaling&#8217;</strong>. The scaling is done by multiplying by the <strong>ratio          of the dimensions of one area to another</strong>. The shifting is done          by adding the <strong>difference between the positions of the upper left          corner of each area</strong>. For the universe that is (0,0), for the          viewport and radar it is the stage coordinates of the upper left corner          of each.</p>
<p>The methods that contain the mapping functions [uniToView()          uniToRadar() viewToUni() radarToUni()] are only called from within the          render script and so may be considered &#8216;private&#8217; methods. However, as          complexity is added it is conceivable that <strong>other scripts may need          access to these methods</strong> and so I made them public.</p>
<p><strong><em>Rendering to the Viewport</em></strong><br />
Rendering is done on <strong>two levels</strong>. First, the render script          sets properties common to all universe elements. Then it calls <strong>each          element&#8217;s own render()</strong> method:</p>
<div><span>on</span> renderToView()<br />
<span>repeat with</span> element <span>in</span> universe.elements<br />
element.sp.<span>loc</span> = uniToView(element.posVec)<br />
element.sp.<span>height</span> = element.height * zoomLevel<br />
element.sp.<span>width</span> = element.width * zoomLevel<br />
element.render()<br />
<span>end repeat<br />
end</span></div>
<p><span><strong>renderToView() method of &#8220;render&#8221; script </strong></span></p>
<p>This way each type of element can make some <strong>custom          modifications</strong> to its sprite, such as the ship and suns setting          rotation.</p>
<p>Notice that the <span>sp</span> property          and <span>render()</span> method of each element in          <span>universe.elements</span> is accessed <em><strong>even          though the </strong></em><strong><em>element</em></strong><em><strong> variable can be a variety of object types</strong></em>. The <span>element</span> variable points to ship, star, and sun objects in turn. It works because          these objects <strong>have common properties and methods by inheriting          them</strong> from the universeElement script (class). This is known in          OO jargon as <strong>&#8216;polymorphism&#8217;</strong>.</p>
<p>This is the reason there is an <strong>empty render() method</strong> defined in the universeElement script. Scripts that inherit from universeElement          can <strong>override this method</strong>, as do sun and ship scripts.          But they don&#8217;t need to, as shown by the star script. In either case the          <strong>call to the render() method of the object is valid</strong>.</p>
<p><strong><em>Rendering to the Radar</em></strong><br />
This consists of setting the <strong>location of the radar ship dot</strong>,          by making use of the uniToRadar() mapping method.</p>
<p>Also on the radar is the <strong>&#8216;view area&#8217; box</strong>,          but placing and sizing this box is <strong>not technically a part of rendering</strong> since the box doesn&#8217;t represent anything in the universe model. Instead,          the box shows the relationship between the Viewport and the universe as          specified by the camera.</p>
<p>To set the box, first the Viewport rectangle is mapped          to universe coordinates and then those universe coordinates are mapped          to the radar:</p>
<div><span>on</span> renderToRadar()<br />
spRadarShip.<span>loc</span> = uniToRadar(universe.ship.posVec)</p>
<p>topLeft = viewToUni(point(viewRect.<span>left</span>,          viewRect.<span>top</span>))<br />
botRight = viewToUni(point(viewRect.<span>right</span>,<br />
viewRect.<span>bottom</span>))<br />
spRadarBox.<span>rect</span> = <span>rect</span>(uniToRadar(topLeft),<br />
uniToRadar(botRight))<br />
<span>end</span></div>
<p><span><strong>renderToRadar() method of &#8220;render&#8221; script</strong></span></p>
<p><span>Miscellaneous</span><br />
<em><strong>Single Starfield Image</strong></em><br />
Another way to program the starfield, which is less processor intensive,          is to use one image for the whole starfield rather than using a sprite          for each star. Add a &#8220;starfield&#8221; element to the universe model          with a script like this:</p>
<p><span>property</span> <span>ancestor</span></p>
<p><span>on new</span>(<span>me</span>,          uniW, uniH)<br />
me.<span>ancestor</span> = <span>script</span>(&#8220;universeElement&#8221;).<span>new</span>()<br />
me.posVec = <span>vector</span>(uniW/<span>2</span>,          uniH/<span>2</span>, <span>0</span>)<br />
me.<span>height</span> = uniH<br />
me.<span>width</span> = uniW<br />
me.sp.<span>member</span> = &#8220;starFieldMember&#8221;<br />
<span>return me<br />
end</span></p>
<p><strong><em>Tree Data Structure for the Model</em></strong><br />
For simplicity in this demo, the universe object uses a <strong>list to          store the elements</strong> in the universe. But what if, for example,          you wanted to have moons circling planets which circle suns? Or you have          several elements you want to <strong>animate as a group</strong>? Using          a tree to store the universe elements makes this type of animation much          easier.</p>
<p>This is the technique used for 3D worlds, and it can be          used very similarly for 2D. See <a href="http://www.jmckell.com/3Dworld.html">3D World Hierarchy</a> for more on using trees in this way. A few of the primary differences          between using a list and a tree are:</p>
<p>•instead of iterating through the list, you&#8217;ll traverse the tree          <a href="http://www.jmckell.com/datastruc.html#recursion">recursively</a><br />
•each element&#8217;s position is relative to its parent, so its absolute          position is found<br />
algorithmically</p>
<p>I&#8217;d stick with using the <strong>transform data type</strong> as in the 3D quad demos. In 2D there will be just a transform to specify          position, dropping the vectors used for the quad corners. A bonus is you          get <strong>rotation and scale</strong> built in to the transform type.          Take sprite rotation from the transform rotation vector z value (assuming          you are working in 2D xy plane), and scale width/height from transform          scale vector xy values.</p>
<p>For an implementation see <a href="http://www.jmckell.com/spaceView2.html">Space Viewport 2.0</a>.</p>
<p><strong><em>A Rendering Alternative</em></strong><br />
In this demo, each universe element has a <strong>dedicated sprite</strong>.          When the element is first created it puppets the sprite, sets a few of          its properties, and uses it throughout the program.</p>
<p>A different way is to puppet the sprites and set the sprite          properties for all the elements <strong>each time the universe is rendered</strong>,          first releasing the sprites used for the last render. This takes more          computation but is a cleaner render technique and is a better solution          in some cases.</p>
<p>For example, say you had <strong>10 universe models</strong> to view alternately with each using <strong>150 sprites</strong> to render. This would be easy to do, just instantiate 10 universe                objects and set the renderObj.universe property to the one you wanted                to view. However, if the sprites are dedicated as in this demo you&#8217;d                need <strong>1500 sprites puppeted simultaneously</strong>. So this                alternate way of rendering would be the better solution in this                case.</p>
<img src="http://www.jmckell.com/?ak_action=api_record_view&id=83&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.jmckell.com/space-viewport-1-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
