Disappearing internal boundary conditions in Lattice Boltzmann simulation - simulation

I am using Electron with TypeScript to prototype some fluid simulation code, using the Lattice Boltzmann algorithm, which will eventually go into a game. So far, I have been using static boundary conditions (with simulation calculations only occurring on the interior of the grid, and values for the boundary cells remaining fixed), an everything appears to work fine in that regime. In particular, I can impose internal boundary conditions (for example, enforcing that a certain density of fluid always exits a certain lattice site on every frame, to simulate a hose/rocket nozzle/whatever) by just manually setting the cell values in between each simulation step.
However, if I switch to using periodic boundary conditions (i.e., a wrap-around, toroidal-topology Asteroids world), the whole simulation become static. I just get constant fluid density everywhere, for all time, and it's like all of my boundary conditions are erased, no matter where in the simulation cycle (before streaming or before collision) I choose to assert them. I am not sure if periodic boundary conditions will end up being relevant for the game, but this failure makes me think there must be some subtle bug somewhere in the simulation.
The complete code is available at https://github.com/gliese1337/balloon-prototype/tree/deopt , but what I expect are the relevant portions are as follows:
class LatticeBoltzmann {
private streamed: Float32Array; // microscopic densities along each lattice direction
private collided: Float32Array;
public rho: Float32Array; // macroscopic density; cached for rendering
...
public stream(barriers: boolean[]) {
const { xdim, ydim, collided, streamed } = this;
const index = (x: number, y: number) => (x%xdim)+(y%ydim)*xdim;
const cIndex = (x: number, y: number, s: -1|1, j: number) =>
9*(((x+s*cxs[j])%xdim)+((y+s*cys[j])%ydim)*xdim)+j;
// Move particles along their directions of motion:
for (let y=1; y<ydim-1; y++) {
for (let x=1; x<xdim-1; x++) {
const i = index(x, y);
const i9 = i*9;
for (let j=0;j<9;j++) {
streamed[i9 + j] = collided[cIndex(x, y, -1, j)];
}
}
}
// Handle bounce-back from barriers
for (let y=0; y<ydim; y++) {
for (let x=0; x<xdim; x++) {
const i = index(x, y);
const i9 = i*9;
if (barriers[i]) {
for (let j=1;j<9;j++) {
streamed[cIndex(x, y, 1, j)] = collided[i9 + opp[j]];
}
}
}
}
}
// Set all densities in a cell to their equilibrium values for a given velocity and density:
public setEquilibrium(x: number, y: number, ux: number, uy: number, rho: number) {
const { xdim, streamed } = this;
const i = x + y*xdim;
this.rho[i] = rho;
const i9 = i*9;
const u2 = 1 - 1.5 * (ux * ux + uy * uy);
for (let j = 0; j < 9; j++) {
const dir = cxs[j]*ux + cys[j]*uy;
streamed[i9+j] = weights[j] * rho * (u2 + 3 * dir + 4.5 * dir * dir);
}
}
}
Lattice data is stored in two flat arrays, collided which holds the end states after the collision step and serves as input to the streaming step, and streamed, which holds the end states after the streaming step and serves as input to the next collision step. The 9 vector components for the D2Q9 lattice are stored in contiguous blocks, which are then grouped into rows. Note that I am already using mod operations to calculate array indices from lattice coordinates; this is completely irrelevant as long as the simulation calculations only range over the interior of the lattice, but it should make periodic boundaries ready-to-go as soon as the for (let y=1; y<ydim-1; y++) and for (let x=1; x<xdim-1; x++) loops have their bounds changed to for (let y=0; y<ydim; y++) and for (let x=0; x<xdim; x++), respectively. And indeed it is that specific 6-character change that I am having trouble with.
The setEquilibrium method is used to impose boundary conditions. In the driver code, it is currently being called like this, once per frame:
// Make fluid flow in from the left edge and out through the right edge
function setBoundaries(LB: LatticeBoltzmann, ux: number) {
for (let y=0; y<ydim; y++) {
LB.setEquilibrium(0, y, ux, 0, 1);
LB.setEquilibrium(xdim-1, y, ux, 0, 1);
}
}
With static boundary conditions, calling that once per frame happens to be superfluous, because it only alters the boundary lattice sites. Shifting the hard-coded x-values to the interior of the lattice, however, (where reasserting the boundary conditions once per frame is in fact necessary) does exactly what you would expect--it makes fluid appear or disappear at specific locations. Switching to periodic boundary conditions, however, results in that code ceasing to have any visible effect.
So... anybody know what I might be doing wrong?

I am not entirely certain why this particular error had this particular weird effect, but it turns out that the problem was in my use of the % operator--it's signed. Thus, when putting in a negative lattice index, naive usage of the % does not perform the wrap-around that one would want from a proper modulus operator; rather, it just gives you back the same negative value, and results in an out-of-bounds array access.
Adding on the array dimension prior to taking the remainder ensures that all values are positive, and we get the necessary wrap-around behavior.
Incidentally, being able to range over the entire lattice without bothering to treat the edges specially allows for collapsing nested loops into a single linear scan over the entire lattice, which eliminates the need for the primary index calculation function, and enormously simplifies the collision-streaming offset index function, cIndex, which now looks like const cIndex = (i: number, s: -1|1, j: number) => 9*((i+s*(cxs[j]+cys[j]*xdim)+max)%max)+j;, requiring only a single modulus instead of one per dimension. The result of that string of simplifications is a massive speedup to the code, with associated improved framerate.

Related

Moving an object along a path with constant speed

I have an object path composed by a polyline (3D point array) with points VERY unevenly distributed. I need to move an object at constant speed using a timer with interval set at 10 ms.
Unevenly distributed points produce variable speed to the human eye. So now I need to decide how to treat this long array of 3D points.
The first idea I got was to subdivide long segments in smaller parts. It works better but where points are jam-packed the problem persists.
What's the best approach in these cases? Another idea, could be to simplify the original path using Ramer–Douglas–Peucker algorithm, then to subdivide it evenly again but I'm not sure if it will fully resolve my problem.
This should be a fairly common problem in many areas of the 3D graphics, so does a proven approach exist?
I made a JavaScript pen for you https://codepen.io/dawken/pen/eYpxRmN?editors=0010 but it should be very similar in any other language. Click on the rect to add points.
You have to maintain a time dependent distance with constant speed, something like this:
const t = currentTime - startTime;
const distance = (t * speed) % totalLength;
Then you have to find the two points in the path such that the current distance is intermediate between the "distance" on the path; you store the "distance from start of the path" on each point {x, y, distanceFromStart}. The first point points[i] such that distance < points[i].distanceFromStart is your destination; the point before that points[i - 1] is your source. You need to interpolate linearly between them.
Assuming that you have no duplicate points (otherwise you get a division by zero) you could do something like this.
for (let i = 0; i < points.length; i++) {
if (distance < points[i].distanceFromStart) {
const pFrom = points[i - 1];
const pTo = points[i];
const f = (distance - pFrom.distanceFromStart) / (pTo.distanceFromStart- pFrom.distanceFromStart);
const x = pFrom.x + (pTo.x - pFrom.x) * f;
const y = pFrom.y + (pTo.y - pFrom.y) * f;
ctx.fillRect(x - 1, y - 1, 3, 3);
break;
}
}
See this pen. Click on the rectangle to add points: https://codepen.io/dawken/pen/eYpxRmN?editors=0010

Move object to nearest empty space on a plane

Check the following gif: https://i.gyazo.com/72998b8e2e3174193a6a2956de2ed008.gif
I want the cylinder to instantly change location to the nearest empty space on the plane as soon as I put a cube on the cylinder. The cubes and the cylinder have box colliders attached.
At the moment the cylinder just gets stuck when I put a cube on it, and I have to click in some direction to make it start "swimming" through the cubes.
Is there any easy solution or do I have to create some sort of grid with empty gameobjects that have a tag which tells me if there's an object on them or not?
This is a common problem in RTS-like video games, and I am solving it myself. This requires a breadth-first search algorithm, which means that you're checking the closest neighbors first. You're fortunate to only have to solve this problem in a gridded-environment.
Usually what programmers will do is create a queue and add each node (space) in the entire game to that queue until an empty space is found. It will start with e.g. the above, below, and adjacent spaces to the starting space, and then recursively move out, calling the same function inside of itself and using the queue to keep track of which spaces still need to be checked. It will also need to have a way to know whether a space has already been checked and avoid those spaces.
Another solution I'm conceiving of would be to generate a (conceptual) Archimedean spiral from the starting point and somehow check each space along that spiral. The tricky part would be generating the right spiral and checking it at just the right points in order to hit each space once.
Here's my quick-and-dirty solution for the Archimedean spiral approach in c++:
float x, z, max = 150.0f;
vector<pair<float, float>> spiral;
//Generate the spiral vector (run this code once and store the spiral).
for (float n = 0.0f; n < max; n += (max + 1.0f - n) * 0.0001f)
{
x = cos(n) * n * 0.05f;
z = sin(n) * n * 0.05f;
//Change 1.0f to 0.5f for half-sized spaces.
//fmod is float modulus (remainder).
x = x - fmod(x, 1.0f);
z = z - fmod(z, 1.0f);
pair<float, float> currentPoint = make_pair(x, z);
//Make sure this pair isn't at (0.0f, 0.0f) and that it's not already in the spiral.
if ((x != 0.0f || z != 0.0f) && find(spiral.begin(), spiral.end(), currentPoint) == spiral.end())
{
spiral.push_back(currentPoint);
}
}
//Loop through the results (run this code per usage of the spiral).
for (unsigned int n = 0U; n < spiral.size(); ++n)
{
//Draw or test the spiral.
}
It generates a vector of unique points (float pairs) that can be iterated through in order, which will allow you to draw or test every space around the starting space in a nice, outward (breadth-first), gridded spiral. With 1.0f-sized spaces, it generates a circle of 174 test points, and with 0.5f-sized spaces, it generates a circle of 676 test points. You only have to generate this spiral once and then store it for usage numerous times throughout the rest of the program.
Note:
This spiral samples differently as it grows further and further out from the center (in the for loop: n += (max + 1.0f - n) * 0.0001f).
If you use the wrong numbers, you could very easily break this code or cause an infinite loop! Use at your own risk.
Though more memory intensive, it is probably much more time-efficient than the traditional queue-based solutions due to iterating through each space exactly once.
It is not a 100% accurate solution to the problem, however, because it is a gridded spiral; in some cases it may favor the diagonal over the lateral. This is probably negligible in most cases though.
I used this solution for a game I'm working on. More on that here. Here are some pictures (the orange lines in the first are drawn by me in Paint for illustration, and the second picture is just to demonstrate what the spiral looks like if expanded):

Moving object continuously using translate

I want to move an object from A to B continuously,like 1st A to B then B to A then again A to B and so on,thanks in advance. I've tried this.
float speed X = 1; float speed Y = 0; float speed Z = 0;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.Translate (new Vector 3 (speed X, speed Y, speed Z) * Time . delta time );
}
You should need to use Vector3.Lerp:
Linearly interpolates between two vectors.
Interpolates between the vectors a and b by the interpolant t. The
parameter t is clamped to the range [0, 1]. This is most commonly used
to find a point some fraction of the way along a line between two
endpoints (e.g. to move an object gradually between those points.(read this)
While for your actual answer here is code you can see:
http://answers.unity3d.com/questions/14279/make-an-object-move-from-point-a-to-point-b-then-b.html
http://answers.unity3d.com/questions/905966/moving-an-object-constantly-between-two-points-wit.html
How to move an object between two points in Unity?
http://answers.unity3d.com/questions/690884/how-to-move-an-object-along-x-axis-between-two-poi.html

Procedural structure generation

I have a voxel based game in development right now and I generate my world by using Simplex Noise so far. Now I want to generate some other structures like rivers, cities and other stuff, which can't be easily generated because I split my world (which is practically infinite) into chunks of 64x128x64. I already generated trees (the leaves can grow into neighbouring chunks), by generating the trees for a chunk, plus the trees for the 8 chunks surrounding it, so leaves wouldn't be missing. But if I go into higher dimensions that can get difficult, when I have to calculate one chunk, considering chunks in an radius of 16 other chunks.
Is there a way to do this a better way?
Depending on the desired complexity of the generated structure, you may find it useful to first generate it in a separate array, perhaps even a map (a location-to-contents dictionary, useful in case of high sparseness), and then transfer the structure to the world?
As for natural land features, you may want to google how fractals are used in landscape generation.
I know this thread is old and I suck at explaining, but I'll share my approach.
So for example 5x5x5 trees. What you want is for your noise function to return the same value for an area of 5x5 blocks, so that even outside of the chunk, you can still check if you should generate a tree or not.
// Here the returned value is different for every block
float value = simplexNoise(x * frequency, z * frequency) * amplitude;
// Here it will return the same value for an area of blocks (you should use floorDiv instead of dividing, or you it will get negative coordinates wrong (-3 / 5 should be -1, not 0 like in normal division))
float value = simplexNoise(Math.floorDiv(x, 5) * frequency, Math.floorDiv(z, 5) * frequency) * amplitude;
And now we'll plant a tree. For this we need to check what x y z position this current block is relative to the tree's starting position, so we can know what part of the tree this block is.
if(value > 0.8) { // A certain threshold (checking if tree should be generated at this area)
int startX = Math.floorDiv(x, 5) * 5; // flooring the x value to every 5 units to get the start position
int startZ = Math.floorDiv(z, 5) * 5; // flooring the z value to every 5 units to get the start position
// Getting the starting height of the trunk (middle of the tree , that's why I'm adding 2 to the starting x and starting z), which is 1 block over the grass surface
int startY = height(startX + 2, startZ + 2) + 1;
int relx = x - startX; // block pos relative to starting position
int relz = z - startZ;
for(int j = startY; j < startY + 5; j++) {
int rely = j - startY;
byte tile = tree[relx][rely][relz]; // Get the needing block at this part of the tree
tiles[i][j][k] = tile;
}
}
The tree 3d array here is almost like a "prefab" of the tree, which you can use to know what block to set at the position relative to the starting point. (God I don't know how to explain this, and having english as my fifth language doesn't help me either ;-; feel free to improve my answer or create a new one). I've implemented this in my engine, and it's totally working. The structures can be as big as you want, with no chunk pre loading needed. The one problem with this method is that the trees or structures will we spawned almost within a grid, but this can easily be solved with multiple octaves with different offsets.
So recap
for (int i = 0; i < 64; i++) {
for (int k = 0; k < 64; k++) {
int x = chunkPosToWorldPosX(i); // Get world position
int z = chunkPosToWorldPosZ(k);
// Here the returned value is different for every block
// float value = simplexNoise(x * frequency, z * frequency) * amplitude;
// Here it will return the same value for an area of blocks (you should use floorDiv instead of dividing, or you it will get negative coordinates wrong (-3 / 5 should be -1, not 0 like in normal division))
float value = simplexNoise(Math.floorDiv(x, 5) * frequency, Math.floorDiv(z, 5) * frequency) * amplitude;
if(value > 0.8) { // A certain threshold (checking if tree should be generated at this area)
int startX = Math.floorDiv(x, 5) * 5; // flooring the x value to every 5 units to get the start position
int startZ = Math.floorDiv(z, 5) * 5; // flooring the z value to every 5 units to get the start position
// Getting the starting height of the trunk (middle of the tree , that's why I'm adding 2 to the starting x and starting z), which is 1 block over the grass surface
int startY = height(startX + 2, startZ + 2) + 1;
int relx = x - startX; // block pos relative to starting position
int relz = z - startZ;
for(int j = startY; j < startY + 5; j++) {
int rely = j - startY;
byte tile = tree[relx][rely][relz]; // Get the needing block at this part of the tree
tiles[i][j][k] = tile;
}
}
}
}
So 'i' and 'k' are looping withing the chunk, and 'j' is looping inside the structure. This is pretty much how it should work.
And about the rivers, I personally haven't done it yet, and I'm not sure why you need to set the blocks around the chunk when generating them ( you could just use perlin worms and it would solve problem), but it's pretty much the same idea, and for your cities too.
I read something about this on a book and what they did in these cases was to make a finer division of chunks depending on the application, i.e.: if you are going to grow very big objects, it may be useful to have another separated logic division of, for example, 128x128x128, just for this specific application.
In essence, the data resides is in the same place, you just use different logical divisions.
To be honest, never did any voxel, so don't take my answer too serious, just throwing ideas. By the way, the book is game engine gems 1, they have a gem on voxel engines there.
About rivers, can't you just set a level for water and let rivers autogenerate in mountain-side-mountain ladders? To avoid placing water inside mountain caveats, you could perform a raycast up to check if it's free N blocks up.

How to move incrementally in a 3D world using glRotatef() and glTranslatef()

I have some 3D models that I render in OpenGL in a 3D space, and I'm experiencing some headaches in moving the 'character' (that is the camera) with rotations and translation inside this world.
I receive the input (ie the coordinates where to move/the dregrees to turn) from some extern event (image a user input or some data from a GPS+compass device) and the kind of event is rotation OR translation .
I've wrote this method to manage these events:
- (void)moveThePlayerPositionTranslatingLat:(double)translatedLat Long:(double)translatedLong andRotating:(double)degrees{
[super startDrawingFrame];
if (degrees != 0)
{
glRotatef(degrees, 0, 0, 1);
}
if (translatedLat != 0)
{
glTranslatef(translatedLat, -translatedLong, 0);
}
[self redrawView];
}
Then in redrawView I'm actualy drawing the scene and my models. It is something like:
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
NSInteger nModels = [models count];
for (NSInteger i = 0; i < nModels; i++)
{
MD2Object * mdobj = [models objectAtIndex:i];
glPushMatrix();
double * deltas = calloc(sizeof(double),2);
deltas[0] = currentCoords[0] - mdobj.modelPosition[0];
deltas[1] = currentCoords[1] - mdobj.modelPosition[1];
glTranslatef(deltas[0], -deltas[1], 0);
free(deltas);
[mdobj setupForRenderGL];
[mdobj renderGL];
[mdobj cleanupAfterRenderGL];
glPopMatrix();
}
[super drawView];
The problem is that when translation an rotation events are called one after the other: for example when I'm rotating incrementally for some iterations (still around the origin) then I translate and finally rotate again but it appears that the last rotation does not occur around the current (translated) position but around the old one (the old origin). I'm well aware that this happens when the order of transformations is inverted, but I believed that after a drawing the new center of the world was given by the translated system.
What am I missing? How can I fix this? (any reference to OpenGL will be appreciated too)
I would recommend not doing cummulative transformations in the event handler, but internally storing the current values for your transformation and then only transforming once, but I don't know if this is the behaviour that you want.
Pseudocode:
someEvent(lat, long, deg)
{
currentLat += lat;
currentLong += long;
currentDeg += deg;
}
redraw()
{
glClear()
glRotatef(currentDeg, 0, 0, 1);
glTranslatef(currentLat, -currentLong, 0);
... // draw stuff
}
It sounds like you have a couple of things that are happening here:
The first is that you need to be aware that rotations occur about the origin. So when you translate then rotate, you are not rotating about what you think is the origin, but the new origin which is T-10 (the origin transformed by the inverse of your translation).
Second, you're making things quite a bit harder than you really need. What you might want to consider instead is to use gluLookAt. You essentially give it a position within your scene and a point in your scene to look at and an 'up' vector and it will set up the scene properly. To use it properly, keep track of where you camera is located, call that vector p, and a vector n (for normal ... indicates the direction you're looking) and u (your up vector). It will make things easier for more advanced features if n and u are orthonormal vectors (i.e. they are orthoginal to each other and have unit length). If you do this, you can compute r = n x u, (your 'right' vector), which will be a normal vector orthoginal to the other two. You then 'look at' p+n and provide the u as the up vector.
Ideally, your n, u and r have some canonical form, for instance:
n = <0, 0, 1>
u = <0, 1, 0>
r = <1, 0, 0>
You then incrementally accumulate your rotations and apply them to the canonical for of your oritentation vectors. You can use either Euler Rotations or Quaternion Rotations to accumulate your rotations (I've come to really appreciate the quaternion approach for a variety of reasons).