我正在使用 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);
}
最终结果是一个随机上下移动的平面。
我最好的猜测是我弄乱了
terrain_texture
的分辨率或我在顶点着色器中读取 UV 的方式。
我已经搞乱了很多次,但无法找到解决方案。
所以,有两个问题。第一,我不知道你必须在每次抽奖时设置制服,第二,使用
float height = texture2D(uTerrain, aTexCoord.xy).r * (255.0 + uNoiseFactor);
是从噪声纹理中采样的正确方法。