Files
SingularityViewer/indra/llmath/llperlin.h

176 lines
5.4 KiB
C++

/**
* @file llperlin.h
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_PERLIN_H
#define LL_PERLIN_H
#include "stdtypes.h"
#include "llmath.h"
#include "v2math.h"
#include "v3math.h"
// namespace wrapper
class LLPerlinNoise
{
public:
static F32 noise(const F32& x, U32 wrap_at = 256)
{
U8 b[1][2];
F32 r[1][2], s[1], u, v;
fast_setup(&x, b, r, s, wrap_at);
u = grad(p[b[VX][0]], r[VX][0]);
v = grad(p[b[VX][1]], r[VX][1]);
return lerp(u, v, s[VX]);
}
static F32 noise(const LLVector2& vec, U32 wrap_at = 256)
{
U8 b[2][2];
F32 r[2][2], s[2], u, v, A, B;
fast_setup(vec.mV, b, r, s, wrap_at);
u = grad(p[p[b[VX][0]] + b[VY][0]], r[VX][0], r[VY][0]);
v = grad(p[p[b[VX][1]] + b[VY][0]], r[VX][1], r[VY][0]);
A = lerp(u, v, s[VX]);
u = grad(p[p[b[VX][0]] + b[VY][1]], r[VX][0], r[VY][1]);
v = grad(p[p[b[VX][1]] + b[VY][1]], r[VX][1], r[VY][1]);
B = lerp(u, v, s[VX]);
return lerp(A, B, s[VY]);
}
static F32 noise(const LLVector3& vec, U32 wrap_at = 256)
{
U8 b[3][2];
F32 r[3][2], s[3], u, v, A, B, C, D;
fast_setup(vec.mV, b, r, s, wrap_at);
u = grad(p[p[p[b[VX][0]] + b[VY][0]] + b[VZ][0]], r[VX][0], r[VY][0], r[VZ][0]);
v = grad(p[p[p[b[VX][1]] + b[VY][0]] + b[VZ][0]], r[VX][1], r[VY][0], r[VZ][0]);
A = lerp(u, v, s[VX]);
u = grad(p[p[p[b[VX][0]] + b[VY][1]] + b[VZ][0]], r[VX][0], r[VY][1], r[VZ][0]);
v = grad(p[p[p[b[VX][1]] + b[VY][1]] + b[VZ][0]], r[VX][1], r[VY][1], r[VZ][0]);
B = lerp(u, v, s[VX]);
C = lerp(A, B, s[VY]);
u = grad(p[p[p[b[VX][0]] + b[VY][0]] + b[VZ][1]], r[VX][0], r[VY][0], r[VZ][1]);
v = grad(p[p[p[b[VX][1]] + b[VY][0]] + b[VZ][1]], r[VX][1], r[VY][0], r[VZ][1]);
A = lerp(u, v, s[VX]);
u = grad(p[p[p[b[VX][0]] + b[VY][1]] + b[VZ][1]], r[VX][0], r[VY][1], r[VZ][1]);
v = grad(p[p[p[b[VX][1]] + b[VY][1]] + b[VZ][1]], r[VX][1], r[VY][1], r[VZ][1]);
B = lerp(u, v, s[VX]);
D = lerp(A, B, s[VY]);
return lerp(C, D, s[VZ]) * 0.77f;
}
template <typename T>
static F32 turbulence(const T& vec, F32 freq, U32 wrap_at = 256)
{
F32 t;
for (t = 0.f; freq >= 1.f; freq *= 0.5f)
{
t += noise(vec * freq, wrap_at) / freq;
// t += fabs(noise(vec * freq)) / freq; // Like snow - bubbly at low frequencies
// t += sqrt(fabs(noise(vec * freq))) / freq; // Better at low freq
// t += (noise(vec * freq)*noise(vec * freq)) / freq;
}
return t;
}
template <typename T>
static F32 clouds(const T& vec, F32 freq, U32 wrap_at = 256)
{
F32 t;
for (t = 0.f; freq >= 1.f; freq *= 0.5f)
{
// t += noise(vec * freq)/freq;
// t += fabs(noise(vec * freq)) / freq; // Like snow - bubbly at low frequencies
// t += sqrt(fabs(noise(vec * freq))) / freq; // Better at low freq
t += (noise(vec * freq, wrap_at)*noise(vec * freq, wrap_at)) / freq;
}
return t;
}
private:
static F32 s_curve(const F32 t)
{
return t * t * t * (t * (6.f * t - 15.f) + 10.f); //5th degree
//return t * t * (3.f - 2.f * t); //3rd degree
}
static F32 grad(U32 hash, F32 x)
{
return x * (2.f*F32(hash) / 255.f - 1.f);
}
static F32 grad(U32 hash, F32 x, F32 y)
{
//Rotated slightly off the axes. Reduces directional artifacts.
//Scaled to match the old perlin method's output range
static const F32 l[2] = { .466666667f, .933333332f };
static const LLVector2 vecs[] = {
LLVector2(l[0], l[1]), LLVector2(l[0], -l[1]), LLVector2(-l[0], l[1]), LLVector2(-l[0], -l[1]),
LLVector2(l[1], l[0]), LLVector2(l[1], -l[0]), LLVector2(-l[1], l[0]), LLVector2(-l[1], -l[0]) };
return vecs[hash % LL_ARRAY_SIZE(vecs)] * LLVector2(x, y);
}
static F32 grad(U32 hash, F32 x, F32 y, F32 z)
{
static const LLVector3 vecs[] = {
OO_SQRT3*LLVector3(1, 1, 0), OO_SQRT3*LLVector3(-1, 1, 0), OO_SQRT3*LLVector3(1, -1, 0), OO_SQRT3*LLVector3(-1, -1, 0),
OO_SQRT3*LLVector3(1, 0, 1), OO_SQRT3*LLVector3(-1, 0, 1), OO_SQRT3*LLVector3(1, 0, -1), OO_SQRT3*LLVector3(-1, 0, -1),
OO_SQRT3*LLVector3(0, 1, 1), OO_SQRT3*LLVector3(0, -1, 1), OO_SQRT3*LLVector3(0, 1, -1), OO_SQRT3*LLVector3(0, -1, -1) };
return vecs[hash % LL_ARRAY_SIZE(vecs)] * LLVector3(x, y, z);
}
template <int N>
static void fast_setup(const F32* vec, U8 (&b)[N][2], F32 (&r)[N][2], F32 (&s)[N], const U32& wrap_at)
{
const U32 limit = llclamp(wrap_at, U32(1), U32(256));
for (U32 i = 0; i < N; ++i)
{
const S32 t_S32 = llfloor(vec[i]);
b[i][0] = (t_S32) % limit;
b[i][1] = (t_S32 + 1) % limit;
r[i][0] = vec[i] - F32(t_S32);
r[i][1] = r[i][0] - 1.f;
s[i] = s_curve(r[i][0]);
}
}
static const U32 sPremutationCount = 512;
static const U8 p[sPremutationCount];
};
#endif // LL_PERLIN_