I am trying my attempt at Perlin Noise (3-dimensional) as outlined in this document: http://lodev.org/cgtutor/randomnoise.html
However, this is what I'm getting.
It looks like the smoothing isn't working. You can see blocks the size of the 'size' parameter. Can someone point out what I'm doing wrong?
Here's my code:
%ffp
ctl(1):standard,"Size",range=(1,256), pos=(300,20), size=(120,*),val=64,track, action=preview
onFilterStart:
{
allocArray(9,64,64,64,4); // Array for noise depth
for(int z = 0; z < 64; z++)
for(int y = 0; y < 64; y++)
for(int x = 0; x < 64; x++) {
fputArray(9,x,y,z,(float)(rand() % 32768) / 32768.0);
}
return false;
}
forEveryTile:
{
double fractX,fractY,fractZ,xx,yy,zz;
int x1,y1,z1,x2,y2,z2,col;
double value = 0.0, value2 = 0.0, size, isize=(float)ctl(1);
// int X=screen Width, int Y=screen Height
for(int y = 0; y < Y; y++) {
for(int x = 0; x < X; x++) {
//for(int z = 0; z < 64; z++) {
value2 = 0.0;
size = isize;
while (size >=1.0) {
xx=(float)x/size;
yy=(float)y/size;
zz=(float)clock()/size;
fractX = xx - (int)(xx);
fractY = yy - (int)(yy);
fractZ = zz - (int)(zz);
x1 = ((int)(xx) + 64) % 64;
y1 = ((int)(yy) + 64) % 64;
z1 = ((int)(zz) + 64) % 64;
x2 = (x1 + 64- 1) % 64;
y2 = (y1 + 64- 1) % 64;
z2 = (z1 + 64- 1) % 64;
value=0.0;
value += fractX * fractY * fractZ * fgetArray(9,z1,y1,x1);
value += fractX * (1 - fractY) * fractZ * fgetArray(9,z1,y2,x1);
value += (1 - fractX) * fractY * fractZ * fgetArray(9,z1,y1,x2);
value += (1 - fractX) * (1 - fractY) * fractZ * fgetArray(9,z1,y2,x2);
value += fractX * fractY * (1 - fractZ) * fgetArray(9,z2,y1,x1);
value += fractX * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x1);
value += (1 - fractX) * fractY * (1 - fractZ) * fgetArray(9,z2,y1,x2);
value += (1 - fractX) * (1 - fractY) * (1 - fractZ) * fgetArray(9,z2,y2,x2);
value2 += value*size;
size /= 2.0;
}
col=(int)((float)(128.0 * value2 / isize));
col=max(min(col,255),0);
psetp(x,y,RGB(col,col,col));
//} //z
} //x
} //y
return true;
}
Your code is kind of hard to read as written.
For Perlin noise start out with a integer noise function, that behaves like a hash.
float noise(int x, int y, int z) { return hash(x+y*5+z*7); }
or
float noise(int x, int y, int z) { return array[x%w+y%h*w+z%d*w*h]; }
Those are just examples. The important part is that noise(x,y,z) = noise(x,y,z). The noise function has to return the same value for the same parameters every time.
There is a problem though: The noise function only takes integer parameters! But we would like to sample it at float values.
float noisesample (float x, float y, float z) { ... }
The easiest way to to that is using linear filtering. Any positive float value is between (int)pos and ((int)pos)+1. At sub-position pos-(int)pos. This gets us:
float Lerp(float a, float b, float f) { return a+(b-a)*f; }
Where f is the sub-position in the [0..1] range and a,b are the values to the left and right. If f is 0, Lerp returns a, if it is 1, it returns b. In between it does linear interpolation.
So use this for a simple 1D noisesample function:
float noisesample(float x) { return Lerp(noise((int)x), noise((int)x+1), fract(x) }
with
float fract(float x) { return x-(int)x; }
I am using (int)x liberally here, it is the same as floor(x) if x is positive.
To go from a single parameter noisesample to x,y is easy: Do the Lerp twice for x at y and y+1, and Lerp between those:
float noisesample(float x, float y) {
float y0 = Lerp(noise((int)x,(int)y), noise((int)x+1,(int)y), fract(x) }
float y1 = Lerp(noise((int)x,(int)y+1), noise((int)x+1,(int)y+1), fract(x) }
return Lerp ( y0, y1, fract(y) );
}
First interpolate x, twice, then interpolate between the results in y. In total we sample noise() 4 times. I leave it as an exercise how to write noisesample ( float x, float y, float z). It will sample noise() eight times and call Lerp 7 times.
All that got us is that we can sample noise (somewhat smooth - there are smoother ways!) at float coordinates. And that is what we need to make perlin noise!
float perlin(float x, float y, float z, int oc=4) {
// maybe: x = x*2^oc, y, z...
float r = 0;
float s = 1;
for ( int i=0; i<oc; i++ ) {
r += noisesample(x,y,z) * s;
s/=2.0f; // to taste
x/=2.0f;
y/=2.0f;
z/=2.0f;
}
return r;
}
The key idea is to understand sampling. It's just a combination of sampling a simple integer noise function.
Related
I use floating point numbers in my code (c code with openGL) to operate with colors, but the graphic I am using is in the rgb byte format. Loaded with the following code everything works correctly:
//... glfw window initialization...
for (int y = 0; y < 32; y++)
{
for (int x = 0; x < 32; x++)
{
int p = (y * 32 + x) * 3;
float r = rgb[p];
float g = rgb[p + 1];
float b = rgb[p + 2];
glColor3ub(r, g, b);
glPointSize(16);
glBegin(GL_POINTS);
glVertex2i(x * 16, y * 16);
glEnd();
}
}
Resulting in:
The error occurs if I try to normalize the bytes (one by one) with the following code:
//... glfw window initialization...
for (int y = 0; y < 32; y++)
{
for (int x = 0; x < 32; x++)
{
int p = (y * 32 + x) * 3;
float r = ((float)rgb[p]) / 255.0f;
float g = ((float)rgb[p + 1]) / 255.0f;
float b = ((float)rgb[p + 2]) / 255.0f;
glColor3f(r,g, b);
glPointSize(16);
glBegin(GL_POINTS);
glVertex2i(x * 16, y * 16);
glEnd();
}
}
The picture loaded this way has different colors:
Suppose the array rbg[] is signed, and consider a red component value 255.
In the first example the 255 is actually -1 and is converted to -1.000000 and this is then passed to the function after converting to type GLubyte which is unsigned 8-bit. The conversion rules will make this value 255 which is what you thought you had.
In the second example the 255 is again converted to -1.000000 and scaled to be -0.003922 instead of the expected 1.000000and so the result is very different from what you expected.
The solution is to define the array as unsigned char or uint8_t.
I'm trying to write out pixles on a LCD. I'm plotting them at X, Y coordinates and I'm using this code:
void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1){
uint8_t k = (x1 - x0)/(y1 - y0);
uint8_t y = y0;
for(uint8_t x = x0; x < x1; x++){
pixel(x, y, true);
y += k;
}
}
The problem where is that if k becomes a decimal number e.g 1.98, then k will still 1. If k = 2.01, then k = 2 due to the uint8_t datatype.
Assume that we are going to plot the line (0,0), (40, 20) {x,y}.
Sure, now k will be 2. That works!
But assume that if we plot the line (0,0), (35, 20) {x,y}.
Now k will be a float number of 1.75. This will not work for me.
Is there a way to find a better k?
I have tried this, but the line does not follow the coordinates.
void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1){
float k = 0;
if(y1 > x1){
k = (y1 - y0)/(x1 - x0);
}else{
k = (x1 - x0)/(y1 - y0);
}
float y = y0;
for(uint8_t x = x0; x < x1; x++){
pixel(x, (uint8_t) y, true);
y += k;
}
}
Instead of attempting FP math, research Bresenham's line algorithm for an all integer solution.
Untested code:
void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1) {
int dx = x1 - x0;
int dy = y1 - y0;
int D = 2*dy - dx;
int y = y0;
// code still needs work when x0 > x1 or |dy| > |dx|
for (int x = x0; x <= x1; x++) {
pixel(x,y,true);
if (D > 0) {
y++;
D = D - 2*dx;
}
D = D + 2*dy;
}
}
You were on the right path with changing k and y to data type float.
But in addition to that, you need to make sure that the right hand side of
k = (y1 - y0)/(x1 - x0);
will be a float value, too. Currently, since only integral values are involved, the result of the expression on the right hand side will be integral. So k will never receive any fractional part.
To "enforce" floating point division, it is sufficient that one of the operands is of type float. You can achieve this by an explicit cast. Write, for example:
k = ((float)(y1 - y0))/(x1 - x0);
I have implemented this function:
double heron(double a)
{
double x = (a + 1) / 2;
while (x * x - a > 0.000001) {
x = 0.5 * (x + a / x);
}
return x;
}
This function is working as intended, however I would wish to improve it. It's supposed to use and endless while loop to check if something similar to x * x is a. a is the number the user should input.
So far I have no working function using that method...This is my miserably failed attempt:
double heron(double a)
{
double x = (a + 1) / 2;
while (x * x != a) {
x = 0.5 * (x + a / x);
}
return x;
}
This is my first post so if there is anything unclear or something I should add please let me know.
Failed attempt number 2:
double heron(double a)
{
double x = (a + 1) / 2;
while (1) {
if (x * x == a){
break;
} else {
x = 0.5 * (x + a / x);
}
}
return x;
}
Heron's formula
It's supposed to use and endless while loop to check if something similar to x * x is a
Problems:
Slow convergence
When the initial x is quite wrong, the improved |x - sqrt(a)| error may still be only half as big. Given the wide range of double, the may take hundreds of iterations to get close.
Ref: Heron's formula.
For a novel 1st estimation method: Fast inverse square root.
Overflow
x * x in x * x != a is prone to overflow. x != a/x affords a like test without that range problem. Should overflow occur, x may get "infected" with "infinity" or "not-a-number" and fail to achieve convergence.
Oscillations
Once x is "close" to sqrt(a) (within a factor of 2) , the error convergence is quadratic - the number of bits "right" doubles each iteration. This continues until x == a/x or, due to peculiarities of double math, x will endlessly oscillate between two values as will the quotient.
Getting in this oscillation causes OP's loop to not terminate
Putting this together, with a test harness, demonstrates adequate convergence.
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
double rand_finite_double(void) {
union {
double d;
unsigned char uc[sizeof(double)];
} u;
do {
for (unsigned i = 0; i < sizeof u.uc; i++) {
u.uc[i] = (unsigned char) rand();
}
} while (!isfinite(u.d));
return u.d;
}
double sqrt_heron(double a) {
double x = (a + 1) / 2;
double x_previous = -1.0;
for (int i = 0; i < 1000; i++) {
double quotient = a / x;
if (x == quotient || x == x_previous) {
if (x == quotient) {
return x;
}
return ((x + x_previous) / 2);
}
x_previous = x;
x = 0.5 * (x + quotient);
}
// As this code is (should) never be reached, the `for(i)`
// loop "safety" net code is not needed.
assert(0);
}
double test_heron(double xx) {
double x0 = sqrt(xx);
double x1 = sqrt_heron(xx);
if (x0 != x1) {
double delta = fabs(x1 - x0);
double err = delta / x0;
static double emax = 0.0;
if (err > emax) {
emax = err;
printf(" %-24.17e %-24.17e %-24.17e %-24.17e\n", xx, x0, x1, err);
fflush(stdout);
}
}
return 0;
}
int main(void) {
for (int i = 0; i < 100000000; i++) {
test_heron(fabs(rand_finite_double()));
}
return 0;
}
Improvements
sqrt_heron(0.0) works.
Change code for a better initial guess.
double sqrt_heron(double a) {
if (a > 0.0 && a <= DBL_MAX) {
// Better initial guess - halve the exponent of `a`
// Could possible use bit inspection if `double` format known.
int expo;
double significand = frexp(a, &expo);
double x = ldexp(significand, expo / 2);
double x_previous = -1.0;
for (int i = 0; i < 8; i++) { // Notice limit moved from 1000 down to < 10
double quotient = a / x;
if (x == quotient) {
return x;
}
if (x == x_previous) {
return (0.5 * (x + x_previous));
}
x_previous = x;
x = 0.5 * (x + quotient);
}
assert(0);
}
if (a >= 0.0) return a;
assert(0); // invalid argument.
}
I have a 2D plane in three dimensions: x+y+z=1, and I want to generate random points(x,y,z) on the plane. How can I choose these points so that they are distributed uniformly?
The Problem
As mentioned in the comments, the question was under specified. Despite that it's a interesting question. Because no distribution was given I just picked one. Here is the more precise(?)/general(?) question I will answer:
Suppose I have a plane P in R^3 defined by ax + by + cz = d.
Let c be in the point on P closest to the origin.
How can I uniformly choose a point on P within some radius r of c?
The Algorithm
Let n = (a,b,c). n is the vector normal to P.
direction
Generate any non-zero vector on the plane ax + by + cz = d, call it w. You can do this by taking the cross product of n with any non-zero vector not parallel to n.
Rotate w around n by a random angle in [0,2pi). You can do this using http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula.
so , now you got direction by normalizing it
direction = direction / direction.magnitude
origin of the ray
If d is 0, we're done. Otherwise:
Calculate c = distance of plane from Vector3(0 , 0 , 0)
according to http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane.
Translate Origin of ray
origin of the ray = vector3.zero + c * ( n )
scale = random.range(min , max)
So the point is
origin_of_the_ray + scale * (direction_)
The Code
Here is my C implementation of the algorithm. I wrote all the vector machinery from scratch so it's a little messy. I have not tested this throughly.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
typedef struct {
double x, y, z;
} vec3;
vec3 vec(double x, double y, double z);
vec3 crossp(vec3 u, vec3 v);
vec3 add(vec3 u, vec3 v);
double dotp(vec3 u, vec3 v);
double norm2(vec3 u);
double norm(vec3 u);
vec3 scale(vec3 u, double s);
vec3 normalize(vec3 u);
void print_vec3(vec3 u);
// generates a random point on the plane ax + by + cz = d
vec3 random_on_plane(double r, double a, double b, double c, double d) {
// The normal vector for the plane
vec3 n = vec(a, b, c);
// create a normal vector on the plane ax + by + cz = 0
// we take any vector not parallel to n
// and find the cross product
vec3 w;
if (n.x == 0)
w = crossp(n, vec(1,0,0));
else
w = crossp(n, vec(0,0,1));
// rotate the vector around n by a random angle
// using Rodrigues' rotation formula
// http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
double theta = ((double)rand() / RAND_MAX) * M_PI;
vec3 k = normalize(n);
w = add(scale(w, cos(theta)),
scale(crossp(k, w), sin(theta)));
// Scale the vector fill our disk.
// If the radius is zero, generate unit vectors
if (r == 0) {
w = scale(w, r/norm(w));
} else {
double rand_r = ((double)rand() / RAND_MAX) * r;
w = scale(w, rand_r/norm(w));
}
// now translate the vector from ax + by + cz = 0
// to the plane ax + by + cz = d
// http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_plane
if (d != 0) {
vec3 t = scale(n, d / norm2(n));
w = add(w, t);
}
return w;
}
int main(void) {
int i;
srand(time(NULL));
for (i = 0; i < 100; i++) {
vec3 r = random_on_plane(10, 1, 1, 1, 1);
printf("random v = ");
print_vec3(r);
printf("sum = %f, norm = %f\n", r.x + r.y + r.z, norm(r));
}
}
vec3 vec(double x, double y, double z) {
vec3 u;
u.x = x;
u.y = y;
u.z = z;
return u;
}
vec3 crossp(vec3 u, vec3 v) {
vec3 w;
w.x = (u.y * v.z) - (u.z * v.y);
w.y = (u.z * v.x) - (u.x * v.z);
w.z = (u.x * v.y) - (u.y * v.x);
return w;
}
double dotp(vec3 u, vec3 v) {
return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
}
double norm2(vec3 u) {
return dotp(u, u);
}
double norm(vec3 u) {
return sqrt(norm2(u));
}
vec3 scale(vec3 u, double s) {
u.x *= s;
u.y *= s;
u.z *= s;
return u;
}
vec3 add(vec3 u, vec3 v) {
u.x += v.x;
u.y += v.y;
u.z += v.z;
return u;
}
vec3 normalize(vec3 u) {
return scale(u, 1/norm(u));
}
void print_vec3(vec3 u) {
printf("%f %f %f\n", u.x, u.y, u.z);
}
Eugene had it almost right: generate two random numbers on the interval [0,1), call them A, B. Then x = min(A,B), y = max(A,B) - x, z = 1 - (x + y). Basically, you pick two points on the line [0,1) and your three coordinates are the three intervals defined by those two points.
I'll first give you a simple algorithm
x = rand()
y = rand()
z = 1 - x - y
Now lets see an implementation of that algorithm
This code will produce any sort of numbers ( +ve or -ve )
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand(time(NULL));
int x= ( rand() - rand() ) ;
int y= ( rand() - rand() ) ;
int z=1-x-y;
printf("x=%d y=%d z=%d",x,y,z);
}
just use srand() to seed the random number generator, and use rand() to assign a random number.
If you need to create random numbers with a range, then use rand() % ( maxnumber + 1 ) where maxnumber is the maximum value you want.
If you want all of your numbers to be positive, then try this
int main()
{
srand(time(NULL));
int x, y , z = -1;
while ( z < 0 )
{
x = rand() ;
y = rand() ;
z = 1 - (x + y );
}
printf("x=%d y=%d z=%d",x,y,z);
}
WARNING
the above code might take some time to execute, so don't expect an instant result
int main ()
{
int n = 0;
int base = 0;
while(n < 10)
{
int x = 2;
int answer = power(x, n);
float neganswer = negpower(x, n);
printf("%d %d %f\n", base, answer, neganswer);
base++;
n++;
}
return EXIT_SUCCESS;
}
int power(int base, int power)
{
int result, i;
result = 1;
for (i=0; i < power; i++)
{
result *= base;
}
return result;
}
int negpower(int base, int power)
{
float result, i;
result = 1.0;
for (i=0; i < power; i++)
{
result = result / base;
}
return result;
}
So I'm trying to call upon this function that i've made, and I think its calculating it correctly, however it is only outputting 1.0000000 followed directly by 0.0000000. I think I've got problems with carrying the float value, can anyone chime in?
Thanks
This is because you are returning a float from negpower() which has return type of int and assigning it to a float neganswer.
Change
int negpower(int base, int power)
to
float negpower(int base, int power)
Output:
Side note:
Always add required header files.
A prototype should be declared if a function definition appears after the main().
The answer is much simpler. Your negpower function returns an int, when you actually return a float from it. Change the prototype and it should work alright.
This is optimized library if you are interested:
#ifdef DOCUMENTATION
title pow x raised to power y
index x raised to power y
usage
.s
double x, y, f, pow();
.br
f = pow(x, y);
.s
description
.s
Returns value of x raised to power y
.s
diagnostics
.s
There are three error possible error messages from this function.
.s
If the x argument is negative the message 'pow arg negative',
followed by the value of x, is written to stderr. The value
of pow for |x| is returned.
.s
If x = 0.0 and y <= 0.0 or if result overflows the message 'pow
overflow', followed by the value of y, is written to stderr.
The value of HUGE is returned.
.s
If the result underflows and if warnings are enabled (normally not),
the message 'pow underflow', followed by the value of y, is written
to stderr. The value of 0 is returned.
.s
The suggestion of Cody and Waite, that the domain be reduced to
simplify the overflow test, has been adopted, consequently overflow
is reported if the result would exceed HUGE * 2**(-1/16).
2**(-1/16) is approximately 0.9576.
.s
internal
.s
Algorithm from Cody and Waite pp. 84-124. This algorithm required
two auxiliary programs POWGA1 and POWGA2 to calculate, respectively,
the arrays a1[] and a2[] used to represent the powers of 2**(-1/16)
to more than machine precision.
The source code for these programs are in the files POWGA1.AUX and
POWGA2.AUX. The octal table on page 98 of Cody and Waite is in the
file POWOCT.DAT which is required on stdin by POWGA2.
.s
author
.s
Hamish Ross.
.s
date
.s
27-Jan-85
#endif
#include <math.h>
#define MAXEXP 2031 /* (MAX_EXP * 16) - 1 */
#define MINEXP -2047 /* (MIN_EXP * 16) - 1 */
static double a1[] = {
1.0,
0.95760328069857365,
0.91700404320467123,
0.87812608018664974,
0.84089641525371454,
0.80524516597462716,
0.77110541270397041,
0.73841307296974966,
0.70710678118654752,
0.67712777346844637,
0.64841977732550483,
0.62092890603674203,
0.59460355750136054,
0.56939431737834583,
0.54525386633262883,
0.52213689121370692,
0.50000000000000000
};
static double a2[] = {
0.24114209503420288E-17,
0.92291566937243079E-18,
-0.15241915231122319E-17,
-0.35421849765286817E-17,
-0.31286215245415074E-17,
-0.44654376565694490E-17,
0.29306999570789681E-17,
0.11260851040933474E-17
};
static double p1 = 0.833333333333332114e-1;
static double p2 = 0.125000000005037992e-1;
static double p3 = 0.223214212859242590e-2;
static double p4 = 0.434457756721631196e-3;
static double q1 = 0.693147180559945296e0;
static double q2 = 0.240226506959095371e0;
static double q3 = 0.555041086640855953e-1;
static double q4 = 0.961812905951724170e-2;
static double q5 = 0.133335413135857847e-2;
static double q6 = 0.154002904409897646e-3;
static double q7 = 0.149288526805956082e-4;
static double k = 0.442695040888963407;
double pow(x, y)
double x, y;
{
double frexp(), g, ldexp(), r, u1, u2, v, w, w1, w2, y1, y2, z;
int iw1, m, p;
if (y == 0.0)
return(1.0);
if (x <= 0.0) {
if (x == 0.0) {
if (y > 0.0)
return(x);
cmemsg(FP_POWO, &y);
return(HUGE);
}
else {
cmemsg(FP_POWN, &x);
x = -x;
}
}
g = frexp(x, &m);
p = 0;
if (g <= a1[8])
p = 8;
if (g <= a1[p + 4])
p += 4;
if (g <= a1[p + 2])
p += 2;
p++;
z = ((g - a1[p]) - a2[p / 2]) / (g + a1[p]);
z += z;
v = z * z;
r = (((p4 * v + p3) * v + p2) * v + p1) * v * z;
r += k * r;
u2 = (r + z * k) + z;
u1 = 0.0625 * (double)(16 * m - p);
y1 = 0.0625 * (double)((int)(16.0 * y));
y2 = y - y1;
w = u2 * y + u1 * y2;
w1 = 0.0625 * (double)((int)(16.0 * w));
w2 = w - w1;
w = w1 + u1 * y1;
w1 = 0.0625 * (double)((int)(16.0 * w));
w2 += (w - w1);
w = 0.0625 * (double)((int)(16.0 * w2));
iw1 = 16.0 * (w1 + w);
w2 -= w;
while (w2 > 0.0) {
iw1++;
w2 -= 0.0625;
}
if (iw1 > MAXEXP) {
cmemsg(FP_POWO, &y);
return(HUGE);
}
if (iw1 < MINEXP) {
cmemsg(FP_POWU, &y);
return(0.0);
}
m = iw1 / 16;
if (iw1 >= 0)
m++;
p = 16 * m - iw1;
z = ((((((q7*w2 + q6)*w2 + q5)*w2 + q4)*w2 + q3)*w2 + q2)*w2 + q1)*w2;
z = a1[p] + a1[p] * z;
return(ldexp(z, m));
}
You have all sorts of ints in there. When you do that, the decimal gets truncated. You should make your power functions return floats, and use a float base.