Skip to content

Commit

Permalink
fix and improved the hash function in Perlin noise generator.
Browse files Browse the repository at this point in the history
update WorleyNoise3DGeneratorTemplate to return a squared closest distance instead of a closest distance.
WIP: implement CloudMediumDistribution.
  • Loading branch information
shocker-0x15 committed Jul 22, 2017
1 parent f265c77 commit 5b4beb9
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 115 deletions.
121 changes: 45 additions & 76 deletions TestScenes/Cornell_Box_Boxes_Medium.txt
Original file line number Diff line number Diff line change
@@ -1,44 +1,12 @@
// Dusty Cornell Box

//setRenderer("method": "Volumetric PT", ("samples": 16384,));
setRenderer("method": "Volumetric BPT", ("samples": 16384,));
setRenderer("method": "Volumetric PT", ("samples": 16384,));
//setRenderer("method": "Volumetric BPT", ("samples": 16384,));
setRenderSettings("width": 1024, "height": 1024);

function CBMat(name, attrs) {
// if (name == "Material.002")
// return createSurfaceMaterial("matte", (SpectrumTexture(Spectrum(0.5, 0.5, 0.5)),));
return;
}

cornellBoxNode = createNode();
cornellBox = load3DModel("models/Cornell_box_RB.assbin", CBMat);
addChild(cornellBoxNode, cornellBox);

lightNode = createNode();
setTransform(lightNode, translate(0.0, 0.999, 0.0));
diffuseCol = Spectrum(0.9, 0.9, 0.9);
diffuseTex = SpectrumTexture(diffuseCol);
scatterMat = createSurfaceMaterial("matte", (diffuseTex,));
difLightCol = Spectrum("Illuminant", 500);
difLightTex = SpectrumTexture(difLightCol);
emitterMat = createEmitterSurfaceProperty("diffuse", (difLightTex,));
//emitterMat = createEmitterSurfaceProperty("ideal directional", (difLightTex, Vector(1, 0.25, 2)));
surfMat = createSurfaceMaterial("emitter", (scatterMat, emitterMat));

lightMesh = createMesh(
(
((-0.25, 0, -0.25), (0, -1, 0), (1, 0, 0), (0, 0)),
(( 0.25, 0, -0.25), (0, -1, 0), (1, 0, 0), (1, 0)),
(( 0.25, 0, 0.25), (0, -1, 0), (1, 0, 0), (1, 1)),
((-0.25, 0, 0.25), (0, -1, 0), (1, 0, 0), (0, 1))
),
(
(surfMat, ((0, 1, 2), (0, 2, 3))),
)
);
addChild(lightNode, lightMesh);
addChild(cornellBoxNode, lightNode);
addChild(root, cornellBoxNode);
groundAlbedo = Spectrum(0.1, 0.1, 0.3);
envTex = SpectrumTexture("sky", (0.2 * 3.1415926536 / 2, 2, groundAlbedo));
setEnvironment(envTex, 30);

//leftBoxNode = createNode();
// function leftBoxMat(name, attrs) {
Expand Down Expand Up @@ -79,51 +47,52 @@ medium0Node = createNode();
// Spectrum(360, 830, (0.4, 0.4)),
// Spectrum(360, 830, (0.5, 0.5)),
// medMat);
// medium0 = createCloudMedium(Point(-0.5, -0.5, -0.5), Point(0.5, 0.5, 0.5),
// 1.0, 4.0, 1461287313, medMat);
medium0 = createGridMedium(Point(-0.5, -0.5, -0.5), Point(0.5, 0.5, 0.5),
Spectrum((360, 830), (0.09, 0.09)),
Spectrum((360, 830), (0.1, 0.1)),
"Cloud0_256x256x256.vdg", medMat);
medium0 = createCloudMedium(Point(-5.0, 1.5, -5.0) * 1000, Point(5.0, 2.0, 5.0) * 1000,
0.1, 0.001, 1461287313, medMat);
// medium0 = createGridMedium(Point(-0.5, -0.5, -0.5), Point(0.5, 0.5, 0.5),
// Spectrum((360, 830), (0.09, 0.09)),
// Spectrum((360, 830), (0.1, 0.1)),
// "Cloud0_256x256x256.vdg", medMat);
addChild(medium0Node, medium0);
//setTransform(medium0Node, rotateY(0.7853981634) * rotateX(0.7853981634));
addChild(cornellBoxNode, medium0Node);

idolNode = createNode();
function idolMat(name, attrs) {
// etaExt = SpectrumTexture(Spectrum("ID": "Air", 0));
// etaInt = SpectrumTexture(Spectrum("ID": "Glass_BK7", 0));
// coeff = SpectrumTexture(Spectrum("Reflectance", 0.999));
// return createSurfaceMaterial("glass", (coeff, etaExt, etaInt));
addChild(root, medium0Node);

etaExt = Spectrum("IoR", "Air", 0);
etaInt = Spectrum("IoR", "Water", 0);
alpha_g = 0.01;
surfMat = createSurfaceMaterial("microfacet glass", (SpectrumTexture(etaExt), SpectrumTexture(etaInt), FloatTexture(alpha_g)));
normalMap = NormalTexture("voronoi", (0.01, 3.14 / 12));
return (surfMat, normalMap);
}
function idolMeshCallback(name, mesh, minP, maxP) {
//sigma_s = Spectrum((360, 830), (1.0, 1.0));
//sigma_e = Spectrum((360, 830), (2.0, 10.0));
//sigma_s = Spectrum(651.6, 687.8, 724, "space": "Rec709");
//sigma_e = Spectrum(724, 724, 724, "space": "Rec709");

//medMat = createMediumMaterial("isotropic", (,));
//medium = createHomogeneousMedium(minP, maxP, sigma_s, sigma_e, medMat);
medium = createVacuum(minP, maxP);
setInternalMedium(mesh, medium);
return true;
}
idol = load3DModel("models/bunny.assbin", idolMat, idolMeshCallback);
addChild(idolNode, idol);
setTransform(idolNode, translate(0, -1, 0) * scale(1.0));
//addChild(cornellBoxNode, idolNode);
//idolNode = createNode();
// function idolMat(name, attrs) {
//// etaExt = SpectrumTexture(Spectrum("ID": "Air", 0));
//// etaInt = SpectrumTexture(Spectrum("ID": "Glass_BK7", 0));
//// coeff = SpectrumTexture(Spectrum("Reflectance", 0.999));
//// return createSurfaceMaterial("glass", (coeff, etaExt, etaInt));
//
// etaExt = Spectrum("IoR", "Air", 0);
// etaInt = Spectrum("IoR", "Water", 0);
// alpha_g = 0.01;
// surfMat = createSurfaceMaterial("microfacet glass", (SpectrumTexture(etaExt), SpectrumTexture(etaInt), FloatTexture(alpha_g)));
// normalMap = NormalTexture("voronoi", (0.01, 3.14 / 12));
// return (surfMat, normalMap);
// }
// function idolMeshCallback(name, mesh, minP, maxP) {
// //sigma_s = Spectrum((360, 830), (1.0, 1.0));
// //sigma_e = Spectrum((360, 830), (2.0, 10.0));
// //sigma_s = Spectrum(651.6, 687.8, 724, "space": "Rec709");
// //sigma_e = Spectrum(724, 724, 724, "space": "Rec709");
//
// //medMat = createMediumMaterial("isotropic", (,));
// //medium = createHomogeneousMedium(minP, maxP, sigma_s, sigma_e, medMat);
// medium = createVacuum(minP, maxP);
// setInternalMedium(mesh, medium);
// return true;
// }
// idol = load3DModel("models/bunny.assbin", idolMat, idolMeshCallback);
// addChild(idolNode, idol);
//setTransform(idolNode, translate(0, -1, 0) * scale(1.0));
////addChild(cornellBoxNode, idolNode);

cameraNode = createNode();
camera = createPerspectiveCamera("aspect": 1.0, "fovY": 0.5235987756, "radius": 0.025,
camera = createPerspectiveCamera("aspect": 1.0, "fovY": 0.5235987756, "radius": 0.0,
"imgDist": 1.0, "objDist": 4.5);
addChild(cameraNode, camera);
setTransform(cameraNode, translate(0, 0, 5) * rotateY(-3.1415926536));
setTransform(cameraNode, translate(0, 1.75 * 1000, 10 * 1000) * rotateY(-3.1415926536));

addChild(root, cameraNode);
setTransform(root, rotateY(-1.57));
73 changes: 42 additions & 31 deletions libSLR/Core/distributions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,17 @@ namespace SLR {



template <typename RealType>
uint8_t ImprovedPerlinNoise3DGeneratorTemplate<RealType>::hash(int32_t x, int32_t y, int32_t z) {
uint32_t sum = 0;
sum += PermutationTable[ 0 + (PermutationTable[ 0 + (PermutationTable[ 0 + x % 11] + y) % 11] + z) % 11];
sum += PermutationTable[11 + (PermutationTable[11 + (PermutationTable[11 + x % 13] + y) % 13] + z) % 13];
sum += PermutationTable[24 + (PermutationTable[24 + (PermutationTable[24 + x % 16] + y) % 16] + z) % 16];
sum += PermutationTable[40 + (PermutationTable[40 + (PermutationTable[40 + x % 17] + y) % 17] + z) % 17];
sum += PermutationTable[57 + (PermutationTable[57 + (PermutationTable[57 + x % 19] + y) % 19] + z) % 19];
return sum % 16;
}

template <typename RealType>
RealType ImprovedPerlinNoise3DGeneratorTemplate<RealType>::gradient(uint32_t hash, RealType xu, RealType yu, RealType zu) {
switch (hash & 0xF) {
Expand Down Expand Up @@ -417,6 +428,8 @@ namespace SLR {
z += m_repeat;
}

// Calculate the "unit cube" that the point asked will be located in.
// The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that plus 1.
int32_t iEvalCoord[3];
iEvalCoord[0] = std::floor(x);
iEvalCoord[1] = std::floor(y);
Expand All @@ -429,9 +442,7 @@ namespace SLR {
// 6t^5 - 15t^4 + 10t^3
return t * t * t * (t * (t * 6 - 15) + 10);
};

// Calculate the "unit cube" that the point asked will be located in.
// The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that plus 1.

// Next we calculate the location (from 0.0 to 1.0) in that cube.
// We also fade the location to smooth the result.
RealType xu = x - iEvalCoord[0];
Expand All @@ -442,25 +453,25 @@ namespace SLR {
RealType v = fade(yu);
RealType w = fade(zu);

// Code in the reference site uses a permutation table of size 256.
// It imposes the repetition pattern of size 256 even if repetition is not specified.
// Modified it by instead using a pseudo random number generator based on integer coordinate.
uint8_t cornerHashes[8];
for (int iz = 0; iz < 2; ++iz) {
for (int iy = 0; iy < 2; ++iy) {
for (int ix = 0; ix < 2; ++ix) {
int32_t iCoord[3] = {iEvalCoord[0] + ix, iEvalCoord[1] + iy, iEvalCoord[2] + iz};
if (m_repeat > 0) {
iCoord[0] %= m_repeat;
iCoord[1] %= m_repeat;
iCoord[2] %= m_repeat;
}
uint32_t hash = getFNV1Hash32((uint8_t*)iCoord, sizeof(iCoord));
LinearCongruentialRNG rng(hash);
cornerHashes[4 * iz + 2 * iy + ix] = (rng.getUInt() >> 24) & 0xF;
}
}
}
const auto inc = [this](int32_t num) {
++num;
if (m_repeat > 0)
num %= m_repeat;
return num;
};

const int32_t xi = iEvalCoord[0];
const int32_t yi = iEvalCoord[1];
const int32_t zi = iEvalCoord[2];
uint8_t lll, llu, lul, luu, ull, ulu, uul, uuu;
lll = hash( xi , yi , zi );
ull = hash(inc(xi), yi , zi );
lul = hash( xi , inc(yi), zi );
uul = hash(inc(xi), inc(yi), zi );
llu = hash( xi , yi , inc(zi));
ulu = hash(inc(xi), yi , inc(zi));
luu = hash( xi , inc(yi), inc(zi));
uuu = hash(inc(xi), inc(yi), inc(zi));

const auto lerp = [](RealType v0, RealType v1, RealType t) {
return v0 * (1 - t) + v1 * t;
Expand All @@ -469,12 +480,12 @@ namespace SLR {
// The gradient function calculates the dot product between a pseudorandom gradient vector and
// the vector from the input coordinate to the 8 surrounding points in its unit cube.
// This is all then lerped together as a sort of weighted average based on the faded (u,v,w) values we made earlier.
RealType _llValue = lerp(gradient(cornerHashes[0], xu, yu, zu), gradient(cornerHashes[1], xu - 1, yu, zu), u);
RealType _ulValue = lerp(gradient(cornerHashes[2], xu, yu - 1, zu), gradient(cornerHashes[3], xu - 1, yu - 1, zu), u);
RealType _llValue = lerp(gradient(lll, xu, yu, zu), gradient(ull, xu - 1, yu, zu), u);
RealType _ulValue = lerp(gradient(lul, xu, yu - 1, zu), gradient(uul, xu - 1, yu - 1, zu), u);
RealType __lValue = lerp(_llValue, _ulValue, v);

RealType _luValue = lerp(gradient(cornerHashes[4], xu, yu, zu - 1), gradient(cornerHashes[5], xu - 1, yu, zu - 1), u);
RealType _uuValue = lerp(gradient(cornerHashes[6], xu, yu - 1, zu - 1), gradient(cornerHashes[7], xu - 1, yu - 1, zu - 1), u);
RealType _luValue = lerp(gradient(llu, xu, yu, zu - 1), gradient(ulu, xu - 1, yu, zu - 1), u);
RealType _uuValue = lerp(gradient(luu, xu, yu - 1, zu - 1), gradient(uuu, xu - 1, yu - 1, zu - 1), u);
RealType __uValue = lerp(_luValue, _uuValue, v);

// For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1)
Expand Down Expand Up @@ -536,7 +547,7 @@ namespace SLR {


template <typename RealType>
void WorleyNoise3DGeneratorTemplate<RealType>::evaluate(const Point3DTemplate<RealType> &p, RealType* closestDistance, uint32_t* hashOfClosest, uint32_t* closestFPIdx) const {
void WorleyNoise3DGeneratorTemplate<RealType>::evaluate(const Point3DTemplate<RealType> &p, RealType* closestSqDistance, uint32_t* hashOfClosest, uint32_t* closestFPIdx) const {
using Point3DType = Point3DTemplate<RealType>;

int32_t iEvalCoord[3];
Expand All @@ -551,7 +562,7 @@ namespace SLR {
// It is necessary to evaluate 56 cells even if
// optimization is applied using information that which of 8 blocks the evaluation point belongs to in the cell where the evaluation point is in.
// However, it seems evaluating only 27 cells works well.
*closestDistance = INFINITY;
*closestSqDistance = INFINITY;
for (int iz = -1; iz <= 1; ++iz) {
for (int iy = -1; iy <= 1; ++iy) {
for (int ix = -1; ix <= 1; ++ix) {
Expand All @@ -564,9 +575,9 @@ namespace SLR {
Point3DType fp = Point3DType(iCoord[0] + rng.getFloat0cTo1o(),
iCoord[1] + rng.getFloat0cTo1o(),
iCoord[2] + rng.getFloat0cTo1o());
RealType dist = distance(p, fp);
if (dist < *closestDistance) {
*closestDistance = dist;
RealType dist2 = sqDistance(p, fp);
if (dist2 < *closestSqDistance) {
*closestSqDistance = dist2;
*hashOfClosest = hash;
*closestFPIdx = i;
}
Expand Down
24 changes: 23 additions & 1 deletion libSLR/Core/distributions.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,11 @@ namespace SLR {
// http://flafla2.github.io/2014/08/09/perlinnoise.html
template <typename RealType>
class ImprovedPerlinNoise3DGeneratorTemplate {
static const uint8_t PermutationTable[];

int32_t m_repeat;

static uint8_t hash(int32_t x, int32_t y, int32_t z);
static RealType gradient(uint32_t hash, RealType xu, RealType yu, RealType zu);

public:
Expand All @@ -217,6 +220,25 @@ namespace SLR {
RealType evaluate(const Point3DTemplate<RealType> &p) const;
};

// Reference:
// Long-Period Hash Functions for Procedural Texturing
// Permutation table of the hash function of period 739,024 = lcm(11, 13, 16, 17, 19)
template <typename RealType>
const uint8_t ImprovedPerlinNoise3DGeneratorTemplate<RealType>::PermutationTable[] = {
// table 0: 11 numbers
0, 10, 2, 7, 3, 5, 6, 4, 8, 1, 9,
// table 1: 13 numbers
5, 11, 6, 8, 1, 10, 12, 9, 3, 7, 0, 4, 2,
// table 2: 16 numbers = the range of the hash function required by Perlin noise.
13, 10, 11, 5, 6, 9, 4, 3, 8, 7, 14, 2, 0, 1, 15, 12,
// table 3: 17 numbers
1, 13, 5, 14, 12, 3, 6, 16, 0, 8, 9, 2, 11, 4, 15, 7, 10,
// table 4: 19 numbers
10, 6, 5, 8, 15, 0, 17, 7, 14, 18, 13, 16, 2, 9, 12, 1, 11, 4, 3,
// // table 6: 23 numbers
// 20, 21, 4, 5, 0, 18, 14, 2, 6, 22, 10, 17, 3, 7, 8, 16, 19, 11, 9, 13, 1, 15, 12
};



template <typename RealType>
Expand Down Expand Up @@ -295,7 +317,7 @@ namespace SLR {
public:
WorleyNoise3DGeneratorTemplate() { }

void evaluate(const Point3DTemplate<RealType> &p, RealType* closestDistance, uint32_t* hashOfClosest, uint32_t* closestFPIdx) const;
void evaluate(const Point3DTemplate<RealType> &p, RealType* closestSqDistance, uint32_t* hashOfClosest, uint32_t* closestFPIdx) const;
};


Expand Down
Loading

0 comments on commit 5b4beb9

Please sign in to comment.