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

使用Raylib渲染Perlin噪声失败,仅显示黑屏求助

C++ Raylib渲染Perlin噪声黑屏问题解决

核心问题:透明度值溢出导致像素不可见

Raylib的Color结构体中,alpha通道是8位无符号整数,取值范围为0-255。你代码中写的(char)256会因为char的溢出特性(8位最大值为255)被截断为0,导致所有像素完全透明,所以窗口显示黑屏。

将alpha值改为255即可解决这个基础问题:

Color col{c, c, c, 255};

额外优化与潜在问题修复

除了透明度问题,你的Perlin噪声实现还有两个潜在问题,可能导致噪声效果异常:

  1. 数组索引越界风险
    p数组长度为256,当xInd或yInd为255时,xInd +1或yInd +1会变成256,超出数组范围引发未定义行为。需要对索引取模256:
// 修正梯度向量的索引计算,避免越界
int hash00 = p[(p[xi] + yi) & 255];
int hash10 = p[(p[xi + 1 & 255] + yi) & 255];
int hash01 = p[(p[xi] + yi + 1 & 255) & 255];
int hash11 = p[(p[xi + 1 & 255] + yi + 1 & 255) & 255];
  1. Perlin噪声插值顺序错误
    原代码的双线性插值顺序不符合标准实现,会导致噪声纹理扭曲。正确的逻辑是先对x方向插值,再对y方向插值:
// 修正双线性插值顺序
float x1 = lerp(dot00, dot10, u);  // 底部两个点的x方向插值
float x2 = lerp(dot01, dot11, u);  // 顶部两个点的x方向插值
return lerp(x1, x2, v);          // 上下结果的y方向插值

修正后的完整代码

#include <math.h>
#include <iostream>
#include <vector>

#include "raylib.h"

using namespace std;

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

float fade(float t) { return t * t * t * (6 * t * t - 15 * t + 10); }

float lerp(float a0, float a1, float t) { return a0 + t * (a1 - a0); }

float dotp(Vector2 a, Vector2 b) { return a.x * b.x + a.y * b.y; }

Vector2 grad(int a) {
  int l = a % 4;
  Vector2 v;

  if (l == 0) {
    v = {1.0, 1.0};
  } else if (l == 1) {
    v = {-1.0, 1.0};
  } else if (l == 2) {
    v = {-1.0, -1.0};
  } else {
    v = {1.0, -1.0};
  }

  return v;
}

float perlinNoise(float x, float y) {
  int xi = (int)floor(x) & 255;
  int yi = (int)floor(y) & 255;

  float xf = x - floor(x);
  float yf = y - floor(y);

  // 方向向量:从四个网格点到(x,y)的偏移
  Vector2 d00 = {xf, yf};
  Vector2 d10 = {xf - 1.0f, yf};
  Vector2 d01 = {xf, yf - 1.0f};
  Vector2 d11 = {xf - 1.0f, yf - 1.0f};

  // 网格点的哈希值,避免越界
  int hash00 = p[(p[xi] + yi) & 255];
  int hash10 = p[(p[xi + 1 & 255] + yi) & 255];
  int hash01 = p[(p[xi] + yi + 1 & 255) & 255];
  int hash11 = p[(p[xi + 1 & 255] + yi + 1 & 255) & 255];

  // 点积计算
  float dot00 = dotp(grad(hash00), d00);
  float dot10 = dotp(grad(hash10), d10);
  float dot01 = dotp(grad(hash01), d01);
  float dot11 = dotp(grad(hash11), d11);

  // fade曲线
  float u = fade(xf);
  float v = fade(yf);

  // 双线性插值
  float x1 = lerp(dot00, dot10, u);
  float x2 = lerp(dot01, dot11, u);
  return lerp(x1, x2, v);
}

int main(void) {
  const int screenWidth = 512;
  const int screenHeight = 512;

  cout << perlinNoise(1.5, 1.5) << '\n';

  InitWindow(screenWidth, screenHeight, "perlins go brrrrrrrrrrrrr");

  SetTargetFPS(60);

  while (!WindowShouldClose()) {
    BeginDrawing();

    ClearBackground(BLACK);

    for (int y = 0; y < screenHeight; y++) {
      for (int x = 0; x < screenWidth; x++) {
        float n = perlinNoise(x * 0.01f, y * 0.01f);
        // 将噪声值归一化到0-1
        n = (n + 1.0f) / 2.0f;
        int c = (int)round(n * 255.0f);
        Color col{c, c, c, 255};
        DrawPixel(x, y, col);
      }
    }

    EndDrawing();
  }

  CloseWindow();

  return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:10:34