How to create random points in three-dimensional space?

The biggest problem I encountered is that I do not have the vocabulary to describe what I am doing, so if nothing else, some help with this would be greatly appreciated.

From what I understand, Perlin noise can give you a random value for a point in 3D space and, in addition, any close points will have the same value. This works for me in a program for creating 3D blocks floating in space when a random value passes a certain threshold. This works well, because I can select any point and not worry about which points were calculated earlier, determine its value (it would be possible to generate blob generation if I wanted to).

Now I want to do something similar, except that I want to change the color of this point to blob if a random value passes a certain threshold. However, I want this to be random and unrelated to my neighbors (as opposed to Perlin's noise).

What algorithm am I looking for for this?

Key criteria:

  • The function takes a 3D vector as a parameter.
  • Values ​​are not completely related.
  • Control points of the order do not affect the results of the function.
  • The function returns the same result if the same point is passed to it.

Result

So I decided to use an approach similar to Koehler’s answer with some small tricks. I did not want to use all the redirects and operations used by a multiple instance or even just re-sowing a random number generator. I ended up copying the random number generator used in the UE4 RandomStream class, and it suited my needs. I am sure that this generator does not belong to them, because the numbers used look in other places, but it was there that I found it.

float WhiteNoise::GetNoise3D(const FVector& vector) const { int32 s1 = seed; int32 s2 = ((s1 + FMath::TruncToInt(vector.X)) * 196314165) + 907633515; int32 s3 = ((s2 + FMath::TruncToInt(vector.Y)) * 196314165) + 907633515; int32 s4 = ((s3 + FMath::TruncToInt(vector.Z)) * 196314165) + 907633515; const float tmp = 1.0f; float result; *(int32*)&result = (*(int32*)&tmp & 0xff800000) | (s4 & 0x007fffff); return FMath::Fractional(result); } 

There are some obvious problems with the above code. One of them is that the numbers are not very random, while the others are truncation, causing a granularity problem. Both of these goals are completely acceptable in my situation, so it works quite well.

+5
source share
2 answers

If a function returns the same number every time the same parameter is passed, this is not a random function. To get an explicitly arbitrary pattern without preserving the exact result of each point, you can use a random generator with position-dependent seed.

Sort of

 value_t get_value(coord_t x, coord_t y, coord_t z) { seed_t seed = some_equation(x,y,z); return generate_random_with_seed(seed); } 

C ++ now has a <random> library, you will need to adjust the equation to get satisfactory results. And they will be repeated every time the seed is repeated with a seemingly random pattern every call. One of the possible seed generators distributes all possible discrete possibilities by type of seed, since equal seeds mean equal results.

(so the 256x256x256 grid can use the seed (x*256*256 + y*256 + z)

This strategy actually maps an ordered set to a clearly unordered set. The output will be related to the position of a random seed generator.

Since the requirements for unique seeds can become quite cumbersome, you can also get duplicate results by dividing your volume into smaller ones, each of which consisted of N points, and the entire fragment has the same unique seed, a random value of the ith element is the ith run of a random generator with a piece seed.

This will reduce the need for unique seeds by N times, but increase average extraction operations by (N-1) / 2.

Some time ago I tried several <random> distributions, here is some code that shows ~ graphical ~ output (comments are in Portuguese, but the code is simple).

You will probably need a uniformly random variable for the threshold, here is an online link to uniform_int_distribution .

+2
source

Taking a slightly different approach than the excellent answer above Kahler , I wonder if you are just looking for a way to change the number space.

In this context, we can say that a random number exists in a one-dimensional number space. i.e. integer values ​​are available from 0 up and down.

A randomly generated 32-bit integer must be between 0 and 4294967295, i.e. you have 4294967296 possible unique numbers. However, if you “consume” this random number, for example, in two-dimensional space (“grid”, as we say), then your grid size will be the second root of 4294967296, which is 65536. This means that you have 65536 65536 possible "slots", which can randomly be either 0 or 1 (but the distribution of random numbers will fully correspond to this grid).

If you consume a random integer in three-dimensional space, you are faced with the third root 4294967296, which is approximately 1625. That is, the grid size is about 1625x1625x1625 slots (you can also say "cells").

As you can see here, 1625 is not so much, and the following is implied: if you need to maintain space using 32-bit floats for XYZ positions (maybe a space game? You haven't mentioned), then you address space using 96 bits - or, even worse, 192 bits for addressing with doubles - when generating a random number in only 32-bit space. This means that there will be either repetition or coarse ("poor granularity") between the numerical spaces in the display. It's hard to predict exactly how you will experience it. However, you will only have 1625 possible x-positions.

(However, you can change a random number from one-dimensional space to 3-dimensional. On the contrary, it’s prime. Generate a number, capture its logical representation (binary, bits). Then just take the first 11 bits and construct an integer from them: use it to position.x. Then do the same with the next 11 bits and use for position.y. The Z-position gets only 10 bits ... hm - oh well :-). )

The use of seeds is not related to this. Seed makes random generation repeatable and that is still entirely possible with the Kahlers description.

Now to the potential problem:

  • If you "isolate" these things from droplets (with the internal addressing of the 3D addressing from which you inherit the seed), then there is a fear that your random generation will repeat from blob to blob. All drops will look the same.

  • If you, on the other hand, use a global, huge coordinate addressing for your seed, then you may get poor detail among random numbers in separate blocks (for example, only 1625 possible positions along one direction, view).

It's hard to say, but you may get visually unsatisfactory results. I would suggest generating not one random number in time, but 3, one for each direction. You can still determine if it was a hit or not (your "threshold") - but just handle the check using triplets of individual random numbers. And use your global (global) positioning system for each of the individual seeds.

+1
source

Source: https://habr.com/ru/post/1246754/


All Articles