我的 Perlin Noise 函数有太多黑点和小白条
My Perlin Noise function having too many dark spots, and little strips of white
我大致按照 java C# 教程创建了一个 Perlin 噪声函数。
然后我使用 Unity 对其进行可视化(我认为问题不在于 unity,因为它们的内置功能完美运行)
问题是大黑点太多了。 Here is a photo
This is how I would like it to look
如您所见,这些点似乎没有很好地融合。
这是我的噪音代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PerlinNoise
{
public PerlinNoise()
{
}
public double GetPixel(double x, double y)
{
int xint = (int)Math.Floor(x) & 255;
int yint = (int)Math.Floor(y) & 255; //gets what cube the input coords are
int g1 = p[p[xint] + yint];
int g2 = p[p[xint + 1] + yint];
int g3 = p[p[xint] + yint + 1];
int g4 = p[p[xint + 1] + yint + 1]; //gets the gradient vector's vaule on the permutation table
double xdec = x - Math.Floor(x);
double ydec = y - Math.Floor(y); //gets the pixel inside the cube
double d1 = grad(g1, xdec, ydec);
double d2 = grad(g2, xdec - 1, ydec);
double d3 = grad(g3, xdec, ydec - 1);
double d4 = grad(g4, xdec - 1, ydec - 1);
double u = fade(xdec);
double v = fade(ydec);
double x1Inter = lerp(u, d1, d2);
double x2Inter = lerp(u, d3, d4);
double yInter = lerp(v, x1Inter, x2Inter);
return yInter;
}
private static double lerp(double amount, double left, double right)
{
return ((1 - amount) * left + amount * right);
}
private static double fade(double t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
private static double grad(int hash, double x, double y)
{
switch (hash & 3)
{
case 0: return x + y;
case 1: return -x + y;
case 2: return x - y;
case 3: return -x - y;
default: return 0;
}
}
private static readonly int[] p = { 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
}
这里是统一贴图代码:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices.ComTypes;
// Create a texture and fill it with Perlin noise.
// Try varying the xOrg, yOrg and scale values in the inspector
// while in Play mode to see the effect they have on the noise.
public class TextureApply : MonoBehaviour
{
// Width and height of the texture in pixels.
public int pixWidth;
public int pixHeight;
// The origin of the sampled area in the plane.
public float xOrg;
public float yOrg;
// The number of cycles of the basic noise pattern that are repeated
// over the width and height of the texture.
public float scale = 1.0F;
private Texture2D noiseTex;
private Color[] pix;
private Renderer rend;
void Start()
{
rend = GetComponent<Renderer>();
// Set up the texture and a Color array to hold pixels during processing.
noiseTex = new Texture2D(pixWidth, pixHeight);
pix = new Color[noiseTex.width * noiseTex.height];
rend.material.mainTexture = noiseTex;
CalcNoise();
}
void CalcNoise()
{
// For each pixel in the texture...
float y = 0.0F;
while (y < noiseTex.height)
{
float x = 0.0F;
while (x < noiseTex.width)
{
double xCoord = xOrg + x / noiseTex.width * scale;
double yCoord = yOrg + y / noiseTex.height * scale;
PerlinNoise perlin = new PerlinNoise();
double sample = perlin.GetPixel(xCoord, yCoord);
pix[(int)y * noiseTex.width + (int)x] = new Color((float)sample, (float)sample, (float)sample);
x++;
}
y++;
}
// Copy the pixel data to the texture and load it into the GPU.
noiseTex.SetPixels(pix);
noiseTex.Apply();
}
void OnValidate()
{
CalcNoise();
}
}
以上只是 docs.unity3d.com
的修改代码
我认为问题可能出在排列 table 上,我只是复制并粘贴了它,而不是采用一些复杂的方式将值的数量加倍。
编辑:
[这是我将其更改为 Simplex Noise 时得到的图片][1]
[1]: https://i.stack.imgur.com/jfxNr.png
这是正在使用的渐变集。方向 (1, 1) 直接指向对角线邻居。如果那些对角线邻居有 (-1, -1),那么它们相长干涉。其他角对也是如此,当它们彼此指向负而不是正时。编辑:您可以尝试 +x + ROOT2*y, +ROOT2*x + y
及其所有符号排列,以产生 8 个渐变。
此外,即使你改进了梯度,你可能听说过 Perlin 是一种较老的噪声方法,它会产生很多 45 度和 90 度的偏差。我推荐它的情况并不多。如果您想将噪声作为一种编程练习来实现,那就太好了。但是如果你想在项目中使用噪声,我会编码或导入一个好的 2D 单纯形实现。
编辑:查看评论。我看错图了。您需要的解决方案只是 sample = sample * 0.5 + 0.5
重新缩放输出,这样图像中的负值就不会全部被截断。
此外,如果您想将噪声转换为基本的单纯形,您可以这样做:
- 定义常量
double F2 = 0.366025403784439
和 double G2 = -0.211324865405187
。这些将在下面使用,以处理三角形网格。
- 在GetPixel(double x, double y)的开头加上
double s = (x + y) * F2;
x += s; y += s;
。这会将在正方形网格上产生整数的坐标转换为在代表等边三角形的 diagonally-compressed 正方形网格上产生整数的坐标。
- 定义
xdec
和 ydec
后,添加 double t = (xdec + ydec) * G2;
xdec += t; ydec += t;
。这将使这些坐标相对于压缩正方形的底部不倾斜,因此它们现在可以再次用于距离和梯度。
- 定义双打
xdec2 = xdec - 1 - G2;
ydec2 = ydec - G2;
。定义 xdec3 = xdec - G2;
ydec3 = ydec - 1 - G2;
。定义 xdec4 = xdec - 1 - 2*G2;
ydec4 = ydec - 1 - 2*G2;
。你需要这个,因为简单地减去 1 不再适用于获得其他四个角的相对坐标,因为角不再与正方形对齐。现在,任何时候你从坐标的 either 中减去 1,你还需要从 both 中减去 G2。因此,对于 #2 和 #3,你从每个减去 G2 一次,对于 #4,你减去它两次 (2*G2)。您可以自己 re-derive 通过查看如果您已经从一个或两个坐标中减去 1 会发生什么,然后再计算您定义 double t
. 的上一步
- 更改 d2、d3、d4 以使用这些值,例如
d2 = grad(g2, xdec2, ydec2);
- 删除所有以
double u
开头并以 return yInter;
结尾的内容。添加double value = 0;
。您将向该值添加内容。
- 定义
double a1 = 0.5 - xdec*xdec - ydec*ydec;
double a2 = 0.5 - xdec2*xdec2 - ydec2*ydec2;
以及 a3 和 a4 的相同模式。这些函数表示围绕每个三角形顶点的圆圈,圆圈停在三角形边缘。
- 添加
if (a1 > 0) value += (a1 * a1) * (a1 * a1) * d1;
和 a2、a3、a4 相同。这些根据梯度和距离为每个圆圈内的噪声添加一个值。
- 如果您使用我为 Perlin 建议的改进渐变,请添加
return value * 38.283687591552734375;
。如果您使用原始值,我认为乘以的正确值是 75.3929901123046875
但我不确定。不过,这将接近于此。真的,你可能想要更多的单纯形渐变,但 8 应该至少让它看起来比 Perlin 更好。
如果没有改进的梯度,噪点看起来不会很好。您仍然会看到很多 45 度偏差。如果你真的想改善噪点,这是我的建议,使用 24 个渐变。你可以找到这些梯度 here。使用 99.83685446303647
作为最后乘以的值。
private static double grad(int hash, double x, double y)
{
switch (hash % 24)
{
case 0: return 0.130526192220052 * x + 0.99144486137381 * y;
case 1: return 0.38268343236509 * x + 0.923879532511287 * y;
case 2: return 0.608761429008721 * x + 0.793353340291235 * y;
case 3: return 0.793353340291235 * x + 0.608761429008721 * y;
case 4: return 0.923879532511287 * x + 0.38268343236509 * y;
case 5: return 0.99144486137381 * x + 0.130526192220051 * y;
case 6: return 0.99144486137381 * x + -0.130526192220051 * y;
case 7: return 0.923879532511287 * x + -0.38268343236509 * y;
case 8: return 0.793353340291235 * x + -0.60876142900872 * y;
case 9: return 0.608761429008721 * x + -0.793353340291235 * y;
case 10: return 0.38268343236509 * x + -0.923879532511287 * y;
case 11: return 0.130526192220052 * x + -0.99144486137381 * y;
case 12: return -0.130526192220052 * x + -0.99144486137381 * y;
case 13: return -0.38268343236509 * x + -0.923879532511287 * y;
case 14: return -0.608761429008721 * x + -0.793353340291235 * y;
case 15: return -0.793353340291235 * x + -0.608761429008721 * y;
case 16: return -0.923879532511287 * x + -0.38268343236509 * y;
case 17: return -0.99144486137381 * x + -0.130526192220052 * y;
case 18: return -0.99144486137381 * x + 0.130526192220051 * y;
case 19: return -0.923879532511287 * x + 0.38268343236509 * y;
case 20: return -0.793353340291235 * x + 0.608761429008721 * y;
case 21: return -0.608761429008721 * x + 0.793353340291235 * y;
case 22: return -0.38268343236509 * x + 0.923879532511287 * y;
case 23: return -0.130526192220052 * x + 0.99144486137381 * y;
default: return 0;
}
}
可选优化:您一次只需要a2/g2/xdec2/ydec2、a3/g3/xdec3/ydec3之一。如果 ydec > xdec 那么你可以做 a3/g3/xdec3/ydec3,否则 a2/g2/xdec2/ydec2。几乎所有的教程和实现都会有这个,但你不需要它来让噪音起作用。
可选优化 #2:在第 8 步中,您可以拉入 d1 的定义,并在其中拉入 g1 的定义。这样,只有在该条件中需要定义时才会计算定义(如果编译器尚未捕获)。 if (a1 > 0) value += (a1 * a1) * (a1 * a1) * grad(p[p[xint] + yint], xdec, ydec);
然后您可以将它们从最初计算的位置移除。
注意:一些教程或实现会使用正的G2,并翻转它的additions/subtractions。我发现保持负值最有意义,因为这样 unskew 变换的工作方式与 skew 变换完全一样。但值得牢记。
我大致按照 java C# 教程创建了一个 Perlin 噪声函数。 然后我使用 Unity 对其进行可视化(我认为问题不在于 unity,因为它们的内置功能完美运行)
问题是大黑点太多了。 Here is a photo
This is how I would like it to look
如您所见,这些点似乎没有很好地融合。
这是我的噪音代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PerlinNoise
{
public PerlinNoise()
{
}
public double GetPixel(double x, double y)
{
int xint = (int)Math.Floor(x) & 255;
int yint = (int)Math.Floor(y) & 255; //gets what cube the input coords are
int g1 = p[p[xint] + yint];
int g2 = p[p[xint + 1] + yint];
int g3 = p[p[xint] + yint + 1];
int g4 = p[p[xint + 1] + yint + 1]; //gets the gradient vector's vaule on the permutation table
double xdec = x - Math.Floor(x);
double ydec = y - Math.Floor(y); //gets the pixel inside the cube
double d1 = grad(g1, xdec, ydec);
double d2 = grad(g2, xdec - 1, ydec);
double d3 = grad(g3, xdec, ydec - 1);
double d4 = grad(g4, xdec - 1, ydec - 1);
double u = fade(xdec);
double v = fade(ydec);
double x1Inter = lerp(u, d1, d2);
double x2Inter = lerp(u, d3, d4);
double yInter = lerp(v, x1Inter, x2Inter);
return yInter;
}
private static double lerp(double amount, double left, double right)
{
return ((1 - amount) * left + amount * right);
}
private static double fade(double t)
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
private static double grad(int hash, double x, double y)
{
switch (hash & 3)
{
case 0: return x + y;
case 1: return -x + y;
case 2: return x - y;
case 3: return -x - y;
default: return 0;
}
}
private static readonly int[] p = { 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
}
这里是统一贴图代码:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices.ComTypes;
// Create a texture and fill it with Perlin noise.
// Try varying the xOrg, yOrg and scale values in the inspector
// while in Play mode to see the effect they have on the noise.
public class TextureApply : MonoBehaviour
{
// Width and height of the texture in pixels.
public int pixWidth;
public int pixHeight;
// The origin of the sampled area in the plane.
public float xOrg;
public float yOrg;
// The number of cycles of the basic noise pattern that are repeated
// over the width and height of the texture.
public float scale = 1.0F;
private Texture2D noiseTex;
private Color[] pix;
private Renderer rend;
void Start()
{
rend = GetComponent<Renderer>();
// Set up the texture and a Color array to hold pixels during processing.
noiseTex = new Texture2D(pixWidth, pixHeight);
pix = new Color[noiseTex.width * noiseTex.height];
rend.material.mainTexture = noiseTex;
CalcNoise();
}
void CalcNoise()
{
// For each pixel in the texture...
float y = 0.0F;
while (y < noiseTex.height)
{
float x = 0.0F;
while (x < noiseTex.width)
{
double xCoord = xOrg + x / noiseTex.width * scale;
double yCoord = yOrg + y / noiseTex.height * scale;
PerlinNoise perlin = new PerlinNoise();
double sample = perlin.GetPixel(xCoord, yCoord);
pix[(int)y * noiseTex.width + (int)x] = new Color((float)sample, (float)sample, (float)sample);
x++;
}
y++;
}
// Copy the pixel data to the texture and load it into the GPU.
noiseTex.SetPixels(pix);
noiseTex.Apply();
}
void OnValidate()
{
CalcNoise();
}
}
以上只是 docs.unity3d.com
的修改代码我认为问题可能出在排列 table 上,我只是复制并粘贴了它,而不是采用一些复杂的方式将值的数量加倍。
编辑: [这是我将其更改为 Simplex Noise 时得到的图片][1] [1]: https://i.stack.imgur.com/jfxNr.png
这是正在使用的渐变集。方向 (1, 1) 直接指向对角线邻居。如果那些对角线邻居有 (-1, -1),那么它们相长干涉。其他角对也是如此,当它们彼此指向负而不是正时。编辑:您可以尝试 +x + ROOT2*y, +ROOT2*x + y
及其所有符号排列,以产生 8 个渐变。
此外,即使你改进了梯度,你可能听说过 Perlin 是一种较老的噪声方法,它会产生很多 45 度和 90 度的偏差。我推荐它的情况并不多。如果您想将噪声作为一种编程练习来实现,那就太好了。但是如果你想在项目中使用噪声,我会编码或导入一个好的 2D 单纯形实现。
编辑:查看评论。我看错图了。您需要的解决方案只是 sample = sample * 0.5 + 0.5
重新缩放输出,这样图像中的负值就不会全部被截断。
此外,如果您想将噪声转换为基本的单纯形,您可以这样做:
- 定义常量
double F2 = 0.366025403784439
和double G2 = -0.211324865405187
。这些将在下面使用,以处理三角形网格。 - 在GetPixel(double x, double y)的开头加上
double s = (x + y) * F2;
x += s; y += s;
。这会将在正方形网格上产生整数的坐标转换为在代表等边三角形的 diagonally-compressed 正方形网格上产生整数的坐标。 - 定义
xdec
和ydec
后,添加double t = (xdec + ydec) * G2;
xdec += t; ydec += t;
。这将使这些坐标相对于压缩正方形的底部不倾斜,因此它们现在可以再次用于距离和梯度。 - 定义双打
xdec2 = xdec - 1 - G2;
ydec2 = ydec - G2;
。定义xdec3 = xdec - G2;
ydec3 = ydec - 1 - G2;
。定义xdec4 = xdec - 1 - 2*G2;
ydec4 = ydec - 1 - 2*G2;
。你需要这个,因为简单地减去 1 不再适用于获得其他四个角的相对坐标,因为角不再与正方形对齐。现在,任何时候你从坐标的 either 中减去 1,你还需要从 both 中减去 G2。因此,对于 #2 和 #3,你从每个减去 G2 一次,对于 #4,你减去它两次 (2*G2)。您可以自己 re-derive 通过查看如果您已经从一个或两个坐标中减去 1 会发生什么,然后再计算您定义double t
. 的上一步
- 更改 d2、d3、d4 以使用这些值,例如
d2 = grad(g2, xdec2, ydec2);
- 删除所有以
double u
开头并以return yInter;
结尾的内容。添加double value = 0;
。您将向该值添加内容。 - 定义
double a1 = 0.5 - xdec*xdec - ydec*ydec;
double a2 = 0.5 - xdec2*xdec2 - ydec2*ydec2;
以及 a3 和 a4 的相同模式。这些函数表示围绕每个三角形顶点的圆圈,圆圈停在三角形边缘。 - 添加
if (a1 > 0) value += (a1 * a1) * (a1 * a1) * d1;
和 a2、a3、a4 相同。这些根据梯度和距离为每个圆圈内的噪声添加一个值。 - 如果您使用我为 Perlin 建议的改进渐变,请添加
return value * 38.283687591552734375;
。如果您使用原始值,我认为乘以的正确值是75.3929901123046875
但我不确定。不过,这将接近于此。真的,你可能想要更多的单纯形渐变,但 8 应该至少让它看起来比 Perlin 更好。
如果没有改进的梯度,噪点看起来不会很好。您仍然会看到很多 45 度偏差。如果你真的想改善噪点,这是我的建议,使用 24 个渐变。你可以找到这些梯度 here。使用 99.83685446303647
作为最后乘以的值。
private static double grad(int hash, double x, double y)
{
switch (hash % 24)
{
case 0: return 0.130526192220052 * x + 0.99144486137381 * y;
case 1: return 0.38268343236509 * x + 0.923879532511287 * y;
case 2: return 0.608761429008721 * x + 0.793353340291235 * y;
case 3: return 0.793353340291235 * x + 0.608761429008721 * y;
case 4: return 0.923879532511287 * x + 0.38268343236509 * y;
case 5: return 0.99144486137381 * x + 0.130526192220051 * y;
case 6: return 0.99144486137381 * x + -0.130526192220051 * y;
case 7: return 0.923879532511287 * x + -0.38268343236509 * y;
case 8: return 0.793353340291235 * x + -0.60876142900872 * y;
case 9: return 0.608761429008721 * x + -0.793353340291235 * y;
case 10: return 0.38268343236509 * x + -0.923879532511287 * y;
case 11: return 0.130526192220052 * x + -0.99144486137381 * y;
case 12: return -0.130526192220052 * x + -0.99144486137381 * y;
case 13: return -0.38268343236509 * x + -0.923879532511287 * y;
case 14: return -0.608761429008721 * x + -0.793353340291235 * y;
case 15: return -0.793353340291235 * x + -0.608761429008721 * y;
case 16: return -0.923879532511287 * x + -0.38268343236509 * y;
case 17: return -0.99144486137381 * x + -0.130526192220052 * y;
case 18: return -0.99144486137381 * x + 0.130526192220051 * y;
case 19: return -0.923879532511287 * x + 0.38268343236509 * y;
case 20: return -0.793353340291235 * x + 0.608761429008721 * y;
case 21: return -0.608761429008721 * x + 0.793353340291235 * y;
case 22: return -0.38268343236509 * x + 0.923879532511287 * y;
case 23: return -0.130526192220052 * x + 0.99144486137381 * y;
default: return 0;
}
}
可选优化:您一次只需要a2/g2/xdec2/ydec2、a3/g3/xdec3/ydec3之一。如果 ydec > xdec 那么你可以做 a3/g3/xdec3/ydec3,否则 a2/g2/xdec2/ydec2。几乎所有的教程和实现都会有这个,但你不需要它来让噪音起作用。
可选优化 #2:在第 8 步中,您可以拉入 d1 的定义,并在其中拉入 g1 的定义。这样,只有在该条件中需要定义时才会计算定义(如果编译器尚未捕获)。 if (a1 > 0) value += (a1 * a1) * (a1 * a1) * grad(p[p[xint] + yint], xdec, ydec);
然后您可以将它们从最初计算的位置移除。
注意:一些教程或实现会使用正的G2,并翻转它的additions/subtractions。我发现保持负值最有意义,因为这样 unskew 变换的工作方式与 skew 变换完全一样。但值得牢记。