Skip to content

Commit d216fee

Browse files
committed
Refactor perlin
The prior definition used static arrays of initial values, common to all instances of the perlin class. The new refactor defines everything as instance variables, with private methods. Value arrays are initialized on construction, and deleted on destruction. A much simpler implementation. Note that I originally tried using `std::unique_ptr`, but as we're trying to keep the C++ features to C++11, the `unique_ptr` class has some awkwardness around array create. In addition, these arrays are private, allocated only on construction, and deleted on destruction, so a new/delete approach keeps things simple.
1 parent 683c5f9 commit d216fee

File tree

2 files changed

+190
-141
lines changed

2 files changed

+190
-141
lines changed

books/RayTracingTheNextWeek.html

Lines changed: 124 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,17 @@
10591059
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
10601060
class perlin {
10611061
public:
1062+
perlin() {
1063+
init();
1064+
}
1065+
1066+
~perlin() {
1067+
delete[] ranfloat;
1068+
delete[] perm_x;
1069+
delete[] perm_y;
1070+
delete[] perm_z;
1071+
}
1072+
10621073
double noise(const vec3& p) const {
10631074
auto u = p.x() - floor(p.x());
10641075
auto v = p.y() - floor(p.y());
@@ -1069,47 +1080,44 @@
10691080
return ranfloat[perm_x[i] ^ perm_y[j] ^ perm_z[k]];
10701081
}
10711082

1072-
public:
1083+
private:
10731084
static const int point_count = 256;
1074-
static double* ranfloat;
1075-
static int* perm_x;
1076-
static int* perm_y;
1077-
static int* perm_z;
1078-
};
1079-
1080-
static double* perlin_generate() {
1081-
static double p[perlin::point_count];
1085+
double* ranfloat;
1086+
int* perm_x;
1087+
int* perm_y;
1088+
int* perm_z;
1089+
1090+
void init() {
1091+
ranfloat = new double[point_count];
1092+
for (int i = 0; i < point_count; ++i) {
1093+
ranfloat[i] = random_double();
1094+
}
10821095

1083-
for (int i = 0; i < perlin::point_count; ++i)
1084-
p[i] = random_double();
1096+
perm_x = perlin_generate_perm();
1097+
perm_y = perlin_generate_perm();
1098+
perm_z = perlin_generate_perm();
1099+
}
10851100

1086-
return p;
1087-
}
1101+
static int* perlin_generate_perm() {
1102+
auto p = new int[point_count];
10881103

1089-
void permute(int* p, int n) {
1090-
for (int i = n-1; i > 0; i--) {
1091-
int target = random_int(0, i);
1092-
int tmp = p[i];
1093-
p[i] = p[target];
1094-
p[target] = tmp;
1095-
}
1096-
}
1097-
1098-
static int* perlin_generate_perm(int p[]) {
1099-
for (int i = 0; i < perlin::point_count; i++)
1100-
p[i] = i;
1104+
for (int i = 0; i < perlin::point_count; i++)
1105+
p[i] = i;
11011106

1102-
permute(p, perlin::point_count);
1107+
permute(p, point_count);
11031108

1104-
return p;
1105-
}
1106-
1107-
double* perlin::ranfloat = perlin_generate();
1109+
return p;
1110+
}
11081111

1109-
int perlin_values[3][perlin::point_count];
1110-
int* perlin::perm_x = perlin_generate_perm(perlin_values[0]);
1111-
int* perlin::perm_y = perlin_generate_perm(perlin_values[1]);
1112-
int* perlin::perm_z = perlin_generate_perm(perlin_values[2]);
1112+
void permute(int* p, int n) {
1113+
for (int i = n-1; i > 0; i--) {
1114+
int target = random_int(0, i);
1115+
int tmp = p[i];
1116+
p[i] = p[target];
1117+
p[target] = tmp;
1118+
}
1119+
}
1120+
};
11131121
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11141122
[Listing [perlin]: <kbd>[perlin.h]</kbd> A Perlin texture class and functions]
11151123
</div>
@@ -1191,6 +1199,7 @@
11911199

11921200
class perlin {
11931201
public:
1202+
...
11941203
double noise(const vec3& p) const {
11951204
auto u = p.x() - floor(p.x());
11961205
auto v = p.y() - floor(p.y());
@@ -1199,6 +1208,7 @@
11991208
int j = floor(p.y());
12001209
int k = floor(p.z());
12011210
double c[2][2][2];
1211+
12021212
for (int di=0; di < 2; di++)
12031213
for (int dj=0; dj < 2; dj++)
12041214
for (int dk=0; dk < 2; dk++)
@@ -1207,14 +1217,10 @@
12071217
perm_y[(j+dj) & 255] ^
12081218
perm_z[(k+dk) & 255]
12091219
];
1220+
12101221
return trilinear_interp(c, u, v, w);
12111222
}
1212-
1213-
public:
1214-
static const int point_count = 256;
1215-
static int* perm_x;
1216-
static int* perm_y;
1217-
static int* perm_z;
1223+
...
12181224
}
12191225
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12201226
[Listing [perlin-trilinear]: <kbd>[perlin.h]</kbd> Perlin with trilienear interpolation]
@@ -1235,6 +1241,7 @@
12351241
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
12361242
class perlin (
12371243
public:
1244+
...
12381245
double noise(const vec3& p) const {
12391246
auto u = p.x() - floor(p.x());
12401247
auto v = p.y() - floor(p.y());
@@ -1296,12 +1303,23 @@
12961303
max off the lattice. So, first we need to change the random floats to random vectors:
12971304

12981305
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1299-
vec3* perlin::ranvec = perlin_generate();
1300-
1301-
int perlin_values[3][perlin::point_count];
1302-
int* perlin::perm_x = perlin_generate_perm(perlin_values[0]);
1303-
int* perlin::perm_y = perlin_generate_perm(perlin_values[1]);
1304-
int* perlin::perm_z = perlin_generate_perm(perlin_values[2]);
1306+
class perlin {
1307+
public:
1308+
...
1309+
~perlin() {
1310+
delete[] ranvec;
1311+
delete[] perm_x;
1312+
delete[] perm_y;
1313+
delete[] perm_z;
1314+
}
1315+
...
1316+
private:
1317+
vec3* ranvec;
1318+
int* perm_x;
1319+
int* perm_y;
1320+
int* perm_z;
1321+
...
1322+
}
13051323
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13061324
[Listing [perlin-randunit]: <kbd>[perlin.h]</kbd> Perlin with random unit translations]
13071325
</div>
@@ -1311,14 +1329,22 @@
13111329
exactly uniform:
13121330

13131331
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1314-
static vec3* perlin_generate() {
1315-
static vec3 p[perlin::point_count];
1316-
1317-
for (int i = 0; i < perlin::point_count; ++i) {
1318-
p[i] = unit_vector(vec3::random(-1,1));
1319-
}
1332+
class perlin {
1333+
...
1334+
private:
1335+
...
1336+
void init() {
1337+
ranvec = new vec3[point_count];
1338+
1339+
for (int i = 0; i < point_count; ++i) {
1340+
ranvec[i] = unit_vector(vec3::random(-1,1));
1341+
}
13201342

1321-
return p;
1343+
perm_x = perlin_generate_perm();
1344+
perm_y = perlin_generate_perm();
1345+
perm_z = perlin_generate_perm();
1346+
}
1347+
...
13221348
}
13231349
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13241350
[Listing [perlin-gen-2]: <kbd>[perlin.h]</kbd> New perlin_generate()]
@@ -1330,6 +1356,7 @@
13301356
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
13311357
class perlin {
13321358
public:
1359+
...
13331360
double noise(const vec3& p) const {
13341361
auto u = p.x() - floor(p.x());
13351362
auto v = p.y() - floor(p.y());
@@ -1338,6 +1365,7 @@
13381365
int j = floor(p.y());
13391366
int k = floor(p.z());
13401367
vec3 c[2][2][2];
1368+
13411369
for (int di=0; di < 2; di++)
13421370
for (int dj=0; dj < 2; dj++)
13431371
for (int dk=0; dk < 2; dk++)
@@ -1346,15 +1374,10 @@
13461374
perm_y[(j+dj) & 255] ^
13471375
pexm_z[(k+dk) & 255]
13481376
];
1377+
13491378
return perlin_interp(c, u, v, w);
13501379
}
1351-
1352-
public:
1353-
static const int point_count = 256;
1354-
static vec3* ranvec;
1355-
static int* perm_x;
1356-
static int* perm_y;
1357-
static int* perm_z;
1380+
...
13581381
}
13591382
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13601383
[Listing [perlin-2]: <kbd>[perlin.h]</kbd> The perlin class so far]
@@ -1364,21 +1387,29 @@
13641387
And the interpolation becomes a bit more complicated:
13651388

13661389
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1367-
inline double perlin_interp(vec3 c[2][2][2], double u, double v, double w) {
1368-
auto uu = u*u*(3-2*u);
1369-
auto vv = v*v*(3-2*v);
1370-
auto ww = w*w*(3-2*w);
1371-
auto accum = 0.0;
1372-
for (int i=0; i < 2; i++)
1373-
for (int j=0; j < 2; j++)
1374-
for (int k=0; k < 2; k++) {
1375-
vec3 weight_v(u-i, v-j, w-k);
1376-
accum += (i*uu + (1-i)*(1-uu))
1377-
* (j*vv + (1-j)*(1-vv))
1378-
* (k*ww + (1-k)*(1-ww))
1379-
* dot(c[i][j][k], weight_v);
1380-
}
1381-
return accum;
1390+
class perlin {
1391+
...
1392+
private:
1393+
...
1394+
inline double perlin_interp(vec3 c[2][2][2], double u, double v, double w) {
1395+
auto uu = u*u*(3-2*u);
1396+
auto vv = v*v*(3-2*v);
1397+
auto ww = w*w*(3-2*w);
1398+
auto accum = 0.0;
1399+
1400+
for (int i=0; i < 2; i++)
1401+
for (int j=0; j < 2; j++)
1402+
for (int k=0; k < 2; k++) {
1403+
vec3 weight_v(u-i, v-j, w-k);
1404+
accum += (i*uu + (1-i)*(1-uu))
1405+
* (j*vv + (1-j)*(1-vv))
1406+
* (k*ww + (1-k)*(1-ww))
1407+
* dot(c[i][j][k], weight_v);
1408+
}
1409+
1410+
return accum;
1411+
}
1412+
...
13821413
}
13831414
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13841415
[Listing [perlin-interp]: <kbd>[perlin.h]</kbd> Perlin interpolation function so far]
@@ -1421,17 +1452,24 @@
14211452
turbulence and is a sum of repeated calls to noise:
14221453

14231454
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1424-
double turb(const vec3& p, int depth=7) const {
1425-
auto accum = 0.0;
1426-
vec3 temp_p = p;
1427-
auto weight = 1.0;
1428-
for (int i = 0; i < depth; i++) {
1429-
accum += weight*noise(temp_p);
1430-
weight *= 0.5;
1431-
temp_p *= 2;
1432-
}
1433-
return fabs(accum);
1434-
}
1455+
class perlin {
1456+
...
1457+
public:
1458+
...
1459+
double turb(const vec3& p, int depth=7) const {
1460+
auto accum = 0.0;
1461+
vec3 temp_p = p;
1462+
auto weight = 1.0;
1463+
1464+
for (int i = 0; i < depth; i++) {
1465+
accum += weight*noise(temp_p);
1466+
weight *= 0.5;
1467+
temp_p *= 2;
1468+
}
1469+
1470+
return fabs(accum);
1471+
}
1472+
...
14351473
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14361474
[Listing [perlin-turb]: <kbd>[perlin.h]</kbd> Turbulence function]
14371475
</div>

0 commit comments

Comments
 (0)