SIMD noise (not used yet)

This commit is contained in:
2025-11-30 14:25:42 +01:00
parent 0fbc7f32f2
commit c33f700177
3 changed files with 176 additions and 23 deletions

View File

@@ -616,6 +616,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
const block_grass = blocks.getFilename("Grass.json").?;
const block_dirt = blocks.getFilename("Dirt.json").?;
const block_stone = blocks.getFilename("Stone.json").?;
const block_bedrock = blocks.getFilename("Bedrock.json").?;
while (it.next()) |chunk_coords| {
@@ -636,26 +637,30 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
var it2 = Interator3(usize).init(0, 0, 0, 15, 15, 0);
while (it2.next()) |pos| {
const x, const y, _ = pos;
const fpos = Vector3.init(
const fpos = Vector2.init(
@floatFromInt(pos[0]),
@floatFromInt(pos[1]),
@floatFromInt(pos[2]),
).add(origin);
).add(origin.asVector2());
const noise = std.math.clamp(math.noise2(fpos.asVector2().divScalar(30)), -1, 1);
const fheight = (0.5 * noise + 0.5) * 4 + 1;
const iheight: u32 = @intFromFloat(@round(fheight));
const iheight = worldHeightI(fpos);
chunk.blocks[0][y][x] = block_bedrock;
var i: u32 = 0;
var i: i32 = 0;
while (i < iheight) : (i += 1) {
const iz = i + 1;
const block = if (i + 1 == iheight) block_grass else block_dirt;
chunk.blocks[iz][y][x] = block;
const block = if (i + 1 == iheight)
block_grass
else if (i + 4 >= iheight)
block_dirt
else
block_stone;
chunk.blocks[@intCast(iz)][y][x] = block;
}
}
}
const camera_position = Vector3.init(0, 0, @as(f32, @floatFromInt(worldHeightI(.zero))) + 0.5 + 1.62);
var chunk_it = chunks.iterator();
while (chunk_it.next()) |entry| {
const x, const y, const z = entry.key_ptr.*;
@@ -713,6 +718,8 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
.materials = materials,
.textures = textures,
.chunks = chunks,
.camera_position = camera_position,
};
}
@@ -989,3 +996,19 @@ fn recreateSwapchain(self: *Game) !void {
self.engine.setObjectName(semaphore.*, "S Transfer[{d}]", .{i});
}
}
fn worldHeightF(pos: Vector2) f32 {
const noise_hscale = 80;
const noise_zcenter = 8;
const noise_zscale = 5;
const noise = math.noise2(pos.divScalar(noise_hscale));
const height = noise_zscale * noise + noise_zcenter;
return height;
}
fn worldHeightI(pos: Vector2) i32 {
const iheight = worldHeightF(pos);
return @intFromFloat(@round(iheight));
}

View File

@@ -1,5 +1,23 @@
const std = @import("std");
const Vector2 = @import("Vector2.zig").Vector2;
const f32x8 = @Vector(8, f32);
const i32x8 = @Vector(8, i32);
const u32x8 = @Vector(8, u32);
inline fn ps(value: f32) f32x8 {
return @splat(value);
}
inline fn epi32(value: i32) i32x8 {
return @splat(value);
}
inline fn epu32(value: u32) u32x8 {
return @splat(value);
}
const permutation = [256]u8{
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,
@@ -19,18 +37,56 @@ const permutation = [256]u8{
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
};
fn grad2(hash: u8, x: f32, y: f32) f32 {
const h: u3 = @truncate(hash);
const u: f32 = if (h < 4) x else y;
const v: f32 = if (h < 4) x else x;
return (if (h & 0b001 != 0) -u else u) + (if (hash & 0b010 != 0) -2 * v else 2 * v);
inline fn perm(i: i32) i32 {
@setRuntimeSafety(false);
const index: u32 = @as(u32, @bitCast(i)) & 0xFF;
return permutation[index];
}
const F2: f32 = 0.5 * (@sqrt(@as(f32, 3)) - 1);
inline fn permv(i: i32x8) i32x8 {
@setRuntimeSafety(false);
const index: u32x8 = @as(u32x8, @bitCast(i)) & epu32(0xFF);
return .{
permutation[index[0]],
permutation[index[1]],
permutation[index[2]],
permutation[index[3]],
permutation[index[4]],
permutation[index[5]],
permutation[index[6]],
permutation[index[7]],
};
}
fn grad2(hash: i32, x: f32, y: f32) f32 {
const h: i32 = hash & 0b111;
const u: f32 = if (h < 4) x else y;
const v: f32 = if (h < 4) x else x;
return (if (h & 0b001 != 0) -u else u) + (if (h & 0b010 != 0) -2 * v else 2 * v);
}
fn grad2v(hash: i32x8, x: f32x8, y: f32x8) f32x8 {
const h: i32x8 = hash & epi32(0b111);
const u: f32x8 = @select(f32, h < epi32(4), x, y);
const v: f32x8 = @select(f32, h < epi32(4), y, x);
const r1: f32x8 = @select(f32, h & epi32(0b001) != epi32(0), -u, u);
const r2: f32x8 = @select(f32, h & epi32(0b010) != epi32(0), ps(-2) * v, ps(2) * v);
return r1 + r2;
}
const F2: f32 = (@sqrt(@as(f32, 3)) - 1) / 2;
const G2: f32 = (3 - @sqrt(@as(f32, 3))) / 6;
const F2v: f32x8 = ps(F2);
const G2v: f32x8 = ps(G2);
// NOTE No idea why this value, derived experimentally
const noise2_scale: f32 = 34.11;
const noise2v_scale: f32x8 = ps(noise2_scale);
pub fn noise2(v: Vector2) f32 {
const x: f32, const y: f32 = v.asArray();
const s: f32 = (x + y) * F2;
const xs: f32 = x + s;
const ys: f32 = y + s;
@@ -43,23 +99,65 @@ pub fn noise2(v: Vector2) f32 {
const x0: f32 = x - X0;
const y0: f32 = y - Y0;
const _i1: u8, const _j1: u8 = if (x0 > y0) .{ 1, 0 } else .{ 0, 1 };
const _i1: i32 = if (x0 > y0) 1 else 0;
const _j1: i32 = if (x0 > y0) 0 else 1;
const x1: f32 = x0 - @as(f32, @floatFromInt(_i1)) + G2;
const y1: f32 = y0 - @as(f32, @floatFromInt(_j1)) + G2;
const x2: f32 = x0 - 1 + 2 * G2;
const y2: f32 = y0 - 1 + 2 * G2;
const ii: u8 = @truncate(@as(u32, @bitCast(i)));
const jj: u8 = @truncate(@as(u32, @bitCast(j)));
const t0: f32 = 0.5 - x0 * x0 - y0 * y0;
const t1: f32 = 0.5 - x1 * x1 - y1 * y1;
const t2: f32 = 0.5 - x2 * x2 - y2 * y2;
const n0 = if (t0 < 0) 0 else (t0 * t0) * (t0 * t0) * grad2(permutation[ii +% permutation[jj]], x0, y0);
const n1 = if (t1 < 0) 0 else (t1 * t1) * (t1 * t1) * grad2(permutation[ii +% _i1 +% permutation[jj +% _j1]], x1, y1);
const n2 = if (t2 < 0) 0 else (t2 * t2) * (t2 * t2) * grad2(permutation[ii +% 1 +% permutation[jj +% 1]], x2, y2);
const gi0: i32 = perm(i + perm(j));
const gi1: i32 = perm(i + _i1 + perm(j + _j1));
const gi2: i32 = perm(i + 1 + perm(j + 1));
return 40 * (n0 + n1 + n2);
const n0: f32 = if (t0 < 0) 0 else (t0 * t0) * (t0 * t0) * grad2(gi0, x0, y0);
const n1: f32 = if (t1 < 0) 0 else (t1 * t1) * (t1 * t1) * grad2(gi1, x1, y1);
const n2: f32 = if (t2 < 0) 0 else (t2 * t2) * (t2 * t2) * grad2(gi2, x2, y2);
const ret: f32 = noise2_scale * (n0 + n1 + n2);
std.debug.assert(ret >= -1 and ret <= 1);
return ret;
}
pub fn noise2v(x: f32x8, y: f32x8) f32x8 {
const s: f32x8 = (x + y) * F2v;
const xs: f32x8 = x + s;
const ys: f32x8 = y + s;
const i: i32x8 = @intFromFloat(@floor(xs));
const j: i32x8 = @intFromFloat(@floor(ys));
const t: f32x8 = @as(f32x8, @floatFromInt(i + j)) * G2v;
const X0: f32x8 = @as(f32x8, @floatFromInt(i)) - t;
const Y0: f32x8 = @as(f32x8, @floatFromInt(j)) - t;
const x0: f32x8 = x - X0;
const y0: f32x8 = y - Y0;
const _i1: i32x8 = @select(i32, x0 > y0, epi32(1), epi32(0));
const _j1: i32x8 = @select(i32, x0 > y0, epi32(0), epi32(1));
const x1: f32x8 = x0 - @as(f32x8, @floatFromInt(_i1)) + G2v;
const y1: f32x8 = y0 - @as(f32x8, @floatFromInt(_j1)) + G2v;
const x2: f32x8 = x0 - ps(1) + ps(2) * G2v;
const y2: f32x8 = y0 - ps(1) + ps(2) * G2v;
const t0: f32x8 = ps(0.5) - x0 * x0 - y0 * y0;
const t1: f32x8 = ps(0.5) - x1 * x1 - y1 * y1;
const t2: f32x8 = ps(0.5) - x2 * x2 - y2 * y2;
const gi0: i32x8 = permv(i + permv(j));
const gi1: i32x8 = permv(i + _i1 + permv(j + _j1));
const gi2: i32x8 = permv(i + epi32(1) + permv(j + epi32(1)));
const n0: f32x8 = @select(f32, t0 < ps(0), ps(0), (t0 * t0) * (t0 * t0) * grad2(gi0, x0, y0));
const n1: f32x8 = @select(f32, t1 < ps(0), ps(0), (t1 * t1) * (t1 * t1) * grad2(gi1, x1, y1));
const n2: f32x8 = @select(f32, t2 < ps(0), ps(0), (t2 * t2) * (t2 * t2) * grad2(gi2, x2, y2));
const ret: f32x8 = noise2v_scale * (n0 + n1 + n2);
std.debug.assert(@reduce(.And, ret >= ps(-1)) and @reduce(.And, ret <= ps(1)));
return ret;
}

View File

@@ -0,0 +1,32 @@
const std = @import("std");
fn noise2rangetest() void {
const f0: u32 = @bitCast(@as(f32, 1));
const f1: u32 = @bitCast(@as(f32, 10));
const step: u32 = (f1 - f0) / 30000;
var max: f32 = -std.math.inf(f32);
var timer = std.time.Timer.start() catch unreachable;
var y: u32 = f0;
while (y <= f1) : (y += step) {
const fy: f32 = @bitCast(@as(u32, @intCast(y)));
var x: u32 = f0;
while (x <= f1) : (x += step) {
const fx: f32 = @bitCast(@as(u32, @intCast(x)));
const noise = @import("noise.zig").noise2(.init(fx, fy));
const noise_abs = @abs(noise);
max = @max(noise_abs, max);
if (timer.read() > 1 * std.time.ns_per_s) {
_ = timer.lap();
const yp: f32 = @as(f32, @floatFromInt(y - f0)) / @as(f32, @floatFromInt(f1 - f0)) * 100.0;
std.debug.print("[{d:.2}%] max: {d} | scale: {d}\n", .{ yp, max, 1 / max });
}
}
}
std.debug.print("max: {d} | scale: {d}\n", .{ max, 1 / max });
}