Implemented terrain texturing
This commit is contained in:
parent
1475fd2101
commit
9fdd47ea6e
19 changed files with 1977 additions and 87 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
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
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
BIN
assets/textures/sand.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1 MiB |
BIN
colormap.png
Normal file
BIN
colormap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
2
ext/stb_image.c
vendored
2
ext/stb_image.c
vendored
|
|
@ -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
1724
ext/stb_image_write.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
heightmap.png
Normal file
BIN
heightmap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 414 KiB |
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue