tag:blogger.com,1999:blog-85829153943295476602024-03-04T20:09:34.356-08:00Unity Tips and TricksAnonymoushttp://www.blogger.com/profile/00096991192172366694noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-8582915394329547660.post-9442970653178949732016-10-08T11:56:00.001-07:002016-10-08T11:56:19.923-07:00Love that Context MenuSo you're happily coding some simple test scenes. Unfortunately, this usually involves lots of references in your scripts to other objects/components in the scene which in turn means lots of drag and drop. You find this tedious and really just want things to automagically happen when possible.<br />
<br />
It turns out that in version 4.0, Unity gave us some new abilities to make automagic things happen: component context menus!<br />
<br />
It's as simple as adding a custom attribute above a script function!<br />
<br />
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: "consolas" , "courier new" , "courier" , monospace; font-size: 10pt;">[ContextMenu(<span style="color: #a31515;">"My custom menu item"</span>)]
<span style="color: blue;">void</span> MyCustomMethod() {</code></pre>
<br />
There's undoubtedly many great uses for this but for now, you're only focused on one: less click selecting, dragging, and dropping.<br />
<br />
You have a parent in the hierarchy and you want it to automatically search its children and determine how to hook up references to them. The parent in this case is the "squad" grouping of units that path together. The children are the ones doing the actual pathing. Here are the references that we want auto-filled:<br />
<br />
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: "consolas" , "courier new" , "courier" , monospace; font-size: 10pt;"> <span style="color: blue;">public</span> NavMeshAgent frontMember;
<span style="color: blue;">public</span> NavMeshAgent rearMember;
<span style="color: blue;">public</span> NavMeshAgent leftMember;
<span style="color: blue;">public</span> NavMeshAgent rightMember;</code></pre>
<br />
This squad is determined by a spatial relationship. If we assume that they are already placed in the map in their desired formation, we can write a context menu script to hook it up. The front member will have the largest z value and the rear value will have the least. You get the idea.<br />
Your furious fingers get to work and produce this:<br />
<br />
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: "consolas" , "courier new" , "courier" , monospace; font-size: 10pt;">[ContextMenu(<span style="color: #a31515;">"Auto Find Members"</span>)]
<span style="color: blue;">void</span> AutoFindMembers() {
<span style="color: blue;">if</span> (transform.childCount >= 4) {
frontMember = transform.GetChild(0).GetComponent<NavMeshAgent>();
rearMember = transform.GetChild(1).GetComponent<NavMeshAgent>();
leftMember = transform.GetChild(2).GetComponent<NavMeshAgent>();
rightMember = transform.GetChild(3).GetComponent<NavMeshAgent>();
<span style="color: blue;">foreach</span>(Transform child <span style="color: blue;">in</span> transform) {
<span style="color: blue;">if</span> (child.position.z > frontMember.transform.position.z) {
frontMember = child.GetComponent<NavMeshAgent>();
}
<span style="color: blue;">if</span> (child.position.z < rearMember.transform.position.z) {
rearMember = child.GetComponent<NavMeshAgent>();
}
<span style="color: blue;">if</span> (child.position.x < leftMember.transform.position.x) {
leftMember = child.GetComponent<NavMeshAgent>();
}
<span style="color: blue;">if</span> (child.position.x > rightMember.transform.position.x) {
rightMember = child.GetComponent<NavMeshAgent>();
}
}
frontMember.name = <span style="color: #a31515;">"front"</span>;
rearMember.name = <span style="color: #a31515;">"rear"</span>;
leftMember.name = <span style="color: #a31515;">"left"</span>;
rightMember.name = <span style="color: #a31515;">"right"</span>;
} <span style="color: blue;">else</span> {
Debug.LogWarning(<span style="color: #a31515;">"Need at least 4 children to perform auto find."</span>);
}
}</code></pre>
<br />
Great! This hooks it all up and renames the children as well so that you can easily verify the results.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEGF1ZHptQXTij8DI3LNXg3-Kf7Xv1Vvdcg_HdoTiTFZicE323VPF3u41ibJ2BEZT9KLarcZ1eHBMcnPeX6MTn4QAOh-0xVinHz_8xDZC90wfG1nFF95ocsCX3JuzPQpo0G3eaU5sDjG8/s1600/Screen+Shot+2014-07-01+at+10.23.57+AM.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEGF1ZHptQXTij8DI3LNXg3-Kf7Xv1Vvdcg_HdoTiTFZicE323VPF3u41ibJ2BEZT9KLarcZ1eHBMcnPeX6MTn4QAOh-0xVinHz_8xDZC90wfG1nFF95ocsCX3JuzPQpo0G3eaU5sDjG8/s1600/Screen+Shot+2014-07-01+at+10.23.57+AM.png" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIq0a7LVoLRt5l9lqzx0NdE6PuiSaR6dVzNRjshZjXDcgoIUJy3WLsIkc09KRPGDBRG6mwhs_p8F0LavGEyky9vYmlvhP6AU6_3YHREqKgYLxyyLJF_8QlOKaW3EXS2wqa27Ovwl113SM/s1600/Screen+Shot+2014-07-01+at+10.23.03+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIq0a7LVoLRt5l9lqzx0NdE6PuiSaR6dVzNRjshZjXDcgoIUJy3WLsIkc09KRPGDBRG6mwhs_p8F0LavGEyky9vYmlvhP6AU6_3YHREqKgYLxyyLJF_8QlOKaW3EXS2wqa27Ovwl113SM/s1600/Screen+Shot+2014-07-01+at+10.23.03+AM.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD444_iCBMWe3s8E68qtMRctgBJ7h3nNDLdzG0zSYrgvFVUyprEP4CRdzWcYNV6zABMRAhfQr2yY3ERBNfMziVfin-YxRTsCWbeQc-de5heWZeNjAQkezrjb8375rMUOgTAiudbrzPyZ0/s1600/Screen+Shot+2014-07-01+at+10.24.04+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD444_iCBMWe3s8E68qtMRctgBJ7h3nNDLdzG0zSYrgvFVUyprEP4CRdzWcYNV6zABMRAhfQr2yY3ERBNfMziVfin-YxRTsCWbeQc-de5heWZeNjAQkezrjb8375rMUOgTAiudbrzPyZ0/s1600/Screen+Shot+2014-07-01+at+10.24.04+AM.png" /></a></div>
<br />
Every little bit counts and you're sure there will be many more cases in the future where being able to call your code via a context menu will pay off.Anonymoushttp://www.blogger.com/profile/00096991192172366694noreply@blogger.com0tag:blogger.com,1999:blog-8582915394329547660.post-4530185032472543072015-10-10T17:08:00.003-07:002015-10-10T17:08:57.377-07:00Taming Unity's Navigation System - Assumption Testing Part 1So you need some pathfinding in your game huh? Well, you have some options and of course some tradeoffs associated whatever you choose. So real quick-like, what are the options?<br />
<br />
<b><span style="color: #ffd966;">1. Unity's native system</span></b><br />
<b><span style="color: #ffd966;">2. Aron Granberg's A* system</span></b><br />
<b><span style="color: #ffd966;">3. Apex Path</span></b><br />
<b><span style="color: #ffd966;">4. Quick Path</span></b><br />
<b><span style="color: #ffd966;">5. Simple Path</span></b><br />
<b><span style="color: #ffd966;">6. Simply A* (free)</span></b><br />
<b><span style="color: #ffd966;">7. Easy Path</span></b><br />
<b><span style="color: #ffd966;">8. Etc..... (several others available on the asset store)</span></b><br />
<br />
That's a lot and unfortunately I don't have the time and money to evaluate each one and so I haven't explored all of these in much depth... with the exception of Unity's own native system. However, I don't think I really needed to as I picked Unity's solution for a very specific reason.<br />
<br />
<h3 style="text-align: center;">
<span style="color: #6fa8dc;">
PERFORMANCE #perfmatters</span></h3>
<br />
Performance really does matter, especially in more CPU intensive games where you have a very tight budget and can't afford to take a big chunk out for pathfinding. Or, maybe you want to have hundreds of independently simulated units. In any case, Unity's system has the advantage of being built with native code (C++) and optimized by the people who make the engine so we can expect it to perform well for most use cases. Check out the improvements made in Unity 5 <a href="https://unity3d.com/unity/whats-new/unity-5.0" target="_blank">here</a>. <br />
<br />
Any 3rd parties that provides this feature will suffer from the overhead involved in running .net scripts (C#/Unityscript/Boo). At best, I've heard performance can be about 1.5x as fast. However, once IL2CPP is fully deployed across all platforms this may be less of an issue (due to cross compilation to native code) for final builds but it will still hurt workflow in the editor which relies on .net/mono, not IL2CPP.<br />
<br />
So that sounds great, it performs well. How easy is it to use and how flexible is it to do whatever crazy things we wanna do?<br />
<br />
Well, a core value of Unity is simplicity so it's no surprise that their system is relatively simple (and that's generally a good thing) but how flexible is it?<br />
<br />
This is a deeper question and why the title of this post is called "taming". Over the next few posts we'll be putting this to the test but for now let's just get our feet wet.<br />
<br />
How do we use this thing?<br />
<br />
<span style="color: #ffd966;"><b>1. Mark your scene objects to support navmesh creation (navmesh static)</b></span><br />
<span style="color: #ffd966;"><b>2. Bake your navmesh (create it)</b></span><br />
<span style="color: #ffd966;"><b>3. Add the NavMeshAgent component to any object you want to be able to navigate</b></span><br />
<span style="color: #ffd966;"><b>4. Set up the agent's properties such as speed, acceleration, radius, etc...</b></span><br />
<span style="color: #ffd966;"><b>5. (Optional) Give any objects that are obstacles the NavMeshObstacle component</b></span><br />
<span style="color: #ffd966;"><b>5. Give the agent a destination and watch em go</b></span><br />
<br />
If you're clear on all these steps read on but if not, check out Unity's tutorials of the whole process here: <a href="http://unity3d.com/learn/tutorials/modules/beginner/navigation" target="_blank">http://unity3d.com/learn/tutorials/modules/beginner/navigation</a><br />
<br />
Also take a quick look at the main APIs we have to work with here:<br />
<a href="http://docs.unity3d.com/ScriptReference/NavMeshAgent.html" target="_blank">NavMeshAgent</a><br />
<a href="http://docs.unity3d.com/ScriptReference/NavMesh.html" target="_blank">NavMesh</a><br />
<br />
With that the API verbage is fresh in your mind, let's start exploring what's there and <b>test any assumptions</b> we might have.<br />
<br />
<h2 style="text-align: center;">
Assumption #1</h2>
<div>
<br /></div>
<div style="text-align: center;">
Setting the destination will immediately calculate a path on the same frame.</div>
<br />
<h2 style="text-align: center;">
Test</h2>
<div>
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/o4W0qgCHH9k" width="420"></iframe>
<br />
<br />
<span style="text-align: left;">Nope, generally not but Unity is pretty clear about this behavior.</span></div>
<div style="text-align: left;">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2sVmDPBuXowerJhEvs4fOcCGOb3CPZIKmPbw10eR9bPhO7MkdQKTpKBGQknGP1HJT-qxJZwyVsetoTeF0_reFAw6SLvg2IEL6zy091XmFw5OmspYyVWaicf8Sc42KYYNtTTNV_iA3Lg/s1600/Screen+Shot+2014-09-27+at+10.25.59+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="149" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2sVmDPBuXowerJhEvs4fOcCGOb3CPZIKmPbw10eR9bPhO7MkdQKTpKBGQknGP1HJT-qxJZwyVsetoTeF0_reFAw6SLvg2IEL6zy091XmFw5OmspYyVWaicf8Sc42KYYNtTTNV_iA3Lg/s1600/Screen+Shot+2014-09-27+at+10.25.59+AM.png" width="640" /></a></div>
<br /></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
In any case you should know what to expect or rather, you should expect to not exactly know what to expect. Let me explain. In a game I was working on during Summer 2015, I had implemented a squad based pathfinding system. It was based around a "leader" unit that knew the full path from their current location to the destination and "follower" units who created micro-paths (small distance away) based on the leader. Most of the time, things worked as expected but occasionally the "followers" would stand around for a while doing nothing until Unity finally calculated a path and they went on their merry way. In some cases this took over 1 second resulting the in "leader" dashing off toward his destination while the "followers" well... did nothing.<br />
<br />
The solution is to use a method the completes immediately when we request the path - <i>NavMeshAgent.CalculationPath</i> and <i>NavMeshAgent.SetPath</i>. Here's an example:<br />
<br />
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">NavMeshPath path = <span style="color: blue;">new</span> NavMeshPath();
agent.CalculatePath(hit.position, path);
agent.SetPath(path);
</code></pre>
<br />
This may be less performant since the calculation cannot be amortized across multiple frames (I assume Unity does something like this but would have to do more investigation to know for sure) but you are guaranteed to have a path immediately available. Also, generally having deterministic logic in your game is generally a very good thing for design and debugging.<br />
<br /></div>
<h2 style="text-align: center;">
Assumption #2</h2>
<div>
<br /></div>
<div style="text-align: center;">
NavMeshAgent.remainingDistance will always tell us how far we have to go.</div>
<br />
<h2 style="text-align: center;">
Test</h2>
<div>
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/GzeVzlV4EFY" width="560"></iframe>
</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Hmmm.... remaining distance appears to be Mathf.Infinity until the agent becomes relatively close to the destination. I guess that's not a value we can rely on. If we really need that info we can calculate it ourselves by measuring the distance between each waypoint (NavMeshAgent.path.corners) and adding them all up.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
What does Unity say about all this:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-JhIPakuS7Umv8efEi6T9wYSjnMrrYXOF9CAxRWWrYRhTxfMHcoE7UnvpqLZbZE70oNdsYiIIMkG2faC_QaiMmY3CDCrq-x-1hwG9wD90prAa8B2hISyJHqhxe13wWnyw6xeVii5DSU0/s1600/Screen+Shot+2014-09-27+at+10.29.11+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-JhIPakuS7Umv8efEi6T9wYSjnMrrYXOF9CAxRWWrYRhTxfMHcoE7UnvpqLZbZE70oNdsYiIIMkG2faC_QaiMmY3CDCrq-x-1hwG9wD90prAa8B2hISyJHqhxe13wWnyw6xeVii5DSU0/s1600/Screen+Shot+2014-09-27+at+10.29.11+AM.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Ok, I suppose by unknown they mean that they haven't yet calculated it for us since we can obviously do the calculations ourselves. Here's an example:</div>
<div class="subsection" style="margin: 0px; padding: 0px;">
<div style="margin-bottom: 15px; padding: 0px;">
<div style="color: #333333; font-family: Helvetica, Arial, sans-serif; font-size: 0.875em; line-height: 21.6000003814697px;">
<br />
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;"><span style="color: blue;">float</span> distance = 0.0f;
Vector3[] corners = myAgent.path.corners;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> c = 0; c < corners.Length - 1; ++c) {
distance += Mathf.Abs((corners[c] - corners[c + 1]).magnitude);</code></pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">}</code></pre>
</div>
<h2 style="text-align: center;">
<br /></h2>
<h2 style="text-align: center;">
Assumption #3</h2>
<div>
<br /></div>
<div style="text-align: center;">
<i>hasPath</i> will be false when the agent has finished pathing.</div>
<div style="text-align: center;">
<br /></div>
<h2 style="text-align: center;">
Test</h2>
<div>
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/rm-_n61uUEk" width="420"></iframe>
</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Ok, so this one is tricky. After a quick test you might conclude this to be true only to discover a case later when it is not. If you leave the NavMeshAgent's settings to their defaults you'll notice that <i>autoBraking</i> is <i>true (</i>checked box in the inspector). And, if you don't change that then you will be able to rely on the <i>hasPath</i> variable actually telling you when the path is complete. Otherwise, you'll have to have some your own logic for determining when an agent should stop "pathing".<br />
<br />
Now there is plenty more testing to be done but I thought I'd chop this up into separate parts in the hopes that I could actually release this to you rather than letting it collect dust in my personal collection. Until then:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://37.media.tumblr.com/tumblr_lzr3rnVDRf1r1jazbo1_500.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://37.media.tumblr.com/tumblr_lzr3rnVDRf1r1jazbo1_500.jpg" height="320" width="223" /></a></div>
<br /></div>
<h2 style="text-align: center;">
</h2>
</div>
</div>
Anonymoushttp://www.blogger.com/profile/00096991192172366694noreply@blogger.com1tag:blogger.com,1999:blog-8582915394329547660.post-26899360867484786532014-07-26T17:10:00.000-07:002014-07-27T11:31:25.979-07:00Terrain, Texture Splatting, and Three.js?So there comes a time in every developers life when they're unable to use the tools they know and love to get the job done. Sometimes the tools aren't a good fit for the task and other times there are political reasons. Maybe you work for the man and the man says use tool "x".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYQzs5Wop9yE5Y00L4sRa06oEI3iXekSrqaENIMrosmxZOPEXOGerA2fBwyE6NyRH0etkpLuuNwz9HALx0cer2R7aJbin7L_WzDu4LJXPv-auWwATqEp_7uetzbuF0fs_g0At-DLF-gSM/s1600/x.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYQzs5Wop9yE5Y00L4sRa06oEI3iXekSrqaENIMrosmxZOPEXOGerA2fBwyE6NyRH0etkpLuuNwz9HALx0cer2R7aJbin7L_WzDu4LJXPv-auWwATqEp_7uetzbuF0fs_g0At-DLF-gSM/s1600/x.png" height="200" width="200" /></a></div>
<br />
<br />
That's a bummer but that's reality. On the bright side, you'll have an opportunity to learn and gain experience you might not have had before. So here's my story:<br />
<br />
One day I was in this situation where I had to make a terrain demo in a web page WITHOUT using any plugins. If you haven't already seen my video about this, check it out <a href="http://youtu.be/q893QCV2zTs" target="_blank">here</a>. This wouldn't be an issue with Unity 5 and above (due to export to asm.js) but at this time, version 4 was the latest.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ6n3PM1RbRAYeRzhBkuD_oStN63HGKeVYejnvbArkJYV_fUeWgIVthlJSozwUzm08ZN-3G2OuE0IwOaX41-rJDZeIjOFTqENtSHm3nz985Kh4ceeRZb4lBO1KDg50G1-p1W0f3tlkXUo/s1600/no-plugins.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ6n3PM1RbRAYeRzhBkuD_oStN63HGKeVYejnvbArkJYV_fUeWgIVthlJSozwUzm08ZN-3G2OuE0IwOaX41-rJDZeIjOFTqENtSHm3nz985Kh4ceeRZb4lBO1KDg50G1-p1W0f3tlkXUo/s1600/no-plugins.png" /></a></div>
<br />
<br />
So let's back up a moment. What is texture splatting and why would we want to use it?<br />
<br />
Simply put, texture splatting is a technique for combining different textures. And not only that, it allows you to change how those textures are combined (blended) at every texel. That means you don't have to blend those textures together the same way over the whole object, the way they are blended can vary.<br />
<br />
For instance, check out the terrain below. It is blending a combination of 4 different textures in different ways across the terrain.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGNPhxkfw7DcPjfw8lDQLuDbmJjjX5BFDFEND8WwFtg939Mbj0UaxU_8ma7n8SbWQHlkuQqBREp5_EGIVxY5NiprPoD_jkIbJsOilAdWjwZ5DkResWSlEWti3Z34obULfIq-dMImGRN9I/s1600/splat.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGNPhxkfw7DcPjfw8lDQLuDbmJjjX5BFDFEND8WwFtg939Mbj0UaxU_8ma7n8SbWQHlkuQqBREp5_EGIVxY5NiprPoD_jkIbJsOilAdWjwZ5DkResWSlEWti3Z34obULfIq-dMImGRN9I/s1600/splat.PNG" height="320" width="319" /></a></div>
<br />
<br />
What you're seeing is a combination of the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq0uFSGopP1Tju6Y93I11ybzUPNyrR1xcDMfNCxaFG1NQgE8-PXF88AXIXO0f9W3scBHi19BtagxrH_f2DLPz2OGcpUnNVHktXHc5v6HSLZc0Uo1EuWj-37uAX5_xVjtwEGdAGmwo1_38/s1600/textures.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq0uFSGopP1Tju6Y93I11ybzUPNyrR1xcDMfNCxaFG1NQgE8-PXF88AXIXO0f9W3scBHi19BtagxrH_f2DLPz2OGcpUnNVHktXHc5v6HSLZc0Uo1EuWj-37uAX5_xVjtwEGdAGmwo1_38/s1600/textures.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
You can see that the mix of textures is applied in different ways across the terrain. For instance, some areas have more snow, more dirt, more grass, or more rock.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
What you're <b>not</b> seeing in those images is the instructions for how to combine them at every point. You just see the result. So what's the secret sauce here?</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Check out this image:</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2NKyQ-jjxCrA9Xja6LlwK6-yZFcpH3mSI2MFTn4yXg8hiUUOvpcLsXqwazVYV6vkAZbU5HISufHHVqGIwDK7p1c0wu5kF_5FVrsi1HYXVdXRRsWAz2XWRUnpVGSqDFsnLMtI5Tz9e_dw/s1600/splat2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2NKyQ-jjxCrA9Xja6LlwK6-yZFcpH3mSI2MFTn4yXg8hiUUOvpcLsXqwazVYV6vkAZbU5HISufHHVqGIwDK7p1c0wu5kF_5FVrsi1HYXVdXRRsWAz2XWRUnpVGSqDFsnLMtI5Tz9e_dw/s1600/splat2.PNG" height="320" width="317" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Immediately you can see that the crazy colors in this image are associated with the terrain you saw above. That's because each color channel in the image (RGBA) corresponds to how much a certain texture should be used. You might get something like this:</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Red channel: dirt </div>
<div class="separator" style="clear: both; text-align: justify;">
Green channel: grass</div>
<div class="separator" style="clear: both; text-align: justify;">
Blue channel: cliff rock</div>
<div class="separator" style="clear: both; text-align: justify;">
Alpha channel: snow</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Note that alpha is not a color but an extra spot usually reserved for transparency. Each color channel is multiplied by the texture its associated with and added up to get the final result. This process is done using pixel shaders (executes in code that runs directly on the GPU) which makes it very fast to compute. Here's some shader code that actually does exactly that:</div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">vec4</span> pixelColor1 <span style="color: #333333;">=</span> texture2D(texture1, UV1);
<span style="color: #008800; font-weight: bold;">vec4</span> pixelColor2 <span style="color: #333333;">=</span> texture2D(texture2, UV2);
<span style="color: #008800; font-weight: bold;">vec4</span> pixelColor3 <span style="color: #333333;">=</span> texture2D(texture3, UV3);
<span style="color: #008800; font-weight: bold;">vec4</span> pixelColor4 <span style="color: #333333;">=</span> texture2D(texture4, UV4);
<span style="color: #008800; font-weight: bold;">vec4</span> alphaMap <span style="color: #333333;">=</span> texture2D(tAlphaMap, alphaUV);
gl_FragColor <span style="color: #333333;">=</span> pixelColor1 <span style="color: #333333;">*</span> alphaMap.r <span style="color: #333333;">+</span> pixelColor2 <span style="color: #333333;">*</span> alphaMap.g <span style="color: #333333;">+</span>
pixelColor3 <span style="color: #333333;">*</span> alphaMap.b <span style="color: #333333;">+</span> pixelColor4 <span style="color: #333333;">*</span> alphaMap.a;</pre>
</div>
<br />
A quick explanation: texture2D is function that looks up a color from texture using a texture coordinate and tAlphaMap refers to the splat texture shown above. Each color channel (.r .g .b .a) is a number between 0 and 1 which makes multiplying color by it the same as taking a percentage of that color (ex .25 = 25%). The idea is that your percentages will all add up to one so you get an appropriate contribution for each texture based on your values. For example, check out a couple examples with just dirt and grass:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqKwRa4A1mxKl2FEXD8JWNgqca0AlEiq37NpGqypk6E4BA0b3fOlIQWHxIlua6IQ6Jo5fE-HhbbcqTLIH6IQKjzSHNSRtOOxYby6GHXsiAkLpQ6Qn2fVGozLEJri50cQhYG3IkYUcrs0A/s1600/grassdirt.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqKwRa4A1mxKl2FEXD8JWNgqca0AlEiq37NpGqypk6E4BA0b3fOlIQWHxIlua6IQ6Jo5fE-HhbbcqTLIH6IQKjzSHNSRtOOxYby6GHXsiAkLpQ6Qn2fVGozLEJri50cQhYG3IkYUcrs0A/s1600/grassdirt.PNG" height="160" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
.5 * dirt + .5 * grass</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEymk7Ank0tI2sGF5bD4AnB2upjKNpe4MVhMU2O4Hrb-BE_lic63hG-vZCznRXzNdHGMPvvA8TISIcCYewkiicx4bEtCdhYrWEDx9h0-gt0v4cDcKtGKSMgXxORiKQm5z51NcdDIBl4Zc/s1600/halfgrass.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEymk7Ank0tI2sGF5bD4AnB2upjKNpe4MVhMU2O4Hrb-BE_lic63hG-vZCznRXzNdHGMPvvA8TISIcCYewkiicx4bEtCdhYrWEDx9h0-gt0v4cDcKtGKSMgXxORiKQm5z51NcdDIBl4Zc/s1600/halfgrass.PNG" height="319" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
.75 * dirt + .25 * grass</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYvyJrL9_gO0umUHccXPhQuAYJQtiYIpWFLHYqQ4-hC9EdP8FyxIC2VUH4mImIjb7P2Ur7-J-trg6nJ4DNIF6DCiMSGuxM0NNwkJUgdX57ml_UTbp-YBNBQNCFqORC8aSU_4PDuzZq1GA/s1600/threequarterdirt.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYvyJrL9_gO0umUHccXPhQuAYJQtiYIpWFLHYqQ4-hC9EdP8FyxIC2VUH4mImIjb7P2Ur7-J-trg6nJ4DNIF6DCiMSGuxM0NNwkJUgdX57ml_UTbp-YBNBQNCFqORC8aSU_4PDuzZq1GA/s1600/threequarterdirt.PNG" height="319" width="320" /></a></div>
<br />
<br />
<br />
So great, texture splatting is a convenient and fast technique for texturing terrain. It's also what Unity uses along with a bunch of nice brushes and tools for painting with them. Again, unfortunately we can't use Unity... at least for rendering in the final application.<br />
<br />
No problem, nothing is stopping us from authoring our splat texture ("alpha map") from Unity and using it elsewhere. Well, nothing other than the fact that Unity doesn't provide a convenient way to get data out. So let's see what's accessible to us via script.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLy7C45DAW6Q2VWQUFFYv-HkUuqJUZB0V5EoT8fB1FzFmHytemLbjVEYyGj8Orwu0wbfrzaXvXKJpOIHFMLkozAWCZIPM2EoeFK6C6t1xKsBQhoaJ_LdEdjJ2QTh6bc1kmwqt00-Kzewk/s1600/Screen+Shot+2014-07-24+at+10.40.46+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLy7C45DAW6Q2VWQUFFYv-HkUuqJUZB0V5EoT8fB1FzFmHytemLbjVEYyGj8Orwu0wbfrzaXvXKJpOIHFMLkozAWCZIPM2EoeFK6C6t1xKsBQhoaJ_LdEdjJ2QTh6bc1kmwqt00-Kzewk/s1600/Screen+Shot+2014-07-24+at+10.40.46+AM.png" height="289" width="640" /></a></div>
<br />
Great, we can access the data. Now how do we get it out? Like this:<br />
<br />
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;"><span style="color: blue;">void</span> SaveSplat() {
<span style="color: green;">// Use the selected texture if it exists or else bring up a dialog to choose</span>
<span style="color: blue;">string</span> assetPath;
<span style="color: blue;">if</span> (alphaMap) {
assetPath = AssetDatabase.GetAssetPath(alphaMap);
} <span style="color: blue;">else</span> {
assetPath = EditorUtility.SaveFilePanelInProject(<span style="color: #a31515;">"Save texture"</span>,
<span style="color: #a31515;">"mySplatAlphaMap.asset"</span>, <span style="color: #a31515;">"asset"</span>, <span style="color: #a31515;">"Please enter a file name to save the texture to."</span>);
}
<span style="color: green;">// If a valid location was chosen</span>
<span style="color: blue;">if</span> (assetPath.Length != 0) {
<span style="color: green;">// Get the terrain and its data, my script that's being used here is TerrainTool</span>
Terrain terrain = (target <span style="color: blue;">as</span> TerrainTool).transform.GetComponent<terrain>;();
TerrainData data = terrain.terrainData;
<span style="color: blue;">float</span>[,,] maps = data.GetAlphamaps(0, 0, data.alphamapWidth, data.alphamapHeight);
<span style="color: blue;">int</span> numSplats = maps.GetLength(2);
Color32[] image = <span style="color: blue;">new</span> Color32[data.alphamapWidth * data.alphamapHeight];
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> y = 0; y < data.alphamapHeight; ++y) {
<span style="color: green;">// Flip the image if desired such as when planning to export the texture to use elsewhere</span>
<span style="color: blue;">int</span> vertical = (invertY) ? data.alphamapHeight - y - 1: y;
<span style="color: blue;">for</span> (<span style="color: blue;">int</span> x = 0; x < data.alphamapWidth; ++x) {
<span style="color: blue;">int</span> imageIndex = y * data.alphamapWidth + x;</terrain></code></pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"></pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"><pre style="margin: 0em; overflow: auto;"><code style="font-family: Consolas, 'Courier New', Courier, monospace; font-size: 10pt;"><span style="color: green;"> // The colors are in the range from 0 to 1 but an image file is expected to be from 0 to 255</span></code></pre>
</pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">
image[imageIndex].r = (<span style="color: blue;">byte</span>)(maps[vertical, x, 0] * 255.0f);
image[imageIndex].g = (numSplats > 1) ? (<span style="color: blue;">byte</span>)(maps[vertical, x, 1] * 255.0f) : (<span style="color: blue;">byte</span>)0;
image[imageIndex].b = (numSplats > 2) ? (<span style="color: blue;">byte</span>)(maps[vertical, x, 2] * 255.0f) : (<span style="color: blue;">byte</span>)0;
image[imageIndex].a = (numSplats > 3) ? (<span style="color: blue;">byte</span>)(maps[vertical, x, 3] * 255.0f) : (<span style="color: blue;">byte</span>)0;
}
}
</code></pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;"><pre style="margin: 0em; overflow: auto;"><code style="font-family: Consolas, 'Courier New', Courier, monospace; font-size: 10pt;"><span style="color: green;"> // make a texture to store our image colors in</span></code></pre>
</code></pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;"> Texture2D finalSplatTexture = <span style="color: blue;">new</span> Texture2D(data.alphamapWidth, data.alphamapHeight);
finalSplatTexture.SetPixels32(image);
alphaMap = finalSplatTexture;
</code></pre>
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;"><pre style="margin: 0em; overflow: auto;"><code style="font-family: Consolas, 'Courier New', Courier, monospace; font-size: 10pt;"><span style="color: green;"> // Save this out as a .asset</span></code></pre>
AssetDatabase.CreateAsset(finalSplatTexture, assetPath);
}
}</code></pre>
<br />
So this goes through the whole alphamap and saves it as a .asset. Unfortunately ".asset" is a Unity format which won't help us much so we need to take one more step to convert that into something we want.<br />
And, frequently when we need something, someone else has already done it out there and has made their work publicly available. For this step, we are in luck. A quick search turns up this:<br />
<br />
<div>
<br /></div>
<pre style="background-color: white; margin: 0em; overflow: auto;"><code style="color: black; font-family: Consolas,"Courier New",Courier,Monospace; font-size: 10pt;">import System.IO;
@MenuItem(<span style="color: #a31515;">"Assets/Export Texture"</span>)
<span style="color: blue;">static</span> function Apply () {
<span style="color: blue;">var</span> texture : Texture2D = Selection.activeObject <span style="color: blue;">as</span> Texture2D;
<span style="color: blue;">if</span> (texture == <span style="color: blue;">null</span>)
{
EditorUtility.DisplayDialog(<span style="color: #a31515;">"Select Texture"</span>, <span style="color: #a31515;">"You Must Select a Texture first!"</span>, <span style="color: #a31515;">"Ok"</span>);
<span style="color: blue;">return</span>;
}
<span style="color: blue;">var</span> bytes = texture.EncodeToPNG();\
File.WriteAllBytes(Application.dataPath + <span style="color: #a31515;">"/exported_texture.png"</span>, bytes);
}</code></pre>
<br />
That adds a handy menu item that we can use once we've selected our splat .asset to generate a .png file. Mission accomplished!<br />
<br />
So now onto the next piece, putting it into a three.js web application. Unfortunately, that's an entirely different blog post unto itself. If you're interested in it feel free to leave a comment for me. I read all of them.<br />
<br />
Oh, and you can get a Unity package with everything we've talked about <a href="https://drive.google.com/file/d/0B97tvqwCatoZenRoVk1vNnFEUzQ/edit?usp=sharing" target="_blank">HERE</a>.<br />
<br />
If you wanna see this in action, make sure you have a WebGL enabled browser and check out the result <a href="http://www.realitymeltdown.com/WebGL/Walkable%20Terrain.html" target="_blank">HERE</a><br />
<br />
To see the source for that demo, hop on over to my github repo where it's waiting for you <a href="https://github.com/insominx/Three.js-Demos" target="_blank">HERE.</a><br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/00096991192172366694noreply@blogger.com0tag:blogger.com,1999:blog-8582915394329547660.post-60062801107394332962013-08-16T12:19:00.001-07:002013-08-16T12:19:59.651-07:00Procedural Meshes - Circles<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;">If you're specifically interested in how to create procedural geometry in Unity and not in the </span><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;">mathematical</span><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;"> details of creating circle geometry, go here: </span></span></div>
</div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="http://www.youtube.com/watch?v=3jHe1FzrKD8" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">http://www.youtube.com/watch?v=3jHe1FzrKD8</span></a><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Otherwise, <span style="color: yellow;">please read on</span>!</span></span></div>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b id="docs-internal-guid-6a282c01-7a89-b5c5-ffd9-8299247cc999" style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the link above, we created a simple 4 vertex 2d rectangle (“quad”). Quads are quite useful but sometimes you’re interested in more complex shapes. How about a </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: bold; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">circle</span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">? </span></span></div>
</div>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ok, that doesn’t sound that much more complex but it does allow us to get our hands dirty with some maths because let’s face it, there was no <span style="color: yellow;">sexy math</span> involved in creating a quad. And, as we’ll soon see, a simple circle is more involved that it sounds.</span></div>
</div>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You may remember this equation from school (if not, you can learn about it up with some cool videos from Khan Academy </span><a href="http://www.youtube.com/watch?v=6r1GQCxyMKI" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">http://www.youtube.com/watch?v=6r1GQCxyMKI</span></a><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ):</span></span></div>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span>
<br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: center;">
<span style="color: orange; font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 19px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">x</span><span style="font-size: 9px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: super; white-space: pre-wrap;">2</span><span style="font-size: 19px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> + y</span><span style="font-size: 9px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: super; white-space: pre-wrap;">2</span><span style="font-size: 19px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> = r</span><span style="font-size: 9px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: super; white-space: pre-wrap;">2</span></span></div>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">and it sure does look simple. It says that the sum of the squares of x and y always have to equal some number, the radius squared.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://lh5.googleusercontent.com/svNL0ebxXFw1MGH3RdVKPnDY6LmoAnCeBpYuGnwWjlsKUF7tO_dVR4Dq1yGwNhPODAVgrLCl0GJ5ec1tsC5eruhYTiyReCQskEo4cCypqYrhqoUMS_ZqMY1Z" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" height="376px;" src="https://lh5.googleusercontent.com/svNL0ebxXFw1MGH3RdVKPnDY6LmoAnCeBpYuGnwWjlsKUF7tO_dVR4Dq1yGwNhPODAVgrLCl0GJ5ec1tsC5eruhYTiyReCQskEo4cCypqYrhqoUMS_ZqMY1Z" width="376px;" /></span></a></div>
<b style="font-weight: normal;"><span style="font-family: Arial, Helvetica, sans-serif;"><br /><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></span></b><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the case, it <span style="color: yellow;">must sum up to be </span></span><span style="background-color: transparent; color: yellow; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>1</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. For example, here we’ve chosen our radius to be equal to </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>1</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>1<sup>2</sup></b> is still equal to <b>1</b>. To test this, let’s pick an <b>x</b> value that is less than our radius. If we pick <b>x</b> to be <b>0.5</b> then <b>x<sup>2</sup></b> will be equal to 0.25. That leaves us with this equation: </span><span style="background-color: transparent; color: orange; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>0.25 + y<sup>2</sup> = 1</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. So now we solve for </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>y</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ("sqrt" means square root): </span><span style="background-color: transparent; color: orange; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>y = sqrt(1 - 0.25)</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. We could compute that but we don’t really have to because we know that you have to add </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>0.75</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>0.25</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to get </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b>1</b></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></span></div>
</div>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Armed with that knowledge alone and some patience, you could probably get something working. and t</span><span style="font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">his seems sufficient to complete the task, but is it the </span><span style="font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"><b>best way</b></span><span style="font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">? <span style="color: yellow;">Let’s explore</span> this a bit further.</span></span></div>
</div>
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<div style="text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We know that creating procedural geometry involves creating a set of points and then connecting those points in sets of three to form triangles. </span><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;">One way to this using the equation above might be to <span style="color: yellow;">iterate across each x value</span> and then generate the matching y value. It might look something like this:</span></span></div>
</div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"><code style="color: black; word-wrap: normal;"> for (float x = -1.0; x < 1.0; x+=0.1) {
float y = Mathf.sqrt(radius * radius - x * x);
myVertices.push(new Vector3(x, y, 0);
}
</code></span></span></pre>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This would get you points laid out across this curve:</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div style="text-align: center;">
<b style="font-weight: normal;"><span style="font-family: Arial, Helvetica, sans-serif;"><img height="196px;" src="https://lh5.googleusercontent.com/JnNBi4C8p8B6guHP9C12db-yNHJpTxLHNYI1OP8vIFv96S5ot8V5NX3pdr6vUDaGYVTF6aSDR6pC4LUGf2XC7HTdBzyCUkbfltX7rnFwrUjjt2F8CUsgVdgJ" width="378px;" /></span></b></div>
<div style="text-align: center;">
<b style="font-weight: normal;"><span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></b></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b><br /></span>
<br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<div style="line-height: 1.15;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But this is <span style="color: yellow;">only half </span>of what you want due to the fact that the definition of a full circle is not defined by a single mathematical function. You’d have to run through the loop again and generate the bottom half.</span></div>
<div style="line-height: 1.15;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
</span></div>
<div class="separator" style="clear: both; line-height: 1.15; text-align: center;">
<a href="https://lh5.googleusercontent.com/YOAUIr_Mn5TyQy4QUIvfHNWoYrSQifKBGb_WM2QBDZS6z3hGwvbMhz4vFFSw9DtjLP3mnknCPcG5F054LvQzR0MBeKpJRAzlW079dxm-biT9F9zEEEAPnfBn" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" height="217px;" src="https://lh5.googleusercontent.com/YOAUIr_Mn5TyQy4QUIvfHNWoYrSQifKBGb_WM2QBDZS6z3hGwvbMhz4vFFSw9DtjLP3mnknCPcG5F054LvQzR0MBeKpJRAzlW079dxm-biT9F9zEEEAPnfBn" width="349px;" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; line-height: 1.15; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; line-height: 1.15; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><code style="color: black; word-wrap: normal;"> // Bottom half generated by using negative value
float y = -Mathf.sqrt(radius * radius - x * x);
</code></span></span></pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<div style="line-height: 1.15; text-align: justify;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So it seems this method requires doing the full circles in 2 passes (2 for-loops). </span><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;">But that’s <span style="color: yellow;">not the biggest problem</span> here. Since we’re iterating by a constant value on the x direction (<b>0.1</b> in the example), we’ll end up with <b>y</b> values that are closer together near <b>x = 0</b> and <b>y </b>values that get increasingly further apart as we move toward <b>+-1</b>. You'll get a distribution looking something like this:</span></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><br /></span></span></div>
<div style="line-height: 1.15;">
<span style="font-family: Arial, Helvetica, sans-serif;">
</span></div>
<div class="separator" style="clear: both; line-height: 1.15; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzZdsk9ldZWCgZTDHkU8QItHjYJ-aF7NzqzQRRvXt-vXCSTIeDCmJXQE9wNwJKVBJDGs-D8trQExBc11ORgbLwGKnVeXhwjVRBOzSytz1Jq45M0JXNrkJlQ3WK7zIcmOkEE3-wBZ42Ol0/s1600/pointspread.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzZdsk9ldZWCgZTDHkU8QItHjYJ-aF7NzqzQRRvXt-vXCSTIeDCmJXQE9wNwJKVBJDGs-D8trQExBc11ORgbLwGKnVeXhwjVRBOzSytz1Jq45M0JXNrkJlQ3WK7zIcmOkEE3-wBZ42Ol0/s320/pointspread.png" width="320" /></span></a></div>
<div class="separator" style="clear: both; line-height: 1.15; text-align: center;">
<br /></div>
<div style="font-size: 15px;">
If you were to triangulate that you'd notice that it looks blocky toward the left and right and smooth toward the top. Are we happy with that?</div>
<div style="line-height: 1.15;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><br /></span>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><br /></span></span></div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYIfO5zE8ATPRCSp71snrlOmsCeP_sxlU9S7sMJw5aaxx76kr31HXtwqX9VyLnnQQQ6euwj6qYdfSQ7a33yFVPuHuahm_TGtYbnT_LQ6Y4drZSXORoG2CUKwsQPn4hphI41bNDClSpjgg/s1600/no.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYIfO5zE8ATPRCSp71snrlOmsCeP_sxlU9S7sMJw5aaxx76kr31HXtwqX9VyLnnQQQ6euwj6qYdfSQ7a33yFVPuHuahm_TGtYbnT_LQ6Y4drZSXORoG2CUKwsQPn4hphI41bNDClSpjgg/s1600/no.jpeg" /></span></a></div>
<b style="font-weight: normal;"><span style="font-family: Arial, Helvetica, sans-serif;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span>
</span></b><br />
<div style="font-size: 15px;">
<b style="font-weight: normal;"><span style="font-family: Arial, Helvetica, sans-serif;">We want something <span style="color: yellow;">evenly distributed</span>. More like this:</span></b></div>
<b style="font-weight: normal;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></span></b><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /></b>
</span><br />
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Arial, Helvetica, sans-serif; margin-left: 1em; margin-right: 1em;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9U2nnB0Fut-RU78fZ7o-ECQzU0JOvFdkVaRsKE5WDOvfCMTn0VONHnCm1uJqwp6hGILoUMr9Gzy5cFS-W-Rl6tofWni28szQrCkPAaL94GgXBbMFc-oU1-Eet3soAcJx7u7h1pnFxT4Q/s1600/pointspread-good.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9U2nnB0Fut-RU78fZ7o-ECQzU0JOvFdkVaRsKE5WDOvfCMTn0VONHnCm1uJqwp6hGILoUMr9Gzy5cFS-W-Rl6tofWni28szQrCkPAaL94GgXBbMFc-oU1-Eet3soAcJx7u7h1pnFxT4Q/s320/pointspread-good.png" width="320" /></a></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So let’s rethink this... This time, using sacred tools from the game developer’s toolbelt: </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: bold; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">vectors</span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. If you’re not already familiar with this <span style="color: yellow;">extremely important</span> concept, check out Khan Academy: (</span><a href="https://www.khanacademy.org/math/linear-algebra/vectors_and_spaces/vectors/v/linear-algebra--introduction-to-vectors" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://www.khanacademy.org/math/linear-algebra/vectors_and_spaces/vectors/v/linear-algebra--introduction-to-vectors</span></a><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">).</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Vectors will allow us to generate the vertex data in </span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: bold; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">one</span><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> convenient loop in an order that makes it easy to triangulate and even more importantly, our points will be evenly spaced out. The idea is to start with a single vector and rotate it by a constant angle to get the next point. We do this for the whole circle. This image sequence will give you the basic idea:</span></span><br />
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Arial, Helvetica, sans-serif; margin-left: 1em; margin-right: 1em;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6vCCycN_A0BHP-lUqHbNWygPJrdpP4V8SaEpMGDkb2PXkz2iG05GSpg6TVFx5xxWr5MbY8w49kJJ8dItb23R7cwhRFHhIqEk6ks0ibexY2DZWIPgWcQOJ8TqKVr4dQ72pyaCrP8AcAiM/s1600/layeredrotations.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6vCCycN_A0BHP-lUqHbNWygPJrdpP4V8SaEpMGDkb2PXkz2iG05GSpg6TVFx5xxWr5MbY8w49kJJ8dItb23R7cwhRFHhIqEk6ks0ibexY2DZWIPgWcQOJ8TqKVr4dQ72pyaCrP8AcAiM/s640/layeredrotations.png" width="480" /></a></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
<b style="font-weight: normal;"><br /></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
This will give <span style="font-family: Arial, Helvetica, sans-serif;"><span style="font-size: 15px; line-height: 1.15; white-space: pre-wrap;">us a set of points around the circle. But, in order to create triangles for this, we need just <span style="color: yellow;">one more point</span>. Take a second and make a guess where it should go. If you guessed that it is needed in the middle of the circle you got it. With one point in the center and a bunch of other points on the outside, we can then start carving this up <span style="color: yellow;">like slices of a pie</span>.</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Let’s get to the code:</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"><code style="color: black; word-wrap: normal;"> // The more verts, the more 'round' the circle appears
// It's hard coded here but it would better if you could pass it in as an argument to this function
int numVerts = 41;
Mesh plane = new Mesh();
Vector3[] verts = new Vector3[numVerts];
Vector2[] uvs = new Vector2[numVerts];
int[] tris = new int[(numVerts * 3)];
In the beginning we set up for everything we’ll need later. We get an array of Vector3 (3 floats) to use for every point as well as arrays for uv coordinates and triangles.
// The first vert is in the center of the triangle
verts[0] = Vector3.zero;
uvs[0] = new Vector2(0.5f, 0.5f);
float angle = 360.0f / (float)(numVerts - 1);
</code></span></span></pre>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here we create our center vertex as the first one in the array and we also figure out how big each slice of pie should be. The number of pieces of pie (triangle) is equal to the number of vertices - 1.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"><code style="color: black; word-wrap: normal;"> for (int i = 1; i < numVerts; ++i) {
verts[i] = Quaternion.AngleAxis(angle * (float)(i - 1), Vector3.back) * Vector3.up;
float normedHorizontal = (verts[i].x + 1.0f) * 0.5f;
float normedVertical = (verts[i].x + 1.0f) * 0.5f;
uvs[i] = new Vector2(normedHorizontal, normedVertical);
}
</code></span></span></pre>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here we iterate through each slice of pie in similar fashion to that image sequence shown above. In this code I’m starting with a vector pointing up and rotating it clockwise. This is a little different from the images above but it doesn’t matter so long as you start somewhere and rotate all the way around. You could choose other methods of rotation here but the Unity built in Quaternion is what I went with. If the rotation is a little mysterious to you let me know and I’ll write something up on it.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"><code style="color: black; word-wrap: normal;"> for (int i = 0; i + 2 < numVerts; ++i) {
int index = i * 3;
tris[index + 0] = 0;
tris[index + 1] = i + 1;
tris[index + 2] = i + 2;
}
</code></span></span></pre>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here we create all of our triangles. Each triangle with start with the vertex in the center and connect to 2 on the outside of the circle.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"><code style="color: black; word-wrap: normal;"> // The last triangle has to wrap around to the first vert so we do this last and outside the lop
var lastTriangleIndex = tris.Length - 3;
tris[lastTriangleIndex + 0] = 0;
tris[lastTriangleIndex + 1] = numVerts - 1;
tris[lastTriangleIndex + 2] = 1;
</code></span></span></pre>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span>
<br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is kind of a special case where we reuse a vertex so we save it for last and manually compute the final triangle.</span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span><br />
<div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"></span></span><br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIzJIN3HJ2hOVGxdYEfoT9BH6VGOENwCMHBZykcE0bc2XCLniBwkwFke5KfnDUqZvjxOH-mz3kwZ6mtQJ4YIvKXG4Ng5tZwybu4lpvwziiU0UsocW2-BpTH7iOjxY6uIRYSVDAqK-tS9M4/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;"><code style="color: black; word-wrap: normal;"> // The last triangle has to wrap around to the first vert so we do this last and outside the lop
var lastTriangleIndex = tris.Length - 3;
tris[lastTriangleIndex + 0] = 0;
tris[lastTriangleIndex + 1] = numVerts - 1;
tris[lastTriangleIndex + 2] = 1;
</code></span></span></pre>
<span style="font-size: 15px; line-height: 17px; white-space: pre-wrap;"><span style="font-family: Arial, Helvetica, sans-serif;">
</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></b>
</span>
<br />
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Make sure you give the mesh everything you just computed and that’s it! Now you’re thinking with portal....errr, ummm, vectors!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can <span style="color: yellow;">download the source package</span> for everything <a href="http://www.realitymeltdown.com/TipsAndTricks/procedural_geometry-circle.unitypackage" target="_blank">here</a>.</span></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b style="font-weight: normal;"><br /></b></span>
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span>
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span>Anonymoushttp://www.blogger.com/profile/00096991192172366694noreply@blogger.com0tag:blogger.com,1999:blog-8582915394329547660.post-16658894984634187492013-05-17T12:20:00.000-07:002015-06-30T16:09:58.389-07:00Camera ShakeBefore we dive in, I recommend you watch the video <a href="http://www.youtube.com/watch?v=cDxQEFP-fhM&feature=youtu.be" target="_blank">here</a>.<br />
First up, let's take a look at how the randomized camera shake is implemented:<br />
<br />
<script src="https://gist.github.com/insominx/f3acce17108d0a2e4619.js"></script><br />
The shake animation all takes place within a coroutine which allows us to keep our timing variables local to this function as opposed to declaring them for the entire class. The shake can be configured to last any length of time using the duration variable and this number will be used to determine what percentage of that duration has elapsed (0% to 100% or in this case 0.0 to 1.0). If you haven't made best friends with math yet I'll do my best to help you visualize it. Here's what we're doing:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3x7ErFvsARU4QCMCf-jxq_eAst8jON9J2OaEpQi0Pz_SspXYKhYDfRbEoMwesKO9axtsHXu8XeHDeH8VAO8BCTvzsDYM2NpisKPWlJUZiMaFRPjqetxF91q6f7O6zBP8t7oeK1nRnQ-E/s1600/percentComplete.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3x7ErFvsARU4QCMCf-jxq_eAst8jON9J2OaEpQi0Pz_SspXYKhYDfRbEoMwesKO9axtsHXu8XeHDeH8VAO8BCTvzsDYM2NpisKPWlJUZiMaFRPjqetxF91q6f7O6zBP8t7oeK1nRnQ-E/s1600/percentComplete.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
The graph above corresponds to having set a duration of 2. The x axis represents the time elapsed and the y axis is the percent complete. The basic equation is percentComplete = timeElapsed / 2.0. It's important to note that percentComplete is 0 at timeElapsed equal to 0 and percentComplete is equal to 1 at timeElapsed equal to 2.<br />
<br />
So now we have a way to determine how far we are through the shake animation. We care for 2 reasons. One is we need to know when to stop shaking and the other is that we'll want to gradually fade the shake out (the damper variable) but we'll get back to that later.<br />
<br />
Next we want to compute x and y values for how far we should move. The idea is that our shake is going to be centered around the camera's starting position and when we're done shaking we should be back where we started. With that in mind the x and y values are just going to be offsets from the camera's original position.<br />
<br />
We make that calculation like this:<br />
<br />
<script src="https://gist.github.com/insominx/93b96036b6e72a2a8a12.js"></script><br />
The Random.value property will give you something between 0 and 1. It's always a positive number. Since we're going to be offset from a starting value, we want to be able to offset in either direction which means what we want is a random value that can be negative as well as positive. So how about -1 to 1. That's what that equation does for you and its graph looks like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxVXHDxVKclT7LT9sc-KNVrwgiRd2dI1vftyAydogxQ3jloCKDhxxwKBw6_hyphenhyphen0Mp9AqL63298sBUYQ25-Wziumi_qmgHoTZGb4xEql7L1DcJ0plsg7MRRtoChBLEIB47ojGMqOjrhszTQ/s1600/remapcentered.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxVXHDxVKclT7LT9sc-KNVrwgiRd2dI1vftyAydogxQ3jloCKDhxxwKBw6_hyphenhyphen0Mp9AqL63298sBUYQ25-Wziumi_qmgHoTZGb4xEql7L1DcJ0plsg7MRRtoChBLEIB47ojGMqOjrhszTQ/s1600/remapcentered.png" width="400" /></a></div>
<br />
So now if you get a random value of 0.5, the value will be remapped to 0. Now is a good time to explain why we're choosing values that either go from 0 to 1 or -1 to 1. Let's say that shaking up to a maximum of 1 unit wasn't enough and we wanted to be able to shake as far as 5 units. By having a value with a maximum of 1, we can just multiply it by what we want (in this case). This is shown in the code:<br />
<br />
<br />
<script src="https://gist.github.com/insominx/f3bd18e69e7478e58c27.js"></script>
But it's also being multiplied by that damper thing too. Ok, let's cover that. Since we want to the camera shake to end where it started but we don't want it to pop back afterward, we have to smoothly bring it back. That's what damper is all about.<br />
<br />
For the first part of the shake animation, the damper is intended to do basically nothing. That shows up in the math when damper is equal to 1 because anything times 1 is itself. Then we the animation is getting closer to finishing, it gradually starts multiplying the offsets by a number less than 1 until at the very end is multiplies it be 0. That brings it back to it's original position. Here's what the graph looks like:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEig-OjDuuyaK6ElhtfdN_Hu_88lS4DvF-DrlRzl42ILEwW9aQr4jjXB6CUa3bvWV17AKBvAoGxWqi-Mo2N6txxX9FSZMi7OQJqUxn0unZ4Syv8uOwPPX7A4n_C5HglrC2D9ClcRdDVKKtk/s1600/damper.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="343" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEig-OjDuuyaK6ElhtfdN_Hu_88lS4DvF-DrlRzl42ILEwW9aQr4jjXB6CUa3bvWV17AKBvAoGxWqi-Mo2N6txxX9FSZMi7OQJqUxn0unZ4Syv8uOwPPX7A4n_C5HglrC2D9ClcRdDVKKtk/s1600/damper.png" width="400" /></a></div>
<br />
That covers most of what you need to know to understand the other variations. The main differences are just that the other version using something better than Random to produce the offset values.<br />
<br />
You can download the Unity package shown in the video <a href="https://drive.google.com/file/d/0B97tvqwCatoZX3lVZ0VhN3pja2s/view?usp=sharing">here</a>. Enjoy!<br />
<br />
PS. If you improve upon my code in any way please let me know! One thing I could think of would be to make the shake more strongly favor a particular direction. For instance a ball hitting a wall might want to shake more in the direction it was traveling when it hit the wall.Anonymoushttp://www.blogger.com/profile/00096991192172366694noreply@blogger.com0