在 GLSL 中读取噪声纹理时出现问题

问题描述 投票:0回答:1

我正在使用 p5js 编写一个 Perlin 噪声地形生成器,遵循 本教程。该应用程序运行不佳,因此我决定使用着色器重写它,这是我以前从未使用过的东西。我首先生成一个不同分辨率的细分平面来使用(我毫不怀疑有更简单的方法来做到这一点):

const SCALE = 50;
function setup() {
    createCanvas(window.innerWidth, window.innerHeight, WEBGL);

    TERRAIN_W = width + floor(width / SCALE) * SCALE;
    TERRAIN_H = height + floor(height / SCALE) * SCALE;
    NUM_COLS = floor(TERRAIN_W / SCALE);
    NUM_ROWS = floor(TERRAIN_H / SCALE);

    plane_model = new p5.Geometry(NUM_COLS, NUM_ROWS, create_plane);
}

function create_plane() {
    let vert_map = []

    for (let y = 0; y < this.detailY; y++) {
        vert_map[y] = []
        for (let x = 0; x < this.detailX; x++) {
            this.vertices.push(createVector(x * SCALE, y * SCALE, 0));
            vert_map[y][x] = this.vertices.length - 1;

            this.uvs.push(x / (this.detailX - 1), y / (this.detailY - 1));
        }
    }

    for (let y = 0; y < this.detailY - 1; y++) {
        for (let x = 0; x < this.detailX - 1; x++) {
            let tl = vert_map[y][x];
            let tr = vert_map[y][x + 1];
            let bl = vert_map[y + 1][x];
            let br = vert_map[y + 1][x + 1];

            this.faces.push([tl, tr, bl]);
            this.faces.push([tr, br, bl]);
        }
    }
  
    this.computeNormals();
}

然后我创建了一个带有噪声的图像以传递给顶点着色器:


const NOISE_OFFSET = 0.05;
var fly_offset = 0;
function setup() {
    terrain_texture = createImage(NUM_ROWS, NUM_COLS);
}

function draw() {
    fly_offset += SHIFT_SPEED;
    let yoff = fly_offset;

    terrain_texture.loadPixels();
    for (let y = 0; y < NUM_ROWS; y++) {
        let xoff = 0;
        for (let x = 0; x < NUM_COLS; x++) {
            terrain_texture.set(x, y, color(map(noise(xoff, yoff), 0, 1, 0, 255)));
            xoff += NOISE_OFFSET;
        }
        yoff += NOISE_OFFSET;
    }
    terrain_texture.updatePixels();
    default_shader.setUniform("uTerrain", terrain_texture);
}

我使用简单的片段着色器创建顶点着色器,该片段着色器使用纹理坐标进行颜色:

#ifdef GL_ES
precision mediump float;
#endif

attribute vec3 aPosition;
attribute vec2 aTexCoord;

uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

varying vec2 vTexCoord;

uniform sampler2D uTerrain;
uniform int uNumCols;
uniform int uNumRows;
uniform float uScale;

void main() {
    vec3 position = aPosition;

    vec2 uv = vec2(aPosition.x / float(uNumCols - 1), aPosition.y / float(uNumRows - 1));

    float height = texture2D(uTerrain, uv).r * 255.0;
    position.z += height;

    vec4 viewModelPosition = uModelViewMatrix * vec4(position, 1.0);

    gl_Position = uProjectionMatrix * viewModelPosition;
    vTexCoord = aTexCoord;
}

最后加载着色器,添加制服并用它来绘制我的飞机:

function preload() {
    default_shader = loadShader("src/shader.vert", "src/shader.frag");
}

function setup() {
    default_shader.setUniform("uScale", SCALE);
    default_shader.setUniform("uNumCols", NUM_COLS);
    default_shader.setUniform("uNumRows", NUM_ROWS);
}

function draw() {
    default_shader.setUniform("uTerrain", terrain_texture);
    shader(default_shader);
    model(plane_model);
}

最终结果是一个随机上下移动的平面。

1

我最好的猜测是我弄乱了

terrain_texture
的分辨率或我在顶点着色器中读取 UV 的方式。 我已经搞乱了很多次,但无法找到解决方案。

javascript glsl shader webgl p5.js
1个回答
0
投票

所以,有两个问题。第一,我不知道你必须在每次抽奖时设置制服,第二,使用

float height = texture2D(uTerrain, aTexCoord.xy).r * (255.0 + uNoiseFactor);

是从噪声纹理中采样的正确方法。

© www.soinside.com 2019 - 2024. All rights reserved.