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.
Related
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
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.
I need to move some objects lets say 50 in a space (i.e a grid of [-5,5]) and making sure that if the grid is divided into 100 portions most of the portions (90% or more) are once visited by any object
constraints :
object should move in random directions in the grid changing their velocities frequently (change speed and direction in each iteration)
I was thinking of bouncing balls ( BUT moving in random directions even if not hit by anything in space, not they way a real ball moves) , if we could leave them into space in different positions with different forces and each time they hit each other (or getting closer to a specific distance ) they move to different directions with different speed and could give us a result near to 90% hit of portions in the grid .
I also need to make sure objects are not getting out of grid ( could make lb and ub limits and get them back in case they try to leave the grid)
My code is different from the idea I have written above ...
ux = 1;
uy = 15;
g = 9.81;
t = 0; x(1) = 0;
y(1) = 0;
tf = 2.0 * uy / g; % time of flight back to the ground
dt = tf / 20; % time increment - taking 20 steps
while t < tf
t = t + dt;
if((uy - 0.5 * g * t) * t >= 0)
x(end + 1) = ux * t;
y(end + 1) = (uy - 0.5 * g * t) * t;
end
end
plot(x,y)
this code makes the ball to go with Newton's law which is not the case
Bottom line i just need to be able to visit many portions of grid in a short time so this is why i want the objects to moves in a chaotic way in the space in a random manner (each time running the code i need different result so it needs to be random path) and to get a better result i could make the objects bounce to different directions if they hit or visit each other in the same portions , this probably give me a better result .
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):
I'm really scratching my head here in an effort to understand a quote i read somewhere that says "the more we zoom inside the fractal, the more iteration we will most likely need to perform".
so far, i haven't been able to find any mathematical / academical paper that proves that saying.
i've also managed to find a small code that calculates the mandelbrot set, taken from here :
http://warp.povusers.org/Mandelbrot/
but yet, wasn't able to understand how zooming affects iterations.
double MinRe = -2.0;
double MaxRe = 1.0;
double MinIm = -1.2;
double MaxIm = MinIm+(MaxRe-MinRe)*ImageHeight/ImageWidth;
double Re_factor = (MaxRe-MinRe)/(ImageWidth-1);
double Im_factor = (MaxIm-MinIm)/(ImageHeight-1);
unsigned MaxIterations = 30;
for(unsigned y=0; y<ImageHeight; ++y)
{
double c_im = MaxIm - y*Im_factor;
for(unsigned x=0; x<ImageWidth; ++x)
{
double c_re = MinRe + x*Re_factor;
double Z_re = c_re, Z_im = c_im;
bool isInside = true;
for(unsigned n=0; n<MaxIterations; ++n)
{
double Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
if(Z_re2 + Z_im2 > 4)
{
isInside = false;
break;
}
Z_im = 2*Z_re*Z_im + c_im;
Z_re = Z_re2 - Z_im2 + c_re;
}
if(isInside) { putpixel(x, y); }
}
}
Thanks!
This is not a scientific answer but a one with common sense. In theory, to decide whether a point belongs to the Mandelbrot set or not, you should iterate infinitely, and check if the value ever reaches Infinity. This is practically useless so we make assumptions:
We iterate only 50 times
We check that iteration value ever gets larger than 2
When you zoom into a Mandelbrot set, the second assumption remains valid. However zooming means increasing the significant fractional digits of the point coordinates.
Say you start with (0.4,-0.2i).
Iterating over and over this value increases the digits used, but won't lose significant digits. Now when your point coordinate looks such: (0.00000000045233452235, -0.00000000000943452634626i) to check if that point is in the set you need much more iteration to see if that iteration would ever reach 2 not to mention that if you use some kind of Float type, you will lose significant digits at some zoom level and you'll have to switch to an arbitrary precision library.
Trying is your best friend :-) Calculate a set with a low iteration and a high iteration and subtract the second image from the first. You will always see change at the edges (where black pixels meet colored pixels), but if your zooming level is high (meaning: the point coordinates have a lot of fractional digits) you will get a different image.
You asked how zooming affects iterations and my typical zoom to iterations ratio is that if you zoom in to a 9th of the size I increase iterations by 1.7. A 9th of the size of course means that both width and height is divided by 3.
Making this more generic I actually use this in my code
Complex middle = << calculate from click in image >>
int zoomfactor = 3;
width = width / zoomfactor;
maxiter = (int)(maxiter * Math.Sqrt(zoomfactor));
minimum = new Complex(middle.Real - width, middle.Imaginary - width);
maximum = new Complex(middle.Real + width, middle.Imaginary + width);
I find that this relation between zoom and iterations works out pretty well, the details in the fractals still come well on deep zooms without getting too crazy on the iterations too fast.
How fast you want to zoom if your own preference, I like a zoomfactor of 3 but anything goes. The important thing is that you need to keep the relation between the zoomfactor and the increase in interations.