tag:blogger.com,1999:blog-3569251764466250132024-03-12T20:29:45.967-07:00Melissa Gill-- Software EngineerAnonymoushttp://www.blogger.com/profile/01883805178932575631noreply@blogger.comBlogger7125tag:blogger.com,1999:blog-356925176446625013.post-1281551260142268172014-04-24T15:55:00.002-07:002014-04-24T15:55:42.095-07:00The Blob Game DebacleIn physics, after successfully implementing basic sphere collision detection and resolution, we were tasked with using this collision system to simulate the behavior of both rods (objects always the same distance apart) and cables (objects never further apart than cable length). In its most basic form, I got these things working pretty well, as you can see below:<br />
<div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br /></div>
<div>
Examples of Cables and Rods respectively:</div>
<div class="" style="clear: both; text-align: center;">
</div>
<div style="text-align: left;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='240' height='199' src='https://www.blogger.com/video.g?token=AD6v5dw9qqCD7dOjOuabmUw8gLfIMHpXJSTZuuDBXSTWY-TRhwI_wmPnlQloV0T3Y0w-KQpUXdkpfpcdN6GNWIgOZw' class='b-hbp-video b-uploaded' frameborder='0'></iframe><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='240' height='199' src='https://www.blogger.com/video.g?token=AD6v5dz1cgRh1pvU4rk1IJcuqBjggGZqTUEvyGpRylh12oOfoL3VhaMZVNNGHk7dyYbSEbUEztdknT0dmn1dMMoU0w' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br />
<br />
The problems started when I tried to link together four or more particles with rods to create larger object structures. The rods would become too much displaced when forces were applied to the particles and the system trying to resolve these rod collisions would make the object rapidly flail around before completely exploding itself. Obviously this is not ideal behavior, and it made our next task quite frustrating.</div>
<br />
<div>
<br /></div>
<div>
The assignment was to create a ball-like structure using rods and particles that could be controlled by applying force to the structure's uppermost node. I could get a triangle to do this quite well, but anything beyond that became unstable. We were also supposed to implement editable level features made from springs, rods, cables, etc which this blob-ball structure could interact with, and collectible items.</div>
<div>
<br /></div>
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdpt9LU32w0P3_AUH0oSmfWRnXOlrrGxuzIS4mOmg_zCKrATDzdgdx62BDfiCO-v9AYmu3y_pUSNxdT07zsA3hunsCfg2lsb08cRcsdpzT5z4bWzgsFsS5Vgy0V5_pXGDGmV2l8fApxmq8/s1600/physicsman.PNG" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdpt9LU32w0P3_AUH0oSmfWRnXOlrrGxuzIS4mOmg_zCKrATDzdgdx62BDfiCO-v9AYmu3y_pUSNxdT07zsA3hunsCfg2lsb08cRcsdpzT5z4bWzgsFsS5Vgy0V5_pXGDGmV2l8fApxmq8/s1600/physicsman.PNG" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">White connections are rods,<br />
black are springs</td></tr>
</tbody></table>
I was able to accomplish these things with some degree of success. Due to the instability of creating a structure entirely of nodes and rods, I created one instead with a center node surrounded by border nodes. The center node is connected to the border nodes by rods so that the structures would keep its form, but the border nodes are connected to one another by springs around the outside edges so that the object has more give and applying force to the nodes does not cause such a shot to the whole object. This was relatively successful, and I was able to get some pretty fun and gloriously blobby motion working.<br />
<br />
For the rest of the game elements I decided to go with a kind of puzzle game driven by time. The layout includes walls of nodes strung together by rods. The nodes can be assigned to be either anchor points which have an increased mass so they are less movable, or basic wall pieces that can be pushed out of the way by running into them. They can also be made collectible, with beneficial (yellow) collectibles increasing the force applied to the player for movement, thus increasing speed, and detrimental (red) ones decreasing the applied force.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqbI0-aoQB07mESEjRTr81Yn5S6PtZBF_khXmFkvlZVoryOvGqritywn9hdVm7t66McPJPxdcckbnion2orK5ATBOuQxTRavJ3KaAeHC0B5qu_jOcCRkHw5SaKSe6yFTvVuubDLi0xLupM/s1600/levelEditor.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqbI0-aoQB07mESEjRTr81Yn5S6PtZBF_khXmFkvlZVoryOvGqritywn9hdVm7t66McPJPxdcckbnion2orK5ATBOuQxTRavJ3KaAeHC0B5qu_jOcCRkHw5SaKSe6yFTvVuubDLi0xLupM/s1600/levelEditor.PNG" height="270" width="320" /></a>I set up a simple system to load levels in from a very basic grid-based text file. It is set up with two grids whose layout should be the same. The first grid indicates the basic layout of anchor points and basic wall nodes and the second indicates which of the nodes should be collectibles and which type they should be.<br />
<br />
In layout section of the file zeros indicate empty spaces, twos indicate anchor points, and ones indicate normal walls. In the type section Xs indicate no type, Es indicate detrimental collectibles, and Cs indicate beneficial ones.<br />
<br />
The player can flip gravity freely throughout the level, as well as move left and right. Using this the player must navigate to the end of the puzzle while the camera slowly pans right. If the player goes off screen to the left they must restart the level. In the test setup all the walls are solid, but they have collectibles in the middles of them so the player must collect them to break the link so they can push the loose ends of the wall to the side and pass through.</div>
<br />
<iframe height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJbk1lemxNTnQxeGc/preview" width="640"></iframe><br />
<br />
Obviously one of my biggest challenges with this project was getting rod structures to function with stability, but it was also a challenge, with the code base I had, to remove nodes and things completely. The system I had was very modular and each node was entirely unaware of all the things associated with it, such as the rod colliders, the sphere collider, any gravity or spring forces, etc, so any removal had to be cleared and cleaned up across multiple systems and the object itself could not handle its own cleanup. If I were to build a system like this again, I would keep this in mind and try to make the individual nodes a bit more self aware.<br />
<br />
Although some of the functionality and behavior isn't quite working as intended (as seen below) I am really quite happy with the system behind it (aforementioned quirks aside). I feel that I manage all the different elements well and it makes it very easy to apply different forces, collision types, and behaviors to nodes in any combination and have the system just manage itself.<br />
<br />
<iframe height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJM2o0U2YwV0E2Q1U/preview" width="640"></iframe>Anonymoushttp://www.blogger.com/profile/01883805178932575631noreply@blogger.comtag:blogger.com,1999:blog-356925176446625013.post-88991905083340291872014-04-23T03:06:00.003-07:002014-04-23T09:02:15.508-07:00Voxelizing Meshes<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEig1bxD9w7mmNxYoNE8Ha1aCU9DB1oBmmk-G9OZRN8K-osNidm1U7nViUQXFB3VxTyHsEfvRpjT2jSPKr9f5TTce4smbvEiljjeNtjaXHDovqstEYL6ysgVwtvKWrV5bYykW_s4tS3BlXJg/s1600/wholeObject_teapot.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/AVvXsEig1bxD9w7mmNxYoNE8Ha1aCU9DB1oBmmk-G9OZRN8K-osNidm1U7nViUQXFB3VxTyHsEfvRpjT2jSPKr9f5TTce4smbvEiljjeNtjaXHDovqstEYL6ysgVwtvKWrV5bYykW_s4tS3BlXJg/s1600/wholeObject_teapot.PNG" height="121" width="200" /></a>This is a continuation of my <a href="http://mlssagll.blogspot.com/2014/03/self-regenerating-destructible-objects.html">self-regenerating destructible object project</a>; the base voxel object structure referenced here is explained in more detail in my previous post.<br />
<br />
Once I got the basic system of units that could be deformed and would gradually regenerate themselves, the next step was to implement a system to import custom meshes and turn them into these voxel units, or "voxelize" them. Basically this is just taking a model and filling it up with little boxes that can be destroyed individually. In the clip below you see a cat where the left half is the original model and the right half is the voxelized version of it:<br />
<br />
<iframe height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJRUpWQmkxbzJyQzQ/preview" width="640"></iframe><br />
<br />
In my voxel object system, every collection of voxels that make up one object, or <code>VoxelUnit</code>, is made up of a bounding box full of voxels that can be activated and deactivated as needed. Even something like a sphere is technically a full box of voxels, but the voxels that are not part of the sphere are made completely inactive and it's as if they were not a part of the shape.<br />
<br />
Although each step is very involved, there are, conceptually, only a few steps in actually voxelizing a model:<br />
<ul>
<li>import the model into a usable structure</li>
<li>calculate the bounding box of the model and create an empty <code>VoxelUnit</code></li>
<li>activate the voxels that intersect with the model's faces </li>
<li>fill in the middle of the model if desired</li>
</ul>
<div>
I only implemented functionality to import .objs with triangular faces, but allowing for other formats should mostly just affect how the model is imported. It may also affect the detection of voxels intersecting faces if the faces are quads or a mixture of quads and tris.</div>
<div>
<br /></div>
<div>
I set up a simple struct to hold all of the mesh data in a way that would be easily accessible:</div>
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
struct Obj<br />
{<br />
vector<Vector3> vertices;<br />
//each tri is a vector of length 3 of the actual vertex values<br />
//rather than a vertex index for ease of access<br />
vector<vector<Vector3>> tris;<br />
//the normal for each tri<br />
vector<Vector3> normals;<br />
//bounding box dimensions<br />
Vector3 boxDimensions;<br />
//the left, bottom, back corner of the model<br />
Vector3 bottomLeftBack;<br />
}<br />
<br />
</code></div>
<br />
To determine the <code>boxDimensions</code> and <code>bottomLeftBack</code> I keep track of the highest and lowest values in each dimension of the points as the bottom, left, back corner and top, right, front corner of the bounding box. These corner points do not necessarily correspond to a vertex, just the highest and lowest value of any vertex in the object in each dimension. Once all the vertices are loaded in, the <code>boxDimensions</code> can be found by subtracting the bottom, left, back corner from the top, right, front corner. It is important to hold onto <code>bottomLeftBack</code> for later to align our <code>VoxelUnit</code> with the model vertices.<br />
<br />
The face normals will also be useful later for determining intersection with faces. You may be able to read them in from your model file, but I am just calculating them to be safe; to do that you simply find the cross product of the vectors that represent two of the sides and share a starting point:<br />
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
for(int i=0;i<obj->tris.size();i++)<br />
{<br />
Vector3 u = obj->tris[i][1] - obj->tris[i][0];<br />
Vector3 v = obj->tris[i][2] - obj->tris[i][0];<br />
<br />
Vector3 norm = u.Cross(v);<br />
norm.Normalize();<br />
obj->normals.push_back(norm);<br />
}<br />
<br />
</code></div>
<br />
Once you have the model data in an accessible format it is time to create a <code>VoxelUnit</code> the size of the <code>Obj</code> <code>boxDimensions</code>. To do this I set up an additional constructor for <code>VoxelUnit</code> that takes in an <code>Obj*</code> and a voxel size so that it can construct the model using the <code>Obj</code> to the level of detail as determined by the voxel size.<br />
<br />
The first thing that needs to be done is, given the dimensions of the bounding box of the model, determine how many voxels across the object will be in each direction. This is pretty straightforward, and very similar to determining it based on just dimensions, but you have to be a bit more careful and conservative about tweaking the dimensions to come to an even voxel count in each direction. Because the object is based on a model, we want to make sure the new bounding box will fully encompass the model.<br />
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
VoxelUnit::VoxelUnit(Obj* obj,float voxelSize)<br />
{<br />
//just get the original necessary dimensions<br />
mDimensions=obj->boxDimensions;<br />
mVoxelSize=voxelSize;<br />
//determine the number of voxels across each dimension will fit in the bounding box<br />
mVoxelsDim=mDimensions/mVoxelSize;<br />
//number of voxels must be an integer<br />
//using the ceiling function so as not to round down and clip off parts of the model<br />
mVoxelsDim=Vector3(ceil(mVoxelsDim.x),ceil(mVoxelsDim.y),ceil(mVoxelsDim.z));<br />
//calculate new actual dimensions<br />
mDimensions=mVoxelsDim*mVoxelSize;<br />
//set the position to the center of the object for easier intersection checking<br />
mPosition=obj->bottomLeftBack+(obj->boxDimensions/2);<br />
}<br />
<br />
</code></div>
<br />
Next you need to populate your <code>Voxel</code> array; this is the most involved and time-consuming part of the process because to determine whether or not each <code>Voxel</code> is active I am checking finding each edge of each <code>Voxel</code> and checking them against faces until it either finds one it intersects with, or runs out of faces to check.<br />
<br />
For each <code>Voxel</code> at index x,y,z:<br />
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
//set a temporary depth and timer value<br />
mVoxels[x][y][z].depth=EMPTY;<br />
mVoxels[x][y][z].regenTimer=0;<br />
<br />
//find the middle position of the voxel<br />
Vector3 pos=mPosition-(mVoxelsDim*mVoxelSize/2);<br />
Vector3 index(x,y,z);<br />
pos+=index*mVoxelSize;<br />
<br />
//find the upper and lower bounds of the individual voxel<br />
Vector3 rightTopFront=pos+(Vector3(1,1,1)*(mVoxelSize/2));<br />
Vector3 leftBottomBack=pos-(Vector3(1,1,1)*(mVoxelSize/2));<br />
<br />
//holder for the edges<br />
vector<vector<Vector3>> edges;<br />
//holder for a single edge with two Vector3 endpoints<br />
vector<Vector3> edge;<br />
<br />
//find top right edge<br />
edge.push_back(rightTopFront);<br />
edge.push_back(Vector3(rightTopFront.x,rightTopFront.y,leftBottomBack.z));<br />
edges.push_back(edge);<br />
edge.clear();<br />
<br />
//find bottom right edge<br />
edge.push_back(Vector3(rightTopFront.x,leftBottomBack.y,rightTopFront.z));<br />
edge.push_back(Vector3(rightTopFront.x,leftBottomBack.y,leftBottomBack.z));<br />
edges.push_back(edge);<br />
edge.clear();<br />
<br />
//continue like this for each of the twelve edges<br />
<br />
</code></div>
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSXmf20tyUEnLnBM1pkag1LG5uoFKAWMIbqTfco-7bLSLsxcQQdCf8g3noCQy_8AfojWO7THE4McSteWKSj6m5BkP0rX-j0I09rh5eljmKdJhDy4nBKjtsjo_SyGerLIL55rOBByUrdy7d/s1600/charizard.PNG" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSXmf20tyUEnLnBM1pkag1LG5uoFKAWMIbqTfco-7bLSLsxcQQdCf8g3noCQy_8AfojWO7THE4McSteWKSj6m5BkP0rX-j0I09rh5eljmKdJhDy4nBKjtsjo_SyGerLIL55rOBByUrdy7d/s1600/charizard.PNG" height="153" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Who's that Pokemon?</td></tr>
</tbody></table>
Originally, once I had found all the <code>Voxel</code>'s edges I checked each edge against every face in the model until one of them intersected or I ran out of faces. As you might imagine, that was very very very time consuming. To cut down on this time, I decided to generate an index range for each <code>Voxel</code> edges would only be checked against faces whose bounding boxes in terms of <code>Voxel</code> indices contained that <code>Voxel</code>. This was incredibly effective at cutting down time. A low quality (high voxel size) import of my test teapot model went from taking upwards of half and hour to taking under a minute. This allowed me to decrease the voxel size, thus increasing the import quality, while keeping the import time reasonable.<br />
<br />
<br />
To find these index-based bounding boxes for each face, I first found the face's true-coordinate bounding box in very much the same way I did with the entire model, and then I used the <code>VoxelUnit</code>'s traits to get the bounding box in terms of object-specific indices:<br />
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
//create a local structure to hold the limits<br />
struct Limits<br />
{<br />
Vector3 upper;<br />
Vector3 lower;<br />
};<br />
<br />
//vector to hold the limits for all the faces<br />
//want to hold onto them so they don't need to be recalculated<br />
vector<Limits> indexLims;<br />
<br />
//find limits for every face<br />
for(int i=0;i<obj->tris.size();i++)<br />
{<br />
Limits lim;<br />
//set limits to the upper and lower limits of the whole VoxelUnit<br />
lim.upper=mPosition-(mDimensions/2);<br />
lim.lower=mPosition+(mDimensions/2);<br />
<br />
//narrow down to the limits of the actual limits of just the one face<br />
for(int j=0;j<obj->tris[i].size();j++)<br />
{<br />
if(obj->tris[i][j].x>lim.upper.x)<br />
lim.upper.x=obj->tris[i][j].x;<br />
if(obj->tris[i][j].x<lim.lower.x)<br />
lim.lower.x=obj->tris[i][j].x;<br />
<br />
if(obj->tris[i][j].y>lim.upper.y)<br />
lim.upper.y=obj->tris[i][j].y;<br />
if(obj->tris[i][j].y<lim.lower.y)<br />
lim.lower.y=obj->tris[i][j].y;<br />
<br />
if(obj->tris[i][j].z>lim.upper.z)<br />
lim.upper.z=obj->tris[i][j].z;<br />
if(obj->tris[i][j].z<lim.lower.z)<br />
lim.lower.z=obj->tris[i][j].z;<br />
}<br />
<br />
//the bottom, left, back corner of the VoxelUnit<br />
Vector3 bottomCorner=mPosition-(mDimensions/2);<br />
<br />
//find index values at the limits<br />
lim.upper-=bottomCorner;<br />
lim.lower-=bottomCorner;<br />
lim.upper/=mVoxelSize;<br />
lim.lower/=mVoxelSize;<br />
<br />
//indices must be integers<br />
lim.lower=Vector3((int)lim.lower.x,(int)lim.lower.y,(int)lim.lower.z);<br />
//be conservative with upper limit so as to not cut off any results<br />
lim.upper=Vector3(ceil(lim.upper.x),ceil(lim.upper.y),ceil(lim.upper.z));<br />
indexLims.push_back(lim);<br />
}<br />
<br />
</code></div>
<br />
After having determined the index bounds for each face, a quick check to make sure the current <code>Voxel</code> index is within the face's index bounds before more in-depth checking can be put in place to significantly cut down on the voxelization time:<br />
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
//for each Voxel at index x,y,z<br />
<br />
for(int i=0;i<edges.size();i++)<br />
{<br />
bool collides=false;<br />
//check each face<br />
for(int j=0;j<obj->tris.size();j++)<br />
{<br />
//if the Voxel is outside of the face index bounds, skip this face<br />
if(x>indexLims[j].upper.x || x<indexLims[j].lower.x<br />
|| y>indexLims[j].upper.y || y<indexLims[j].lower.y<br />
|| z>indexLims[j].upper.z || z<indexLims[j].lower.z)<br />
continue;<br />
<br />
//check triangle/segment collision to see if edge intersects face<br />
collides=segmentTriangleCollision(obj->tris[j],<br />
obj->normals[j],<br />
edges[i]);<br />
//if it does intersect, stop checking faces<br />
if(collides)<br />
break;<br />
}<br />
if(collides)<br />
{<br />
//fill it in if it's touching the model<br />
mVoxels[x][y][z].depth=CENTER;<br />
//voxel already active, stop checking edges<br />
break;<br />
}<br />
}<br />
<br />
</code></div>
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix5tNMMbKIpsk5sGwzTbRaM2YOJuNSPcuPUA6lDw0ehoBnmmOsPbiB5m6URfGTocOMR7irFuObvnEHAvVZgOlJAlCojfjHZdDapQ0i2rbM_L9f19IkFmfnDfFGj5E3x9HgwD7x3M_WDCIV/s1600/hollowTeapot.PNG" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix5tNMMbKIpsk5sGwzTbRaM2YOJuNSPcuPUA6lDw0ehoBnmmOsPbiB5m6URfGTocOMR7irFuObvnEHAvVZgOlJAlCojfjHZdDapQ0i2rbM_L9f19IkFmfnDfFGj5E3x9HgwD7x3M_WDCIV/s1600/hollowTeapot.PNG" height="138" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Hollow teapot</td></tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-zhT-JEC6Bej6XxXkGlu7-jq2Ww4HfVDo2Llj37aMgze10cLHGmHScBHgI5E_ZSgP0Hai2inTg4xm4FfLPsS4yOylvVzKq1fpZMC7sl6YuLWhyphenhyphencAgAUQgHJ_B_06wYKf3DIvAXxHl06Tx/s1600/solidTeapot.PNG" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-zhT-JEC6Bej6XxXkGlu7-jq2Ww4HfVDo2Llj37aMgze10cLHGmHScBHgI5E_ZSgP0Hai2inTg4xm4FfLPsS4yOylvVzKq1fpZMC7sl6YuLWhyphenhyphencAgAUQgHJ_B_06wYKf3DIvAXxHl06Tx/s1600/solidTeapot.PNG" height="170" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Teapot filled in</td></tr>
</tbody></table>
By reassigning <code>Voxel</code>s that intersect with the model faces you will end up with a shell of the model. It will look like a voxelized version of the mesh until part of it is destroyed at which point you will see that it is hollow. This may be what you're going for in some cases, but I really was hoping to create solid objects. In order to do this I go through the newly generated <code>Voxel</code>s and reevaluate each <code>EMPTY</code> one. This involves checking to see whether there is an active <code>Voxel</code> in both directions along each axis going through the <code>Voxel</code> being looked at. If there is an active one at some point in every direction then that currently empty <code>Voxel</code> is actually in the middle of the object and should be active.<br />
<br />
This solution is not without flaws, though. This will fill in any intentional holes in the model as well in any place which is completely encased in the rest of the object. Because of this, I have left the option of leaving the object hollow.<br />
<br />
Hollow Object:<br />
<iframe height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJdGhRTWlSZEhLajQ/preview" width="640"></iframe><br />
<br />
<br />
Solid Object:<br />
<iframe height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJSnJVZVJPZVdobTg/preview" width="640"></iframe><br />
<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZQRobHpE_SIU0v5-Wnpq4OUMIy-pDoVQIQNr8Mzk_z0oAW8R_hqKEov9Pi_8mvwwlvKVtQvPlC0T-Sct7bCAyObiQiEIQC5Lql15Ey1hoQLdGQ7iyCntLsxnVlyu8lm6TgkOu3ZBjx-H0/s1600/inEditor2.PNG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZQRobHpE_SIU0v5-Wnpq4OUMIy-pDoVQIQNr8Mzk_z0oAW8R_hqKEov9Pi_8mvwwlvKVtQvPlC0T-Sct7bCAyObiQiEIQC5Lql15Ey1hoQLdGQ7iyCntLsxnVlyu8lm6TgkOu3ZBjx-H0/s1600/inEditor2.PNG" height="200" width="135" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">A sheet of voxelized cat.</td></tr>
</tbody></table>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN0cRqMu41x6UPZRJbWEqLCcbvF5iyvvvKwVHc8tuLxo2x_8Zq0BuxTAd48tSLIYfPyTeKIH5y3DH-Bnmzu_BkczgXL8_qtiNrcUPNbLJ3oHysITIAl77D70YRv2cCfR7DhgfQmH6m1bsr/s1600/inEditor1.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/AVvXsEjN0cRqMu41x6UPZRJbWEqLCcbvF5iyvvvKwVHc8tuLxo2x_8Zq0BuxTAd48tSLIYfPyTeKIH5y3DH-Bnmzu_BkczgXL8_qtiNrcUPNbLJ3oHysITIAl77D70YRv2cCfR7DhgfQmH6m1bsr/s1600/inEditor1.PNG" height="320" width="65" /></a>In order to avoid having to re-voxelize a mesh every time I wanted to use it, I implemented basic save an load functionality. Each voxelized object file has a header that states the dimensions of the bounding box of the object, and then a list of yz sheets for each layer of x as shown int the picture. Being able to save out these voxelizations also allows the user to edit the voxelized objects; they could fix any area that they are unhappy with how its been filled in, or manually fill in certain areas of the object. Mostly, though, this save and load functionality is convenient because loading a pre-voxelized object is magnitudes faster than voxelizing one on the go.<br />
<br />
<br />
<br />
<br />
Check back for more updates on this project. I plan to continue it by adding more robust, non-destructive collisions, so the objects could actually be used as terrain or other mobile assets. I also plan to, at some point, get most of the calculations running through the GPU using OpenCL for increased processing speed and efficiency.Anonymoushttp://www.blogger.com/profile/01883805178932575631noreply@blogger.comtag:blogger.com,1999:blog-356925176446625013.post-72520763543776009462014-03-16T11:47:00.001-07:002014-03-16T13:54:59.002-07:00Physics Force RegistryThis steps through how to set up the basic elements of a force registry system. This kind of system creates and manages forces and makes it easy to implement different kinds of physics behaviors such as acceleration due to gravity, planetary orbits, or spring motion simply by creating a variety of simple force-generating behaviors and applying them to basic units. To create this system I used OpenGL (freeglut) and my own <a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/Vector3.cpp" target="_blank">Vector3</a> class with basic functionality. This system does not handle collision, but would not be difficult to integrate with a collision system.<br />
<br />
The most basic element of this system is the <code>ForceGenerator</code>. This is a virtual base class that should be extended for each specific type of force needed. It is registered with a unit and is used to calculate the correct force and apply that force to the unit. The base class is very simple, but different members may be needed for more complex forces.<br />
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/ForceGenerator.h" target="_blank">ForceGenerator.h</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
class ForceGenerator<br />
{<br />
float Duration;<br />
virtual void updateForce(Unit* unit)=0;<br />
}<br />
<br />
</code></div>
<br />
<code>updateForce(Unit* unit)</code> is where the force is calculated and applied to <code>unit</code> and <code>Duration</code> indicates an amount of time this force should be applied. If you want a force to be applied forever setting duration to <code>FLT_MAX</code> and not decrementing the time if it is set to this would allow the <code>ForceGenerator</code> to never be removed from the registry.<br />
<br />
One use for a <code>ForceGenerator</code> would be to create simple spring motion. With a simple <code>ForceGenerator</code> you can get fairly complex and convincing behavior with very little code:<br />
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/Spring.h" target="_blank">Spring.h</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
class Spring:public ForceGenerator<br />
{<br />
float RestLength;<br />
float SpringConstant;<br />
Unit* BaseUnit;<br />
<br />
Spring(Unit* base,float springConstant=1,float restLength=0);<br />
void updateForce(Unit* unit);<br />
}<br />
<br />
</code></div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/Spring.cpp" target="_blank">Spring.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
Spring::Spring(Unit* base,float springConstant,float restLength)<br />
{<br />
BaseUnit=base;<br />
SpringConstant=springConstant;<br />
RestLength=restLenght;<br />
<br />
Duration=FLT_MAX; //this force will stay forever<br />
}<br />
<br />
void Spring::updateForce(Unit* unit)<br />
{<br />
Vector3 dir = BaseUnit->Position - unit->Position;<br />
//get the direction of the force to be applied<br />
<br />
float dist = dir.Magnitude();<br />
//get the distance between unit and BaseUnit<br />
<br />
float offset = RestLength - dist;<br />
//get the offset from the rest length for determining the magnitude of the force<br />
<br />
dir.Normalize();<br />
Vector3 force = dir * (-SpringConstant * offset);<br />
//calculate the spring force<br />
<br />
unit->addForce(force);<br />
}<br />
<br />
</code></div>
<br />
By registering this <code>Spring</code> with a <code>Unit</code> you will get anchored spring motion with the anchor being the <code>BaseUnit</code>. If you would like the <code>BaseUnit</code> to be affected by the spring as well, you would register another <code>Spring</code> force with the <code>BaseUnit</code> and the <code>BaseUnit</code> of the <code>Spring</code> set to the <code>Unit</code> that the last <code>Spring</code> was registered with.<br />
<br />
<span style="font-size: x-small;">You can view my code for basic gravity here ( <a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/Gravity.h" target="_blank">Gravity.h</a> <a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/Gravity.cpp" target="_blank">Gravity.cpp</a> )</span><br />
<span style="font-size: x-small;">or for planetary gravity here ( <a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/PlanetGravity.h" target="_blank">PlanetGravity.h</a> <a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/PlanetGravity.cpp" target="_blank">PlanetGravity.cpp</a> ).</span><br />
<br />
This <code>ForceGenerator</code> is queued for processing with a <code>Unit</code> pointer with a <code>ForceRegistration</code> which is a simple struct:<br />
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/ForceRegistration.h" target="_blank">ForceRegistration.h</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
struct ForceRegistration<br />
{<br />
Unit* unit;<br />
ForceGenerator* force;<br />
}<br />
<br />
</code></div>
<br />
The <code>unit</code> in the <code>ForceRegistration</code> is the one that will be passed to <code>force->updateForce()</code>. The Unit class at its most basic needs to contain the following:<br />
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/RigidbodyUnit.h" target="_blank">Unit.h</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
class Unit<br />
{<br />
Vector3 Position;<br />
Vector3 Forces; //Force accumulator<br />
Vector3 Velocity;<br />
<br />
float Mass;<br />
float InverseMass;<br />
float Radius;<br />
<br />
void update();<br />
void draw();<br />
void addForce(Vector3 force);<br />
}<br />
<br />
</code></div>
<br />
This <code>Unit</code> class is specifically for spherical units for simplicity, but <code>Radius</code> could be replaced with some kind of dimensions variable for other shapes. Also, I am storing both the mass and the inverse mass so that they do not have to be calculated each frame.<br />
<br />
Now that we have each of the basic components involved in the force registry system we need to create the actual <code>ForceRegistry</code>. The <code>ForceRegistry</code> is entirely just a <code>ForceRegistration</code> holder and updater.<br />
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/ForceRegistry.h" target="_blank">ForceRegistry.h</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
class ForceRegistry<br />
{<br />
vector<forceregistration> ActiveForces;<br />
<br />
void add(ForceRegistration* force);<br />
void clear();<br />
void remove(int index);<br />
void updateForces();<br />
}<br />
<br />
</code></div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/ForceRegistry.cpp" target="_blank">ForceRegistry.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
void ForceRegistry::add(ForceRegistration* force)<br />
{<br />
ActiveForces.push_back(force);<br />
}<br />
<br />
void ForceRegistry::clear()<br />
{<br />
for(unsigned int i=0;i<ActiveForces.size();i++)<br />
{<br />
delete ActiveForces[i];<br />
}<br />
ActiveForces.clear();<br />
}<br />
<br />
void ForceRegistry::remove(int index)<br />
{<br />
delete ActiveForces[index];<br />
ActiveForces.erase(ActiveForces.begin()+index);<br />
}<br />
<br />
void ForceRegistry::updateForces()<br />
{<br />
for(unsigned int i=0;i<ActiveForces.size();i++)<br />
{<br />
//remove ForceRegistrations that have run their course<br />
if(ActiveForces[i]->Unit->Duration <= 0)<br />
{<br />
remove(i);<br />
i--;<br />
continue;<br />
}<br />
<br />
//update forces<br />
ActiveForces[i]->Force->updateForce(ActiveForces[i]->Unit);<br />
<br />
//decrement force duration<br />
if(ActiveForces[i]->Unit->Duration &lt FLT_MAX)<br />
ActiveForces[i]->Unit->Duration -= DeltaTime;<br />
}<br />
}<br />
<br />
</code></div>
<br />
The last step is to make sure that the units process and apply their accumulated forces correctly when updated. To do this you apply the velocity to the position, calculate acceleration from the accumulated forces, apply the acceleration to the velocity and then clear out the accumulated forces.<br />
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/RigidbodyUnit.cpp" target="_blank">Unit.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
void Unit::update();<br />
{<br />
//apply velocity<br />
Position += Velocity * DeltaTime;<br />
<br />
//calculate acceleration<br />
Vector3 acc = Forces * InverseMass;<br />
<br />
//apply acceleration<br />
Velocity += acc * DeltaTime;<br />
<br />
//clear force accumulator<br />
Forces = Vector3(0,0,0);<br />
}<br />
<br />
</code></div>
<br />
<br />
Now all that's left to do is register a <code>ForceGenerator</code> with a <code>Unit</code>.<br />
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
</code> <code>//create the anchor and unit<br />
Unit* anchor=new Unit();; anchor->Position=Vector3(0,0,0); anchor->Radius=1;<br />
Unit* unit=new Unit();; unit->Position=Vector3(3,6,9); anchor->Radius=1;<br />
<br />
//create the spring force and a force registration<br />
Spring* spring=new Spring(anchor,1.2f,5.0f);<br />
ForceRegistration* reg=new ForceRegistration(unit,spring);<br />
<br />
//add the ForceRegistration to a previously made ForceRegistry<br />
forceRegistry.add(reg);<br />
<br />
</code></div>
<br />
This will result in an anchored spring object.<br />
You can view my whole system code <a href="https://github.com/melissagill/Physics" target="_blank">here</a>.Anonymoushttp://www.blogger.com/profile/01883805178932575631noreply@blogger.comtag:blogger.com,1999:blog-356925176446625013.post-6371741261428546672014-03-13T17:48:00.000-07:002014-04-23T03:20:29.811-07:00Self-Regenerating Destructible Objects<div style="text-align: justify;">
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-1km3izSZmitdNZAK3Ttmfy5q7o8D_7sfFCnqTLhnjCNA-1GMSpZfWgRuZ6NUD3JIGKzUtC2i4qwA9rCloNzfY_0kvVoPikSCVB7fGW4qtw4n8umSx6PPQT4v3BvBWMnUU93bfyJJQ1Af/s1600/90000_05.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/AVvXsEh-1km3izSZmitdNZAK3Ttmfy5q7o8D_7sfFCnqTLhnjCNA-1GMSpZfWgRuZ6NUD3JIGKzUtC2i4qwA9rCloNzfY_0kvVoPikSCVB7fGW4qtw4n8umSx6PPQT4v3BvBWMnUU93bfyJJQ1Af/s1600/90000_05.PNG" height="200" width="185" /></a>Destructible objects and terrain are pretty much awesome, so I figured I'd try implementing it myself (being able to program is fantastic). One thing I really wanted to focus on was making objects regenerate themselves once they had been destroyed. The main problem with destructible assets in games is that at some point everything is destroyed and one of the coolest features is eliminated; by having the assets gradually regenerate themselves this problem is avoided.<br />
<br /></div>
<div>
</div>
<div>
After looking into it a bit I decided that a voxel system would be the best way to accomplish this. A voxel is basically a particle with volume. By packing them together you can form a whole object or terrain whose individual voxels can be manipulated separately allowing for sections of it to be, for example, destroyed. Above is an example from my final product. The whole object is a box, but because it is made up of voxels, the upper right section can be easily removed independently.<br />
<br />
The basic implementation was not even all that difficult. The first step for me was to set up some of the basic structures I would need. The two main ones were the <code>Voxel</code> which would hold information about itself and the <code>VoxelUnit</code> which would store and manage all the voxels contained in it. The <code>VoxelUnit</code> basically acts as a box that fills itself up with voxels and then makes decisions about activating and destroying each one; having this structure allows for there to be separate voxel objects that can be manipulated independently.<br />
<br />
For this tech demo I used OpenGL and my own <a href="https://github.com/melissagill/Physics/blob/master/SpringsAndBungees/mgill_egp425/Vector3.cpp">Vector3</a> class which holds three floats (x, y, z) and has basic vector math functionality.<br />
<br />
You can view my code <a href="https://github.com/melissagill/DestructibleObjects/tree/master/DestructibleObjects" target="_blank">here</a>.<br />
<br />
Because the <code>VoxelUnit</code> handles the collision and display of each of its voxels, the <code>Voxel</code> itself is pretty simple.<br />
<br /></div>
</div>
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
struct Voxel<br />
{<br />
Depth depth;<br />
float regenTimer;<br />
};<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
The <code>regenTimer</code> is pretty obvious. To avoid instantaneous regeneration, each <code>Voxel</code> keeps track of how long it has been waiting to regenerate so that they can be regenerated gradually after a set amount of time.</div>
<div style="text-align: justify;">
The <code>depth</code> variable is a little more complex. This is used as a kind of depth identity; it is an integer defined by the following <code>Depth</code> enum.</div>
<br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
enum Depth{ EMPTY=-3, DESTROYED, BORDER, SURFACE, CENTER };<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
<code>EMPTY</code> indicates a voxel that is not displayed or interacted with and will never regenerate; this allows for shapes other than a cube. In this system every <code>VoxelUnit</code> is made up of a box full of voxels, but by making some empty, different voxel shapes can be achieved.</div>
<div style="text-align: justify;">
<code>DESTROYED</code> voxels are like empty voxels, but they can be regenerated and border voxels are destroyed voxels that are adjacent to surface voxels; the <code>VoxelUnit</code> increments the <code>regenTimer</code> of these.</div>
<div style="text-align: justify;">
<code>SURFACE</code> and <code>CENTER</code> voxels are filled, but only surface voxels are rendered. Separating them also makes it convenient if you were to check surface collisions later.</div>
<div style="text-align: justify;">
<code>EMPTY</code> is set to -3 so that <code>SURFACE</code> is 0. By setting it up this way and putting the <code>Depth</code> values in order, you can easily check if the voxel is active by checking if its depth is greater than or equal to zero.</div>
<br />
The <code>VoxelUnit</code> is basically just a <code>Voxel</code> manager:<br />
<br />
<div style="text-align: right;">
<div style="text-align: left;">
<span style="font-size: x-small;"><a href="https://github.com/melissagill/DestructibleObjects/blob/master/DestructibleObjects/VoxelUnit.h">VoxelUnit.h</a></span></div>
</div>
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
class VoxelUnit<br />
{<br />
///// variables<br />
Vector3 Position;<br />
Vector3 Color;<br />
Vector3 Dimensions;<br />
Vector3 VoxelDimensions;<br />
//dimensions in number of voxels<br />
float VoxelSize;<br />
//the size of each side of each voxel<br />
Voxel*** Voxels<br />
//3D array to store the voxels<br />
<br />
///// functions<br />
void update();<br />
void draw();<br />
<br />
void reassignDepth();<br />
//checks/resets the depth value for every Voxel<br />
Voxel* getAdjacent(Vector3 index);<br />
//returns an array of voxels adjacent to the one at index<br />
bool checkCollision(Vector3 c, float r);<br />
//check collision with a sphere at center c and radius r<br />
};<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
I'll describe what each of these functions is responsible for later on, but first we need to populate our voxel array.</div>
<div style="text-align: justify;">
The first thing you need to do is determine is the voxel dimensions based on the desired dimensions of the box and the desired voxel size.</div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/DestructibleObjects/blob/master/DestructibleObjects/VoxelUnit.cpp">VoxelUnit.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
VoxelDimensions=Dimensions/VoxelSize;<br />
VoxelDimensions=Vector3((int)VoxelDimensions.x,<br />
(int)VoxelDimensions.y,<br />
(int)VoxelDimensions.z);<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
It's important to make sure that the voxel dimensions are integers -- you don't want partial voxels.</div>
<div style="text-align: justify;">
To populate the array, you simply loop through and assign the voxels at the desired depth value.</div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/DestructibleObjects/blob/master/DestructibleObjects/VoxelUnit.cpp">VoxelUnit.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
Voxels=new Voxel**[(int)VoxelDimensions.x];<br />
for(int x=0;x<VoxelDimensions.x;x++)<br />
{<br />
Voxels[x]=new Voxel*[(int)VoxelDimensions.y];<br />
for(int y=0;y<VoxelDimensions.y;y++)<br />
{<br />
Voxels[x][y]=new Voxel[(int)VoxelDimensions.z];<br />
for(int z=0;z<VoxelDimensions.z;z++)<br />
{<br />
Voxels[x][y][z].depth=CENTER;<br />
Voxels[x][y][z].regenTimer=0;<br />
//for generating a different shape:<br />
//if(i>10 && i<VoxelDimensions.x-11<br />
// && j>10 && j<VoxelDimensions.y-11)<br />
// Voxels[x][y][z].depth=EMPTY;<br />
}<br />
}<br />
}<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
Assigning all the <code>depth</code> values to <code>CENTER</code> will result in a completely filled in box; you can get creative with generating interesting shapes though by setting the <code>depth</code> value of certain voxels to <code>EMPTY</code> (they will remain empty). Including the commented section in the code above will result in a box with a tunnel through the center of it, for example.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Throughout most of these functions, most of the actual logic will happen inside the inner-most loop of the nested loop structure because it allows access to each individual voxel.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The next key element of the <code>VoxelUnit</code> class is the <code>reassignDepth</code> function. This function is used to go through and make sure every voxel has the correct depth value after there is any change to the <code>VoxelUnit</code>. An optimal system might disperse this function and handle reassignment more locally depending on specific situations, but for the sake of getting things working, going through and reassigning the depth after any change ensures that reassignment will always be consistent and you can avoid a lot of edge cases. The depth of each voxel is mostly determined by the depths of the voxels surrounding it; this is where our <code>getAdjacent</code> function is primarily utilized as well.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Instead of writing out the nested loop to access each element, assume the following code is surrounded by such a loop and x, y, and z are the index values of the voxel for each array as it was above.</div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/DestructibleObjects/blob/master/DestructibleObjects/VoxelUnit.cpp">VoxelUnit.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
////// void reassignDepth() //////<br />
//for each Voxel in Voxels:<br />
<br />
Vector3 index(x,y,z);<br />
//get an array of adjacent voxels<br />
Voxel* adj=getAdjacent(index);<br />
<br />
<br />
//first we handle the voxels that are active (surface or center)<br />
if(Voxels[x][y][z].depth>=0)<br />
{<br />
//check to see if any of the adjacent voxels are inactive or "outside"<br />
bool outsidePresent=false;<br />
for(int i=0;i<6;i++)<br />
{<br />
if(adj[i].depth<0) //values less than 0 are inactive<br />
outsidePresent=true;<br />
}<br />
if(outsidePresent) //if next to an inactive voxel<br />
Voxels[x][y][z].depth=SURFACE;<br />
else //if all surrounding voxels are active<br />
Voxels[x][y][z].depth=CENTER;<br />
}<br />
<br />
<br />
//next we handle inactive voxels (border or destroyed)<br />
else if(Voxels[x][y][z].depth!=EMPTY)<br />
{<br />
//check to see if any of the adjacent voxels are active<br />
bool objectPresent=false;<br />
for(int i=0;i<6;i++)<br />
{<br />
if(adj[i].depth>=0) //values 0 and higher are active<br />
objectPresent=true;<br />
}<br />
if(objectPresent) //if next to an active voxel<br />
Voxels[x][y][z].depth=BORDER;<br />
else //if all surrounding voxels are inactive<br />
Voxels[x][y][z].depth=DESTROYED;<br />
}<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
All that <code>getAdjacent(Vector3 index)</code> does is return an array of the six voxels with one greater and one less index value for each dimension. To ensure that even edge voxels (index value of 0) have six adjacent voxels, I first populated the array with voxels that had a depth of <code>EMPTY</code> and reassigned them if the voxel actually existed.</div>
<div style="text-align: justify;">
Calling <code>reassignDepth()</code> after instantiating a new voxel array will sort out what is a surface, center, border, etc voxel so that you don't have to worry about that while instantiating.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The <code>update()</code> function is really pretty simple. It is mostly responsible for incrementing the border voxels' <code>regenTimer</code> and restoring the voxels that have waited the necessary time to regenerate.</div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/DestructibleObjects/blob/master/DestructibleObjects/VoxelUnit.cpp">VoxelUnit.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
////// void update() //////<br />
//for each Voxel in Voxels:<br />
<br />
if(mVoxels[x][y][z].depth==BORDER)<br />
{<br />
Voxels[x][y][z].regenTimer+=DeltaTime; //add the time passed to the Voxel's timer<br />
if(Voxels[x][y][z].regenTimer>=RegenTime)<br />
{ //if the timer has reached the required wait time, fill the voxel<br />
Voxels[x][y][z].depth=CENTER;<br />
Voxels[x][y][z].regenTimer=0;<br />
shouldReassign=true; //a boolean to keep track of if anything changes<br />
}<br />
}<br />
<br />
//if shouldReassign=true after each voxel is checked, call reassignDepth()<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
The next step is to draw the <code>VoxelUnit</code>. The most important thing involved with this is calculating each <code>SURFACE</code> voxel's position because the <code>Voxel</code> in my system does not hold its own position. Maybe it should, but it's easy enough to calculate, so I'm just going to stick with that.</div>
<br />
<span style="font-size: x-small;"><a href="https://github.com/melissagill/DestructibleObjects/blob/master/DestructibleObjects/VoxelUnit.cpp">VoxelUnit.cpp</a></span><br />
<div style="background-color: #eeeeee; padding-left: 30px;">
<code><br />
////// void draw() //////<br />
//for each Voxel in Voxels:<br />
<br />
if(mVoxels[x][y][z].depth==SURFACE) //only draw surface voxels<br />
{<br />
//find the position of the specific voxel<br />
Vector3 pos=Position-(VoxelDimensions*VoxelSize/2);<br />
Vector3 index(x,y,z);<br />
pos+=index*VoxelSize;<br />
<br />
//the following is for the fun rainbow coloration in my examples, based on a root Color<br />
Vector3 color=(Vector3(1,1,1)-Color);<br />
color.x*=index.x/VoxelDimensions.x;<br />
color.y*=index.y/VoxelsDimensions.y;<br />
color.z*=index.z/VoxelsDimensions.z;<br />
<br />
//Draw your voxel cube at pos with color<br />
}<br />
<br />
</code></div>
<br />
<div style="text-align: justify;">
All of this gives you a <code>VoxelUnit</code> that draws and regenerates itself, now all that's left to do is make it destructible. In my tech demo I only handle destructive sphere collision, but it would not be difficult to check collisions with other shapes as well. Basically you first determine if your destructive area collides with the bounding box of the <code>VoxelUnit</code> at all. If it does, loop through each of the voxels and, if the voxel is active (<code>voxel.depth>=0</code>), check to see if it collides with the destructive area. The depth of each voxel that collides should be set to <code>DESTROYED</code> and, unless no voxels were destroyed, <code>reassignDepth()</code> should be called.</div>
<br />
The end result should be a destructible voxel object that regenerates itself over time, like so:<br />
<iframe class="googleVideo" height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJQUpKdE1pNjRvdXc/preview" width="640"></iframe><br />
<br />
Or, if the <code>VoxelUnit</code> is not a solid box:<br />
<iframe class="googleVideo" height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJQVhJd2hUOEJmNzg/preview" width="640"></iframe><br />
<br />
<br />
<br />
<div style="text-align: justify;">
As you may have noticed in that clip, I set it so that you could change the destruction radius and the regeneration speed. It's also fun to play around with <code>VoxelSize</code>. The <code>VoxelUnit</code> in the video above has 90,000 voxels (as determined by a decreased <code>VoxelSize</code>), but you can get some pretty cool result with much fewer as well. Obviously, though, more voxels yields much smoother results; unfortunately this leads to massive frame rate hits as well.</div>
<br />
720 voxels:<br />
<iframe class="googleVideo" height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJTHg3TmF3V2NITm8/preview" width="640"></iframe><br />
<br />
720,000 voxels:<br />
<iframe class="googleVideo" height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJWlZOSXRtRWJrVzQ/preview" width="640"></iframe><br />
<br />
<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikWaEdvq8MjU2ZItNlGxIzpLCsro654gDym0l2VTY_x3JcTZlaQF3qOG9fiNRH1EFZoJJgkjBGSB1EBmx93WhUxPDLqpVIGbAL_Ioud7BdtcciDwHzYuwtjcyLVqwco5mE6_KInJk3BNZW/s1600/obstruction_02.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikWaEdvq8MjU2ZItNlGxIzpLCsro654gDym0l2VTY_x3JcTZlaQF3qOG9fiNRH1EFZoJJgkjBGSB1EBmx93WhUxPDLqpVIGbAL_Ioud7BdtcciDwHzYuwtjcyLVqwco5mE6_KInJk3BNZW/s1600/obstruction_02.PNG" height="200" width="179" /></a><br />
<div style="text-align: justify;">
Another cool thing I was able to accomplish with minimal additional effort in this system was the ability to place objects in the space without the <code>VoxelUnit</code> regrowing through it. This seemed like a good thing to implement on the premise of increased user immersion; if the player wanted to build on or place an object within a destroyed area, the voxel object or environment should not hinder that because of its regrowing.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
By placing permanent spheres and applying destructive sphere collision every frame, the <code>VoxelUnit</code> will regenerate around the object, but will not regrow through it.</div>
<br />
I added the ability to remove all of the permanent spheres, and it worked beautifully:<br />
<iframe class="googleVideo" height="385" src="https://docs.google.com/file/d/0B9qR0k-b7pRJWVJpWW9XTXpBejg/preview" width="640"></iframe><br />
<script type="text/javascript">$(window).load(function(){if($('.googleVideo').length$('.googleVideo').show();});</script><br />
<br />
<br />
<div style="text-align: justify;">
The next step for me in this project would be to get non-destructive collision working, so that these objects could be used as terrain or interacted with in ways other than being destroyed. Another feature I would love to add to this demo would be the ability to load in and "voxelize" custom models so that any object could be turned into a self-regenerating, destructible object. I'll post an update here when I accomplish these things!<br />
<br />
Update: I can now <a href="http://mlssagll.blogspot.com/2014/04/voxelizing-meshes.html">voxelize models</a>!</div>
Anonymoushttp://www.blogger.com/profile/01883805178932575631noreply@blogger.comtag:blogger.com,1999:blog-356925176446625013.post-40901061260156168742014-02-04T08:20:00.001-08:002014-02-04T08:23:00.487-08:00Solar System<div style="text-align: justify;">
The purpose of this project was to create a force registry system for rigidbody movement that registers force generators with bodies and then applies them for a desired rotation; I then used this force registry system to create a very basic planetary motion simulation using to-scale units so that the bodies (the sun, the moon, and the eight planets) at least started at to-scale distances away from their orbital center and the correct velocity and had to-scale radii and masses and all apply gravity to one another based on these traits. Once I got the force registry system working and tested using arbitrary values which was pretty straightforward, the next biggest challenge was determining which units to use consistently across the board so that the gravitational constant (G = 6.67384e-11 m^3/kgs^2) could be scaled appropriately; I used <a href="http://www.wolframalpha.com/">WolframAlpha</a> to determine these traits of the planets, sun, and moon in whatever units it returned and then compared a couple different unit options to find one that yielded semi-people-friendly numbers across the board:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgth5jeM14Amk1M51zbCVloRJN2UFRxDzvFWdarVqBBLNE-aCfBVK0K62BRnEf2d-Fd1s2LhCiV_R_hR_j0rPS93FIF4RBuNkD1RGG1ElEVpGkDuzLUSqnSVJdYObCL46IF8J0mOjRjsEA5/s1600/conversionChart.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgth5jeM14Amk1M51zbCVloRJN2UFRxDzvFWdarVqBBLNE-aCfBVK0K62BRnEf2d-Fd1s2LhCiV_R_hR_j0rPS93FIF4RBuNkD1RGG1ElEVpGkDuzLUSqnSVJdYObCL46IF8J0mOjRjsEA5/s1600/conversionChart.PNG" height="132" width="640" /></a></div>
<div style="text-align: justify;">
These numbers were ultimately stored in doubles so as to have as few worries about loss of significant digits in multiplication as possible. The chosen units are the darkened columns: megameters for distance and yottagrams for mass; this yielded a gravitational constant of G = 6.67384e-8 Mm^3/Ygs^2. In the simulation, to speed it up so that it wasn't moving in real time and imperceptibly slowly, I set the timestep per frame to represent about 5500 seconds, which worked well for the inner planets and bumped it up to 400,000 seconds for viewing the outer planets motion; unfortunately toggling this timestep change completely throws off the inner planets.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
This shows the simulation running, starting with just visibility of the inner planets in relatively stable orbits, zooming out a bit to start to see the outer planets and then switching to a preset zoom that I found was ideal for viewing the outer planets' orbits, then the time step is increased right at the end (apologies ahead of time for video quality):</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxg7MjVNIrAvV62H85Dw-NBp9Ti7uHwTVi3yUvcOn95Pw6SGTQpG0lktOp4HQrgvQ4wGJTsegxtuso00FPf-w' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
You might notice that the size of the planets do not change as it is zooming out and then the inner planets become much smaller when it is switched to the "outer planet view"; this is because if the planets were left displaying to-scale, most of them would show up on-screen as maybe a pixel every once and a while; to prevent this, I implemented a toggleable function that allows you to calculate the "screen radius" of the planet and set a minimum proportion they could appear as so that they would scale if they showed up as below a certain proportion of their respective radii. For better visibility in the outer planet view, that proportion decreases for the inner planets while in this view or while viewing outer planets up-close as will be shown later. This shows this minimum size functionality:</div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwFbVTWFjQWgxWTrqYxsZBzQfdXqLbuogZKqLa7c_sf_LMe-0Q9EcyqBs-HA6akxeqgI1oghjX6wZX51ygcuw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
As you can see, all of the bodies are reduced to rendering just the occasional pixel aside from the sun which stays somewhat visible in the inner-planet view mode.<br />
<br />
Unfortunately, with the addition of this minimum scale, the earth "eats" the moon in all the system views, but I assure you: the moon is, in fact, orbiting the earth at the same time as everything else. This demonstrates the earth being targeted as the video anchor point and you can see as the earth is zoomed in on, the moon is maintaining an orbit:<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzY9fKVvg-XEtlI5zlweHR9gvCUnIAYeZeTPtGKNwWCt1eHZS6tLkfm9w-4vkSnTWpYBJqZ6oNjNRpgVQsasA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
The camera also has a pretty full range of motion and rotation and each planet can be selected as a more "perspective" viewpoint base that will also display the current trait information about that planet which is fun to watch as the system and orbits gradually become unstable. This first video demonstrates this targeting of each of the planetary bodies and the second one demonstrates "looking around" from the earth viewpoint.<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dz7jH50-9M8CmiSN0aIWSDHx3DGsE5ob7aE0Vw7Ce5b5U3KEA-XiQwvpnzWsgfZ4oiGeBe2Wu7Nj33UO3-zmg' class='b-hbp-video b-uploaded' frameborder='0'></iframe><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzWLMOWse5ExUyw8d7r5SwwVrViOE7nlVc5U9r8DVVgbuwMP449TsK6RehgOdBENhwy4gc4sn2wNMCSFOBqbA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-356925176446625013.post-8944437514729957442013-12-14T08:02:00.002-08:002013-12-14T08:02:35.420-08:00Predicting Physics<span id="docs-internal-guid-385a50dd-f1d1-50da-c20c-3c72aad352fe"><div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Predicting physics in games is the use of characteristics of an object’s current status and movement to predict where it will end up. Although there are many uses for predicting physics and trajectory in games and at least as many strategies for accomplishing it, the most basic example would be looking at two objects with constant velocities, a target and a projectile, perhaps, and determining when the projectile should be fired in order to hit the target. Given a constant velocity and a starting point for each it is easy to calculate the point at which they should collide and, from there see how long it would take for each of the objects to reach the newly calculated end point; as soon as those two time values are the same, the projectile should be fired to guarantee that it will arrive at the collision point at the same time as the target. Physics prediction can be applied to something as simple as this, or as complicated as predicting the landing location of a projectile launched into a system with multiple points of gravity acting on the projectile based on the projectile’s relative location, which is what I set out to do.</span></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-385a50dd-f1d1-09ea-b5da-f4d83014e2ee"></span></span></div>
<span id="docs-internal-guid-385a50dd-f1d2-0876-3b4c-6def00560666"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<a href="https://lh6.googleusercontent.com/axQVvzeLatN2hD4UxuBb1jLOid8NVDBp8QQ2ie0fZMSGVwarcxC1RpO-br0La1AxSg-ZWjfiq6lG4QrxUNPOyOG31xq_oQxPYbWUYvRQqE0idwfVGhss-bQxEA" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="152" src="https://lh6.googleusercontent.com/axQVvzeLatN2hD4UxuBb1jLOid8NVDBp8QQ2ie0fZMSGVwarcxC1RpO-br0La1AxSg-ZWjfiq6lG4QrxUNPOyOG31xq_oQxPYbWUYvRQqE0idwfVGhss-bQxEA" width="320" /></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">A probably the most common way complexity is added to a projectile is to have it affected by a gravity force, causing it to follow an arch trajectory rather than just a straight line until it hits something. This kind of trajectory is demonstrated in games like Angry Birds and many combat-based games that involve jumping attacks or grenade-like weapons. Based on the basic kinematic equations, which take into account the acceleration due to gravity which is constant in most systems, the calculation of the time to reach an intersection point is quadratic. Once that is accurately implemented, however, the system should work in the same way.</span></div>
<br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><div class="separator" style="clear: both; text-align: center;">
<a href="https://lh5.googleusercontent.com/HMFN6LSknRHTQHaHVnODmBeih6r_l7y03ZAHMh1jgjewpkEq4f4HJxtxHFVM-ehfFogQVuq7m0uUH1qLBlFo2E7V2QcpIPP14uS-i0HLcb7ObBG9idvw4KG4Ag" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://lh5.googleusercontent.com/HMFN6LSknRHTQHaHVnODmBeih6r_l7y03ZAHMh1jgjewpkEq4f4HJxtxHFVM-ehfFogQVuq7m0uUH1qLBlFo2E7V2QcpIPP14uS-i0HLcb7ObBG9idvw4KG4Ag" width="320" /></a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<a href="https://lh6.googleusercontent.com/yuWzWMhJcUtT-gLmW84eRE8Dm7YE52vqezlayE1n8s_RA-AvU9Jku3-rNY2GbuYCkMNTQBgz3XErwPxCke7Jp7NjOzR5UpJ9kAnBS48avM9u-cm4kSSyolb6Hg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="137" src="https://lh6.googleusercontent.com/yuWzWMhJcUtT-gLmW84eRE8Dm7YE52vqezlayE1n8s_RA-AvU9Jku3-rNY2GbuYCkMNTQBgz3XErwPxCke7Jp7NjOzR5UpJ9kAnBS48avM9u-cm4kSSyolb6Hg" width="320" /></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Obviously, the more contributing factors to a projectile’s trajectory, the more complicated prediction becomes. Sometimes it just becomes over-complicated and inefficient beyond feasibility to calculate the trajectory in one shot. Depending on the complexity and the variability of the results, an iterative process can be used to make guesses about the required initial velocity to get within a certain degree of accuracy of a target’s location. Using this strategy, an initial guess would usually be made ignoring the complicating factors, then the real final location would be calculated based on that guess and, based on where that is relative to the target location, assign it as a boundary and make another guess that is higher or lower, depending on what was wrong with the initial guess. This would be </span><span style="font-family: Arial; font-size: 15px; line-height: 1.15; white-space: pre-wrap;">iterated through until a guess is made that falls within a certain pre-determined degree of accuracy (Millington).</span></div>
<br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><div class="separator" style="clear: both; text-align: center;">
<a href="https://lh5.googleusercontent.com/-Ti3Wn7NqEa3UqZGwd9rK5RRfprmmFO41BJQEzbPW3EO16RKiydTB58YsT8a9xkmEw_HuLFY4IIww26wxizrKiK6vclg6yEd8NRNpEsP8rqphnebJaidTNwlsw" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="268" src="https://lh5.googleusercontent.com/-Ti3Wn7NqEa3UqZGwd9rK5RRfprmmFO41BJQEzbPW3EO16RKiydTB58YsT8a9xkmEw_HuLFY4IIww26wxizrKiK6vclg6yEd8NRNpEsP8rqphnebJaidTNwlsw" width="400" /></a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">In my prediction system, the landing point was one of any number of planets in a solar system and there is little correlation between the initial velocity and the landing position, as it would apply to the aforementioned iteration system. I instead used iteration to basically run a limited simulation, feeding in the initial position and velocity and stepping through each frame to determine what forces would be applied and, thus, how the trajectory would be affected frame-by-frame. I iterated through each time step until either a collision was found or the prediction timed out according to a limit I determined. You can see in the screenshots that the pink dots are positions along the trajectory of the projectile, the yellow dot with a yellow trail.</span></div>
<br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Predicting physics is not innately too processor intensive, or have any specific platform requirements. Obviously iterative prediction methods are going to be significantly more processor intensive, with an increase in demand based on how accurate the calculated trajectory must be or how long until a simulation-based iteration will continue without reaching a target. Simple things such as the first example involving constant velocities and calculating just the timing takes only a few simple operations.</span></div>
<br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><div class="separator" style="clear: both; text-align: center;">
<a href="https://lh6.googleusercontent.com/LhpDrym9PYSphz3_cnin7WNZ7OWugJwgkAmMMIMUCVbGfDX9w1Y3YcwgMyMxywtA8gXEGYhER8MBBl3Kgslanum76NZa9Eptdmw_L3bBGmjpEl1iIEvcTnocBA" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://lh6.googleusercontent.com/LhpDrym9PYSphz3_cnin7WNZ7OWugJwgkAmMMIMUCVbGfDX9w1Y3YcwgMyMxywtA8gXEGYhER8MBBl3Kgslanum76NZa9Eptdmw_L3bBGmjpEl1iIEvcTnocBA" width="400" /></a></div>
<div dir="ltr" style="line-height: 1.15; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Works Cited: </span></div>
<span style="background-color: white; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">Millington, Ian, and John Funge. "Predicting Physics." </span><span style="background-color: white; font-size: 16px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;">Artificial Intelligence for Games</span><span style="background-color: white; font-size: 16px; vertical-align: baseline; white-space: pre-wrap;">. 2nd ed. Burlington, MA: Morgan Kaufmann, 2009. 120-33. Print.</span></span><br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-356925176446625013.post-44960976271073571842013-09-30T21:53:00.001-07:002013-09-30T22:27:02.472-07:00Networking for Games Game Jam Space Jam Games and JamOur task: create a slightly simplified version of Space Wars that could be played by 2-4 networked players in about two and a half hours.<br />
The result: at the end of two and a half hours we had something that almost entirely didn't run.<br />
Over the next few days Ian the Super Fantastic and I worked to finish it up and mend all the breaks.<br />
<br />
The end product featured:<br />
<ul>
<li>independent momentum and turning</li>
<li>toggle-able gravity and center planet</li>
<li>screen-wrapped player and projectile movement</li>
<li>a color selection lobby for player differentiation</li>
</ul>
<br />
The biggest challenge we faced was, what initially seemed to be, random data loss. Turns out we were trying to pack way too much data into single packets so it would try to read in data, get about halfway through it and run out of data to read. This lead to all sorts of interesting behavior and, considering the magnitude of the problem, surprisingly few breaks. Finally we decided to send packets that contained just a data identifier and the actual data instead of packing everything into a single packet and sending it once a frame.<br />
<br />
One thing I think we definitely should have done differently is handling player movement over the network. Currently each player simply sends it's screen coordinates every frame and each player updates the local version of that player. What we should have done was send the player's input when it was provided and let the actual movement be handled locally, perhaps with an actual position update every couple seconds to make sure things did not go horribly, horribly awry.<br />
<br />
There were a couple things that went well, on the other hand. I think the general gravity and momentum based movement we implemented worked very smoothly. The color-selection lobby state I made is pretty spiffy as well. Each player flies around and chooses a color as indicated by color-overlays; the game refuses to start until there is only one player per color (as determined by the host), which we felt was a better way to determine the in-game differentiation without worrying about player order and assigning things based on it.<br />
<br />
Ian Percoco is awesome: <a href="http://ianpercoco.blogspot.com/">Ian's post</a>Unknownnoreply@blogger.com