You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C#实现的Perlin Noise函数存在大量暗斑问题求助

Fixing Your Perlin Noise Dark Blotches in Unity

Hey there! Let’s break down what’s causing those chunky dark spots and fix your implementation step by step—you were right to suspect the permutation table, but there’s another critical issue hiding in how you’re handling the noise output.

The Core Problem: Unnormalized Noise Values

Perlin Noise’s raw output ranges roughly from -0.707 to 0.707 (since the maximum dot product of a 2D gradient vector and a unit vector is √2/2 ≈ 0.707). When you feed this directly into a Color (which expects values between 0 and 1), all negative values get clamped to 0—creating those big, ugly dark blotches. That’s the biggest culprit here.

Secondary Issue: Permutation Table Redundancy

Your current p array is manually duplicated twice, which works in theory but is error-prone and hard to maintain. The standard approach is to define a base 256-element permutation array, then dynamically concatenate it with itself to create the 512-element lookup table.

Fixed Code Implementations

Updated PerlinNoise Class

using System;
using System.Linq;
using UnityEngine;

public class PerlinNoise {
    // Base 256-element permutation table (matches your original values, no manual duplication)
    private static readonly int[] _permutation = { 
        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
    };

    // Dynamically create 512-element lookup table (avoids manual copy-paste errors)
    private static readonly int[] _p = _permutation.Concat(_permutation).ToArray();

    public PerlinNoise() { }

    public double GetPixel(double x, double y) {
        int xint = (int)Math.Floor(x) & 255;
        int yint = (int)Math.Floor(y) & 255;

        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];

        double xdec = x - Math.Floor(x);
        double ydec = y - Math.Floor(y);

        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);
        return Lerp(v, x1Inter, x2Inter);
    }

    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;
        }
    }
}

Updated TextureApply Class

using UnityEngine;

public class TextureApply : MonoBehaviour {
    public int pixWidth = 256;
    public int pixHeight = 256;
    public float xOrg;
    public float yOrg;
    public float scale = 1.0F;

    private Texture2D _noiseTex;
    private Color[] _pix;
    private Renderer _rend;
    private PerlinNoise _perlin; // Reuse a single instance instead of creating new ones

    void Start() {
        _rend = GetComponent<Renderer>();
        _perlin = new PerlinNoise(); // Initialize once for performance
        _noiseTex = new Texture2D(pixWidth, pixHeight);
        _pix = new Color[_noiseTex.width * _noiseTex.height];
        _rend.material.mainTexture = _noiseTex;
        CalcNoise();
    }

    void CalcNoise() {
        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;
                
                double sample = _perlin.GetPixel(xCoord, yCoord);
                // Normalize raw noise to 0-1 range for Color compatibility
                float normalizedSample = (float)((sample + 0.7071) / 1.4142);
                // Clamp to ensure no values exceed 0-1
                normalizedSample = Mathf.Clamp01(normalizedSample);
                
                _pix[(int)y * _noiseTex.width + (int)x] = new Color(normalizedSample, normalizedSample, normalizedSample);
                x++;
            }
            y++;
        }

        _noiseTex.SetPixels(_pix);
        _noiseTex.Apply();
    }

    void OnValidate() {
        if (_noiseTex != null && _perlin != null) {
            CalcNoise();
        }
    }
}

Key Changes Explained

  1. Normalization: We map the raw noise output (-0.707 to 0.707) to the 0-1 range required by Color, eliminating the clamped-to-black values that caused dark blotches.
  2. Permutation Table Cleanup: Dynamic concatenation removes manual copy-paste risk and makes the code easier to update.
  3. Performance Boost: Reusing a single PerlinNoise instance instead of creating a new one every pixel saves unnecessary memory allocations.

Give these changes a try—your noise should now have smooth transitions without those large dark areas!

内容的提问来源于stack exchange,提问作者Joseph Yianni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:03:13