Implemented terrain texturing

This commit is contained in:
Lorenzo Torres 2025-08-14 22:53:53 +02:00
parent 1475fd2101
commit 9fdd47ea6e
19 changed files with 1977 additions and 87 deletions

View file

@ -12,6 +12,8 @@ struct PointLight {
layout(location = 0) out vec4 outColor;
in vec4 gl_FragCoord;
layout(location = 2) in vec3 Normal;
layout(location = 3) in vec3 FragPos;
layout(location = 4) in vec2 TexCoords;
@ -35,14 +37,19 @@ layout(push_constant) uniform pc {
int light_count;
} pushConstants;
vec3 calc_directional_light(vec3 normal, vec3 viewDir) {
layout (set = 1, binding = 1) uniform sampler2D sand;
layout (set = 1, binding = 2) uniform sampler2D grass;
layout (set = 1, binding = 3) uniform sampler2D rock;
vec3 calc_directional_light(vec3 normal, vec3 viewDir, vec3 diffuse) {
vec3 lightDir = normalize(-directional_light.direction);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = directional_light.diffuse * diff;
return (directional_light.ambient + diffuse);
vec3 ambient = directional_light.ambient * diffuse;
vec3 d = directional_light.diffuse * diff * diffuse;
return (ambient + d);
}
vec3 calc_point_light(int index, vec3 normal, vec3 fragPos, vec3 viewDir) {
vec3 calc_point_light(int index, vec3 normal, vec3 fragPos, vec3 viewDir, vec3 diffuse) {
float constant = point_lights.point_lights[index].data[0];
float linear = point_lights.point_lights[index].data[1];
float quadratic = point_lights.point_lights[index].data[2];
@ -52,35 +59,43 @@ vec3 calc_point_light(int index, vec3 normal, vec3 fragPos, vec3 viewDir) {
vec3 reflectDir = reflect(-lightDir, normal);
float distance = length(point_lights.point_lights[index].position - fragPos);
float attenuation = 1.0 / (constant + linear * distance + quadratic * (distance * distance));
vec3 ambient = point_lights.point_lights[index].ambient;
vec3 diffuse = point_lights.point_lights[index].diffuse * diff;
vec3 ambient = point_lights.point_lights[index].ambient * diffuse;
vec3 d = point_lights.point_lights[index].diffuse * diff * diffuse;
ambient *= attenuation;
diffuse *= attenuation;
return (ambient + diffuse);
d *= attenuation;
return (ambient + d);
}
void main() {
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos.pos - FragPos);
vec3 result = calc_directional_light(norm, viewDir);
float height = FragPos.y;
float sandWeight = 1.0 - smoothstep(0.0, 0.035, height);
float grassWeight = smoothstep(0.035, 0.15, height) - smoothstep(0.25, 0.4, height);
float rockWeight = smoothstep(0.25, 0.4, height);
float total = sandWeight + grassWeight + rockWeight;
sandWeight /= total;
grassWeight /= total;
rockWeight /= total;
vec4 sandColor = texture(sand, TexCoords);
vec4 grassColor = texture(grass, TexCoords);
vec4 rockColor = texture(rock, TexCoords);
vec4 finalColor = sandColor * sandWeight +
grassColor * grassWeight +
rockColor * rockWeight;
vec3 result = calc_directional_light(norm, viewDir, vec3(finalColor));
//vec3 result = vec3(0.0, 0.0, 0.0);
for(int i = 0; i < pushConstants.light_count; i++)
result += calc_point_light(i, norm, FragPos, viewDir);
result += calc_point_light(i, norm, FragPos, viewDir, vec3(finalColor));
vec3 tall = vec3(1.0, 0.0, 0.0);
vec3 mid = vec3(0.0, 1.0, 0.0);
vec3 water = vec3(0.0, 0.0, 1.0);
vec3 color;
if (FragPos.y < 0.05) {
color = water;
} else if (FragPos.y > 0.3) {
color = tall;
} else {
color = mid;
}
outColor = vec4(color+result, 1.0);
outColor = vec4(result, 1.0);
//outColor = vec4(finalColor);
}

View file

@ -1,5 +1,6 @@
#version 450
layout(location = 0) in vec3 vertPos;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 uv;
@ -19,17 +20,18 @@ layout(location = 4) out vec2 TexCoords;
layout (set = 1, binding = 0) uniform sampler2D diffuseSampler;
void main() {
float texelSize = 1.0 / 200;
float hL = texture(diffuseSampler, uv - vec2(texelSize, 0.0)).r;
float hR = texture(diffuseSampler, uv + vec2(texelSize, 0.0)).r;
float hD = texture(diffuseSampler, uv - vec2(0.0, texelSize)).r;
float hU = texture(diffuseSampler, uv + vec2(0.0, texelSize)).r;
float texelSize = 1.0 / (50*4);
float hL = texture(diffuseSampler, uv - vec2(texelSize, 0.0)).r * 10;
float hR = texture(diffuseSampler, uv + vec2(texelSize, 0.0)).r * 10;
float hD = texture(diffuseSampler, uv - vec2(0.0, texelSize)).r * 10;
float hU = texture(diffuseSampler, uv + vec2(0.0, texelSize)).r * 10;
float dX = (hR - hL) * 15.0;
float dY = (hU - hD) * 15.0;
float y = texture(diffuseSampler, uv).x * 3;
vec4 out_vec = proj.proj * view.view * vec4(vec3(vertPos.x, y, vertPos.z), 1.0);
float y = texture(diffuseSampler, uv).x;
vec4 out_vec = proj.proj * view.view * vec4(vec3(vertPos.x, y * 10, vertPos.z), 1.0);
FragPos = vec3(vertPos.x, y, vertPos.z);
Normal = normalize(vec3(-dX, -dY, 1.0));

BIN
assets/textures/grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
assets/textures/rock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 MiB

BIN
assets/textures/sand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

BIN
colormap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

2
ext/stb_image.c vendored
View file

@ -1,2 +1,4 @@
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image.h"
#include "stb_image_write.h"

1724
ext/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load diff

BIN
heightmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

View file

@ -279,3 +279,7 @@ pub fn normalize(a: @Vector(3, f32)) @Vector(3, f32) {
pub inline fn scaleVector(a: @Vector(3, f32), s: f32) @Vector(3, f32) {
return a * @as(@Vector(3, f32), @splat(s));
}
pub inline fn inverseLerp(a: f64, b: f64, t: f64) f64 {
return (t - a) / (b - a);
}

View file

@ -62,17 +62,16 @@ fn noise(self: Self, x: f64, y: f64) f64 {
}
pub fn fbm(self: Self, x: f64, y: f64, octaves: u32, lacunarity: f64, gain: f64) f64 {
var total: f64 = 0.0;
var amplitude: f64 = 1.0;
var frequency: f64 = 1.0;
var maxAmplitude: f64 = 1.0;
var maxAmplitude: f64 = 0.0;
for(0..octaves) |_| {
total += self.noise(x * frequency, y * frequency) * amplitude;
maxAmplitude += amplitude;
const value = (self.noise(x * frequency, y * frequency) * 2) - 1;
maxAmplitude += amplitude * value;
amplitude *= gain;
frequency *= lacunarity;
}
return total / maxAmplitude;
return maxAmplitude;
}

View file

@ -216,7 +216,7 @@ pub fn bindDescriptorSets(self: Self, pipeline: vk.GraphicsPipeline, frame: usiz
}
pub fn bindTerrainSets(self: Self, pipeline: vk.TerrainPipeline, frame: usize) void {
const sets = [_]c.VkDescriptorSet {pipeline.descriptor_set, pipeline.heightmap};
const sets = [_]c.VkDescriptorSet {pipeline.descriptor_set, pipeline.map};
c.vkCmdBindDescriptorSets(self.command_buffers[frame], c.VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 2, sets[0..].ptr, 0, null);
}

View file

@ -647,8 +647,8 @@ pub fn init(allocator: Allocator, device: vk.Device, swapchain: vk.Swapchain, re
.view_pos_memory = view_pos_data,
.view_pos_buffer = view_pos_buffer,
.transform_buffer = transform_buffer,
.diffuse_sampler = try vk.Sampler.init(device),
.specular_sampler = try vk.Sampler.init(device),
.diffuse_sampler = try vk.Sampler.init(device, .linear),
.specular_sampler = try vk.Sampler.init(device, .linear),
.textures = std.ArrayList(c.VkDescriptorSet).init(allocator),
.vertex_buffer = vertex_buffer,
.index_buffer = index_buffer,

View file

@ -120,26 +120,29 @@ fn createIndexBuffer(device: vk.Device, indices: std.ArrayList(u32)) !vk.Buffer
return index_buffer;
}
pub fn terrain(allocator: std.mem.Allocator, device: vk.Device, width: usize, height: usize, resolution: f32) !struct { vk.Buffer, vk.Buffer } {
pub fn terrain(allocator: std.mem.Allocator, device: vk.Device, width: usize, height: usize, resolution: usize) !struct { vk.Buffer, vk.Buffer } {
var vertices = std.ArrayList([8]f32).init(allocator);
defer vertices.deinit();
var indices = std.ArrayList(u32).init(allocator);
defer indices.deinit();
for (0..width) |x| {
for (0..height) |z| {
const vertex: [8]f32 = .{@as(f32, @floatFromInt(x))/resolution, 0.0, @as(f32, @floatFromInt(z))/resolution, 0.0, 0.0, 0.0, @as(f32, @floatFromInt(x)) / @as(f32, @floatFromInt(width)), @as(f32, @floatFromInt(z)) / @as(f32, @floatFromInt(height))};
for (0..width*resolution) |x| {
for (0..height*resolution) |z| {
const offset_x = @as(f32, @floatFromInt(x)) / @as(f32, @floatFromInt(width*resolution - 1)) * @as(f32, @floatFromInt(width));
const offset_z = @as(f32, @floatFromInt(z)) / @as(f32, @floatFromInt(height*resolution - 1)) * @as(f32, @floatFromInt(height));
const vertex: [8]f32 = .{offset_x, 0.0, offset_z, 0.0, 0.0, 0.0, @as(f32, @floatFromInt(x)) / @as(f32, @floatFromInt(width*resolution - 1)), @as(f32, @floatFromInt(z)) / @as(f32, @floatFromInt(height*resolution - 1))};
try vertices.append(vertex);
}
}
for (0..width-1) |x| {
for (0..height-1) |z| {
const top_left = @as(u32, @intCast(z * width + x));
const top_right = @as(u32, @intCast(z * width + (x+1)));
const bottom_left = @as(u32, @intCast((z+1) * width + x));
const bottom_right = @as(u32, @intCast((z+1) * width + (x + 1)));
for (0..width*resolution-1) |x| {
for (0..height*resolution-1) |z| {
const top_left = @as(u32, @intCast(z * width*resolution + x));
const top_right = @as(u32, @intCast(z * width*resolution + (x+1)));
const bottom_left = @as(u32, @intCast((z+1) * width*resolution + x));
const bottom_right = @as(u32, @intCast((z+1) * width*resolution + (x + 1)));
try indices.append(top_left);
try indices.append(top_right);

View file

@ -2,6 +2,7 @@ const std = @import("std");
const vk = @import("vulkan.zig");
const Mesh = @import("Mesh.zig");
const math = @import("math");
const stb = vk.Texture.stb;
const Self = @This();
pub const Generator = struct {
@ -15,7 +16,7 @@ pub const Generator = struct {
width: usize,
height: usize,
seed: u64,
resolution: f32 = 1.0,
resolution: usize = 1,
};
heightmap: []f64,
@ -27,25 +28,56 @@ texture: vk.Texture,
vertex_buffer: vk.Buffer,
index_buffer: vk.Buffer,
const layers: [5][3]u32 = .{
.{0, 94, 255},
.{222, 208, 20},
.{14, 122, 41},
.{64, 20, 20},
.{253, 253, 253},
};
pub fn init(allocator: std.mem.Allocator, device: vk.Device, generator: Generator) !Self {
const perlin: math.PerlinNoise = .{ .seed = generator.seed };
const heightmap = try allocator.alloc(f64, generator.width * generator.height);
const heightmap_data = try allocator.alloc(u32, generator.width * generator.height);
const heightmap = try allocator.alloc(f64, generator.width*generator.resolution * generator.height*generator.resolution);
const heightmap_data = try allocator.alloc(u32, generator.width*generator.resolution * generator.height*generator.resolution);
defer allocator.free(heightmap_data);
for (0..generator.width) |x| {
for (0..generator.height) |y| {
var pixel = (perlin.fbm(@as(f64, @floatFromInt(x)) * generator.scale, @as(f64, @floatFromInt(y)) * generator.scale, generator.octaves, generator.lacunarity, generator.gain) * generator.multiplier);
pixel = std.math.pow(f64, pixel, generator.exponent);
const gray: u32 = @intFromFloat(pixel * 255);
const color: u32 = (255 << 24) | (gray << 16) | (gray << 8) | gray;
heightmap[x*generator.width + y] = pixel;
heightmap_data[x*generator.width + y] = color;
var max_noise_height = std.math.floatMin(f64);
var min_noise_height = std.math.floatMax(f64);
const columns = generator.width*generator.resolution;
const rows = generator.height*generator.resolution;
for (0..columns) |x| {
for (0..rows) |y| {
const u = @as(f64, @floatFromInt(x)) / @as(f64, @floatFromInt(columns - 1));
const v = @as(f64, @floatFromInt(y)) / @as(f64, @floatFromInt(rows - 1));
const h_x = u * @as(f64, @floatFromInt(generator.width));
const h_y = v * @as(f64, @floatFromInt(generator.height));
var pixel = (perlin.fbm(h_x / generator.scale, h_y / generator.scale, generator.octaves, generator.lacunarity, generator.gain) * generator.multiplier);
if (pixel > max_noise_height) {
max_noise_height = pixel;
} else if (pixel < min_noise_height) {
min_noise_height = pixel;
}
pixel = std.math.pow(f64, pixel, generator.exponent);
pixel = math.inverseLerp(min_noise_height, max_noise_height, pixel);
heightmap[x*columns + y] = pixel;
const gray: u32 = @intFromFloat(pixel * 255);
const grayscale: u32 = (255 << 24) | (gray << 16) | (gray << 8) | gray;
heightmap_data[x*columns + y] = grayscale;
}
}
const vertex_buffer, const index_buffer = try Mesh.terrain(allocator, device, generator.width, generator.height, generator.resolution);
const heightmap_texture = try vk.Texture.fromBytes(@alignCast(@ptrCast(heightmap_data)), device, generator.width, generator.height);
const heightmap_texture = try vk.Texture.fromBytes(@alignCast(@ptrCast(heightmap_data)), device, generator.width*generator.resolution, generator.height*generator.resolution);
return .{
.heightmap = heightmap,
@ -68,3 +100,21 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator, device: vk.Device) !voi
pub fn getHeight(self: Self, x: usize, y: usize) f64 {
return self.heightmap[x*self.width + y];
}
fn pixelToNoise(
x: usize,
y: usize,
width: usize,
height: usize,
world_min: @Vector(2, f64),
world_max: @Vector(2, f64),
scale: f64
) struct { f64, f64 }{
const u = (@as(f64, @floatFromInt(x)) + 0.5) / @as(f64, @floatFromInt(width));
const v = (@as(f64, @floatFromInt(y)) + 0.5) / @as(f64, @floatFromInt(height));
const world_x = world_min[0] + u * (world_max[0] - world_min[0]);
const world_y = world_min[1] + v * (world_max[1] - world_min[1]);
return .{ world_x / scale, world_y / scale };
}

View file

@ -21,7 +21,10 @@ descriptor_pool: c.VkDescriptorPool,
descriptor_set: c.VkDescriptorSet,
descriptor_set_layout: c.VkDescriptorSetLayout,
heightmap_sampler: vk.Sampler,
heightmap: c.VkDescriptorSet,
sand_sampler: vk.Sampler,
grass_sampler: vk.Sampler,
rock_sampler: vk.Sampler,
map: c.VkDescriptorSet,
const Self = @This();
@ -172,8 +175,29 @@ pub fn init(
.stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT,
};
const sand_sampler_binding = c.VkDescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
};
const grass_sampler_binding = c.VkDescriptorSetLayoutBinding{
.binding = 2,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
};
const stone_sampler_binding = c.VkDescriptorSetLayoutBinding{
.binding = 3,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
};
const bindings = [_]c.VkDescriptorSetLayoutBinding{projection_binding, view_binding, directional_light_binding, point_lights_binding, view_pos_binding};
const texture_bindings = [_]c.VkDescriptorSetLayoutBinding{heightmap_sampler_binding};
const texture_bindings = [_]c.VkDescriptorSetLayoutBinding{heightmap_sampler_binding, sand_sampler_binding, grass_sampler_binding, stone_sampler_binding};
var descriptor_set_layout: c.VkDescriptorSetLayout = undefined;
var texture_descriptor_set_layout: c.VkDescriptorSetLayout = undefined;
@ -186,7 +210,7 @@ pub fn init(
const texture_descriptor_set_layout_info = c.VkDescriptorSetLayoutCreateInfo{
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1,
.bindingCount = 4,
.pBindings = texture_bindings[0..].ptr,
};
@ -256,7 +280,7 @@ pub fn init(
const sampler_size = c.VkDescriptorPoolSize{
.type = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.descriptorCount = 4,
};
const sizes = [_]c.VkDescriptorPoolSize {size, sampler_size};
@ -379,12 +403,15 @@ pub fn init(
.descriptor_pool = descriptor_pool,
.descriptor_set = descriptor_set,
.descriptor_set_layout = descriptor_set_layout,
.heightmap_sampler = try vk.Sampler.init(device),
.heightmap = undefined,
.heightmap_sampler = try vk.Sampler.init(device, .nearest),
.sand_sampler = try vk.Sampler.init(device, .linear),
.grass_sampler = try vk.Sampler.init(device, .linear),
.rock_sampler = try vk.Sampler.init(device, .linear),
.map = undefined,
};
}
pub fn setHeightmap(self: *Self, device: anytype, heightmap: Texture) !void {
pub fn setMaps(self: *Self, device: anytype, heightmap: Texture) !void {
var set_layouts = [_]c.VkDescriptorSetLayout{self.texture_set_layout};
const descriptor_allocate_info = c.VkDescriptorSetAllocateInfo{
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
@ -396,25 +423,79 @@ pub fn setHeightmap(self: *Self, device: anytype, heightmap: Texture) !void {
var descriptor_set: c.VkDescriptorSet = undefined;
try vk.mapError(c.vkAllocateDescriptorSets(device.handle, &descriptor_allocate_info, &descriptor_set));
const texture_info: c.VkDescriptorImageInfo = .{
const height_info: c.VkDescriptorImageInfo = .{
.imageLayout = c.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = heightmap.image_view,
.sampler = self.heightmap_sampler.handle,
};
const write_texture_descriptor_set = c.VkWriteDescriptorSet{
const sand = try Texture.init("assets/textures/sand.png", device);
const grass = try Texture.init("assets/textures/grass.png", device);
const rock = try Texture.init("assets/textures/rock.png", device);
const sand_info: c.VkDescriptorImageInfo = .{
.imageLayout = c.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = sand.image_view,
.sampler = self.sand_sampler.handle,
};
const grass_info: c.VkDescriptorImageInfo = .{
.imageLayout = c.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = grass.image_view,
.sampler = self.grass_sampler.handle,
};
const rock_info: c.VkDescriptorImageInfo = .{
.imageLayout = c.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.imageView = rock.image_view,
.sampler = self.rock_sampler.handle,
};
const write_height_descriptor_set = c.VkWriteDescriptorSet{
.sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &texture_info,
.pImageInfo = &height_info,
};
c.vkUpdateDescriptorSets(device.handle, 1, &write_texture_descriptor_set, 0, null);
const write_sand_descriptor_set = c.VkWriteDescriptorSet{
.sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set,
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &sand_info,
};
self.heightmap = descriptor_set;
const write_grass_descriptor_set = c.VkWriteDescriptorSet{
.sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set,
.dstBinding = 2,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &grass_info,
};
const write_rock_descriptor_set = c.VkWriteDescriptorSet{
.sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set,
.dstBinding = 3,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &rock_info,
};
const writes = [_]c.VkWriteDescriptorSet {write_height_descriptor_set, write_sand_descriptor_set, write_grass_descriptor_set, write_rock_descriptor_set};
c.vkUpdateDescriptorSets(device.handle, 4, writes[0..].ptr, 0, null);
self.map = descriptor_set;
}
pub fn bind(self: Self, device: vk.Device, frame: usize) void {

View file

@ -3,6 +3,7 @@ const vk = @import("vulkan.zig");
const c = vk.c;
pub const stb = @cImport({
@cInclude("stb_image.h");
@cInclude("stb_image_write.h");
});
image: c.VkImage,

View file

@ -32,6 +32,8 @@ const validation_layers: []const [*c]const u8 = if (!debug) &[0][*c]const u8{} e
pub const Error = error{
out_of_host_memory,
out_of_device_memory,
out_of_pool_memory,
fragmented_pool,
initialization_failed,
layer_not_present,
extension_not_present,
@ -50,6 +52,8 @@ pub fn mapError(result: c_int) !void {
c.VK_ERROR_LAYER_NOT_PRESENT => Error.layer_not_present,
c.VK_ERROR_EXTENSION_NOT_PRESENT => Error.extension_not_present,
c.VK_ERROR_INCOMPATIBLE_DRIVER => Error.incompatible_driver,
c.VK_ERROR_OUT_OF_POOL_MEMORY => Error.out_of_pool_memory,
c.VK_ERROR_FRAGMENTED_POOL => Error.fragmented_pool,
else => Error.unknown_error,
};
}
@ -105,16 +109,21 @@ pub const Buffer = struct {
}
};
pub const SamplerType = enum {
linear,
nearest,
};
pub const Sampler = struct {
handle: c.VkSampler,
pub fn init(device: anytype) !Sampler {
pub fn init(device: anytype, filter: SamplerType) !Sampler {
var sampler: c.VkSampler = undefined;
const create_info: c.VkSamplerCreateInfo = .{
.sType = c.VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = c.VK_FILTER_NEAREST,
.minFilter = c.VK_FILTER_NEAREST,
.magFilter = if (filter == .linear) c.VK_FILTER_LINEAR else c.VK_FILTER_NEAREST,
.minFilter = if (filter == .linear) c.VK_FILTER_LINEAR else c.VK_FILTER_NEAREST,
.addressModeU = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeV = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeW = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,

View file

@ -146,20 +146,20 @@ export fn sideros_init(init: api.GameInit) callconv(.c) void {
renderer = Renderer.init(allocator, @ptrCast(init.instance), @ptrCast(init.surface)) catch @panic("TODO: Gracefully handle error");
resources.terrain = rendering.Terrain.init(allocator, renderer.device, .{
.octaves = 8,
.lacunarity = 3.0,
.octaves = 4,
.lacunarity = 2.0,
.gain = 0.5,
.scale = 0.01,
.multiplier = 3.0,
.exponent = 1.2,
.scale = 30,
.multiplier = 1.0,
.exponent = 1.0,
.width = 700,
.height = 700,
.seed = 12345678,
.resolution = 10.0,
.width = 100,
.height = 100,
.seed = 2497852058242342,
.resolution = 1,
}) catch @panic("TODO: handle this");
renderer.terrain_pipeline.setHeightmap(renderer.device, resources.terrain.texture) catch @panic("TODO: handle this");
renderer.terrain_pipeline.setMaps(renderer.device, resources.terrain.texture) catch @panic("TODO: handle this");
pool.addSystemGroup(&[_]ecs.System{systems.render, systems.moveCamera}, true) catch @panic("TODO: Gracefuly handle error");
pool.resources.renderer = &renderer;