Implemented simple terrain generation
This commit is contained in:
parent
fb9607b2b1
commit
c0b8d021d4
16 changed files with 825 additions and 32 deletions
|
|
@ -78,5 +78,6 @@ void main() {
|
||||||
for(int i = 0; i < pushConstants.light_count; i++)
|
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);
|
||||||
|
|
||||||
|
|
||||||
outColor = vec4(result, 1.0);
|
outColor = vec4(result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,3 +41,4 @@ void main() {
|
||||||
TexCoords = uv;
|
TexCoords = uv;
|
||||||
gl_Position = out_vec;
|
gl_Position = out_vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
86
assets/shaders/terrain.frag
Normal file
86
assets/shaders/terrain.frag
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
#define MAX_POINT_LIGHTS 1024
|
||||||
|
|
||||||
|
struct PointLight {
|
||||||
|
vec3 position;
|
||||||
|
vec3 ambient;
|
||||||
|
vec3 diffuse;
|
||||||
|
vec3 specular;
|
||||||
|
vec3 data;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(location = 2) in vec3 Normal;
|
||||||
|
layout(location = 3) in vec3 FragPos;
|
||||||
|
layout(location = 4) in vec2 TexCoords;
|
||||||
|
|
||||||
|
layout (binding = 2) uniform DirectionalLight {
|
||||||
|
vec3 direction;
|
||||||
|
|
||||||
|
vec3 ambient;
|
||||||
|
vec3 diffuse;
|
||||||
|
vec3 specular;
|
||||||
|
} directional_light;
|
||||||
|
layout (binding = 5) uniform PointLights {
|
||||||
|
PointLight point_lights[MAX_POINT_LIGHTS];
|
||||||
|
} point_lights;
|
||||||
|
|
||||||
|
layout (binding = 3) uniform ViewUniform {
|
||||||
|
vec3 pos;
|
||||||
|
} viewPos;
|
||||||
|
|
||||||
|
layout(push_constant) uniform pc {
|
||||||
|
int light_count;
|
||||||
|
} pushConstants;
|
||||||
|
|
||||||
|
vec3 calc_directional_light(vec3 normal, vec3 viewDir) {
|
||||||
|
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 calc_point_light(int index, vec3 normal, vec3 fragPos, vec3 viewDir) {
|
||||||
|
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];
|
||||||
|
|
||||||
|
vec3 lightDir = normalize(point_lights.point_lights[index].position - fragPos);
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
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;
|
||||||
|
ambient *= attenuation;
|
||||||
|
diffuse *= attenuation;
|
||||||
|
return (ambient + diffuse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 norm = normalize(Normal);
|
||||||
|
vec3 viewDir = normalize(viewPos.pos - FragPos);
|
||||||
|
|
||||||
|
vec3 result = calc_directional_light(norm, viewDir);
|
||||||
|
//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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
38
assets/shaders/terrain.vert
Normal file
38
assets/shaders/terrain.vert
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 vertPos;
|
||||||
|
layout(location = 1) in vec3 normal;
|
||||||
|
layout(location = 2) in vec2 uv;
|
||||||
|
|
||||||
|
layout (binding = 0) uniform ProjUniform {
|
||||||
|
mat4 proj;
|
||||||
|
} proj;
|
||||||
|
|
||||||
|
layout (binding = 1) uniform ViewUniform {
|
||||||
|
mat4 view;
|
||||||
|
} view;
|
||||||
|
|
||||||
|
layout(location = 2) out vec3 Normal;
|
||||||
|
layout(location = 3) out vec3 FragPos;
|
||||||
|
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 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);
|
||||||
|
FragPos = vec3(vertPos.x, y, vertPos.z);
|
||||||
|
|
||||||
|
Normal = normalize(vec3(-dX, -dY, 1.0));
|
||||||
|
TexCoords = uv;
|
||||||
|
gl_Position = out_vec;
|
||||||
|
}
|
||||||
BIN
assets/textures/heightmap.png
Normal file
BIN
assets/textures/heightmap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
|
|
@ -6,6 +6,8 @@ pub const rad = std.math.degreesToRadians;
|
||||||
pub const deg = std.math.radiansToDegrees;
|
pub const deg = std.math.radiansToDegrees;
|
||||||
pub const sqrt = std.math.sqrt;
|
pub const sqrt = std.math.sqrt;
|
||||||
|
|
||||||
|
pub const PerlinNoise = @import("math/PerlinNoise.zig");
|
||||||
|
|
||||||
pub const Axis = struct {
|
pub const Axis = struct {
|
||||||
pub const x: [3]f32 = .{1.0, 0.0, 0.0};
|
pub const x: [3]f32 = .{1.0, 0.0, 0.0};
|
||||||
pub const y: [3]f32 = .{0.0, 1.0, 0.0};
|
pub const y: [3]f32 = .{0.0, 1.0, 0.0};
|
||||||
|
|
|
||||||
78
src/math/PerlinNoise.zig
Normal file
78
src/math/PerlinNoise.zig
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
seed: u64,
|
||||||
|
|
||||||
|
fn hash(self: Self, x: i32, y: i32) u64 {
|
||||||
|
var hasher = std.hash.Wyhash.init(self.seed);
|
||||||
|
hasher.update(std.mem.asBytes(&x));
|
||||||
|
hasher.update(std.mem.asBytes(&y));
|
||||||
|
return hasher.final();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random(self: Self, x: i32, y: i32) @Vector(2, f64) {
|
||||||
|
const h = self.hash(x, y);
|
||||||
|
var rng = std.Random.DefaultPrng.init(h);
|
||||||
|
const angle = rng.random().float(f64) * std.math.tau;
|
||||||
|
|
||||||
|
return .{ std.math.cos(angle), std.math.sin(angle) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dot(a: @Vector(2, f64), b: @Vector(2, f64)) f64 {
|
||||||
|
return @reduce(.Add, a*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fade(t: f64) f64 {
|
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lerp(a: f64, b: f64, t: f64) f64 {
|
||||||
|
return a + t * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn noise(self: Self, x: f64, y: f64) f64 {
|
||||||
|
const x0 = @as(i32, @intFromFloat(std.math.floor(x)));
|
||||||
|
const y0 = @as(i32, @intFromFloat(std.math.floor(y)));
|
||||||
|
const x1 = x0 + 1;
|
||||||
|
const y1 = y0 + 1;
|
||||||
|
|
||||||
|
const sx = fade(x - @as(f64, @floatFromInt(x0)));
|
||||||
|
const sy = fade(y - @as(f64, @floatFromInt(y0)));
|
||||||
|
|
||||||
|
const grad00 = self.random(x0, y0);
|
||||||
|
const grad10 = self.random(x1, y0);
|
||||||
|
const grad01 = self.random(x0, y1);
|
||||||
|
const grad11 = self.random(x1, y1);
|
||||||
|
|
||||||
|
const dx = x - @as(f64, @floatFromInt(x0));
|
||||||
|
const dy = y - @as(f64, @floatFromInt(y0));
|
||||||
|
|
||||||
|
const dot00 = dot(grad00, .{ dx, dy });
|
||||||
|
const dot10 = dot(grad10, .{ dx - 1, dy });
|
||||||
|
const dot01 = dot(grad01, .{ dx, dy - 1 });
|
||||||
|
const dot11 = dot(grad11, .{ dx - 1, dy - 1 });
|
||||||
|
|
||||||
|
const ix0 = lerp(dot00, dot10, sx);
|
||||||
|
const ix1 = lerp(dot01, dot11, sx);
|
||||||
|
|
||||||
|
const value = lerp(ix0, ix1, sy);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for(0..octaves) |_| {
|
||||||
|
total += self.noise(x * frequency, y * frequency) * amplitude;
|
||||||
|
maxAmplitude += amplitude;
|
||||||
|
amplitude *= gain;
|
||||||
|
frequency *= lacunarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total / maxAmplitude;
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ pitch: f32 = -45,
|
||||||
yaw: f32 = 0,
|
yaw: f32 = 0,
|
||||||
|
|
||||||
pub fn getProjection(width: usize, height: usize) math.Matrix {
|
pub fn getProjection(width: usize, height: usize) math.Matrix {
|
||||||
return math.Matrix.perspective(math.rad(45.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 100.0);
|
return math.Matrix.perspective(math.rad(45.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getView(self: *Camera) math.Matrix {
|
pub fn getView(self: *Camera) math.Matrix {
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,12 @@ pub fn transitionImageLayout(self: Self, image: c.VkImage, format: c.VkFormat, o
|
||||||
try self.endSingleTimeCommands(command_buffer);
|
try self.endSingleTimeCommands(command_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drawTerrain(self: Self, indices: u32, frame: usize, vertex_buffer: vk.Buffer, index_buffer: vk.Buffer) void {
|
||||||
|
std.debug.assert(frame < frames_in_flight);
|
||||||
|
c.vkCmdBindIndexBuffer(self.command_buffers[frame], index_buffer.handle, 0, c.VK_INDEX_TYPE_UINT32);
|
||||||
|
self.bindVertexBuffer(vertex_buffer, frame);
|
||||||
|
c.vkCmdDrawIndexed(self.command_buffers[frame], indices, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw(self: Self, indices: u32, frame: usize, mesh: Mesh) void {
|
pub fn draw(self: Self, indices: u32, frame: usize, mesh: Mesh) void {
|
||||||
std.debug.assert(frame < frames_in_flight);
|
std.debug.assert(frame < frames_in_flight);
|
||||||
|
|
@ -210,6 +215,11 @@ pub fn bindDescriptorSets(self: Self, pipeline: vk.GraphicsPipeline, frame: usiz
|
||||||
c.vkCmdBindDescriptorSets(self.command_buffers[frame], c.VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 2, sets[0..].ptr, 0, null);
|
c.vkCmdBindDescriptorSets(self.command_buffers[frame], c.VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 2, sets[0..].ptr, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bindTerrainSets(self: Self, pipeline: vk.TerrainPipeline, frame: usize) void {
|
||||||
|
const sets = [_]c.VkDescriptorSet {pipeline.descriptor_set, pipeline.heightmap};
|
||||||
|
c.vkCmdBindDescriptorSets(self.command_buffers[frame], c.VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 2, sets[0..].ptr, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn updateBuffer(self: Self, comptime T: type, buffer: vk.Buffer, data: [*]T, frame: usize) void {
|
pub fn updateBuffer(self: Self, comptime T: type, buffer: vk.Buffer, data: [*]T, frame: usize) void {
|
||||||
c.vkCmdUpdateBuffer(self.command_buffers[frame], buffer.handle, 0, @sizeOf(T), @ptrCast(@alignCast(data)));
|
c.vkCmdUpdateBuffer(self.command_buffers[frame], buffer.handle, 0, @sizeOf(T), @ptrCast(@alignCast(data)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,18 @@ view_buffer: vk.Buffer,
|
||||||
view_memory: [*c]u8,
|
view_memory: [*c]u8,
|
||||||
transform_buffer: vk.DynamicBuffer(math.Transform),
|
transform_buffer: vk.DynamicBuffer(math.Transform),
|
||||||
view_pos_memory: [*c]u8,
|
view_pos_memory: [*c]u8,
|
||||||
|
view_pos_buffer: vk.Buffer,
|
||||||
diffuse_sampler: vk.Sampler,
|
diffuse_sampler: vk.Sampler,
|
||||||
specular_sampler: vk.Sampler,
|
specular_sampler: vk.Sampler,
|
||||||
textures: std.ArrayList(c.VkDescriptorSet),
|
textures: std.ArrayList(c.VkDescriptorSet),
|
||||||
directional_light: *lights.DirectionalLight,
|
directional_light: *lights.DirectionalLight,
|
||||||
|
directional_light_buffer: vk.Buffer,
|
||||||
point_lights: []lights.PointLight,
|
point_lights: []lights.PointLight,
|
||||||
|
point_lights_buffer: vk.Buffer,
|
||||||
|
|
||||||
|
device: vk.Device,
|
||||||
|
render_pass: vk.RenderPass,
|
||||||
|
swapchain: vk.Swapchain,
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
|
@ -638,6 +645,7 @@ pub fn init(allocator: Allocator, device: vk.Device, swapchain: vk.Swapchain, re
|
||||||
.view_buffer = view_buffer,
|
.view_buffer = view_buffer,
|
||||||
.view_memory = view_data,
|
.view_memory = view_data,
|
||||||
.view_pos_memory = view_pos_data,
|
.view_pos_memory = view_pos_data,
|
||||||
|
.view_pos_buffer = view_pos_buffer,
|
||||||
.transform_buffer = transform_buffer,
|
.transform_buffer = transform_buffer,
|
||||||
.diffuse_sampler = try vk.Sampler.init(device),
|
.diffuse_sampler = try vk.Sampler.init(device),
|
||||||
.specular_sampler = try vk.Sampler.init(device),
|
.specular_sampler = try vk.Sampler.init(device),
|
||||||
|
|
@ -645,7 +653,13 @@ pub fn init(allocator: Allocator, device: vk.Device, swapchain: vk.Swapchain, re
|
||||||
.vertex_buffer = vertex_buffer,
|
.vertex_buffer = vertex_buffer,
|
||||||
.index_buffer = index_buffer,
|
.index_buffer = index_buffer,
|
||||||
.directional_light = directional_light,
|
.directional_light = directional_light,
|
||||||
|
.directional_light_buffer = directional_light_buffer,
|
||||||
.point_lights = point_lights,
|
.point_lights = point_lights,
|
||||||
|
.point_lights_buffer = point_lights_buffer,
|
||||||
|
|
||||||
|
.device = device,
|
||||||
|
.swapchain = swapchain,
|
||||||
|
.render_pass = render_pass,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ const vk = @import("vulkan.zig");
|
||||||
const gltf = @import("gltf.zig");
|
const gltf = @import("gltf.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const c = vk.c;
|
const c = vk.c;
|
||||||
|
const math = @import("math");
|
||||||
|
|
||||||
const Mesh = @This();
|
const Mesh = @This();
|
||||||
|
|
||||||
|
|
@ -59,12 +60,99 @@ pub const Vertex = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, device: anytype) !Mesh {
|
fn createVertexBuffer(device: vk.Device, vertices: std.ArrayList([8]f32)) !vk.Buffer {
|
||||||
const vertex_buffer = try Mesh.createVertexBuffer(allocator, device);
|
var data: [*c]?*anyopaque = null;
|
||||||
const index_buffer = try Mesh.createIndexBuffer(allocator, device);
|
|
||||||
|
|
||||||
return Mesh{
|
const buffer = try device.initBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf([8]f32) * vertices.items.len);
|
||||||
.vertex_buffer = vertex_buffer,
|
|
||||||
.index_buffer = index_buffer,
|
try vk.mapError(vk.c.vkMapMemory(
|
||||||
};
|
device.handle,
|
||||||
|
buffer.memory,
|
||||||
|
0,
|
||||||
|
buffer.size,
|
||||||
|
0,
|
||||||
|
@ptrCast(&data),
|
||||||
|
));
|
||||||
|
|
||||||
|
if (data) |ptr| {
|
||||||
|
const gpu_vertices: [*]Mesh.Vertex = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
@memcpy(gpu_vertices, @as([]Mesh.Vertex, @ptrCast(vertices.items[0..])));
|
||||||
|
}
|
||||||
|
|
||||||
|
vk.c.vkUnmapMemory(device.handle, buffer.memory);
|
||||||
|
|
||||||
|
const vertex_buffer = try device.initBuffer(vk.BufferUsage{ .vertex_buffer = true, .transfer_dst = true, .transfer_src = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(Mesh.Vertex) * vertices.items.len);
|
||||||
|
|
||||||
|
try buffer.copyTo(device, vertex_buffer, 0);
|
||||||
|
buffer.deinit(device.handle);
|
||||||
|
|
||||||
|
return vertex_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createIndexBuffer(device: vk.Device, indices: std.ArrayList(u32)) !vk.Buffer {
|
||||||
|
var data: [*c]?*anyopaque = null;
|
||||||
|
|
||||||
|
const buffer = try device.initBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(u32) * indices.items.len);
|
||||||
|
|
||||||
|
try vk.mapError(vk.c.vkMapMemory(
|
||||||
|
device.handle,
|
||||||
|
buffer.memory,
|
||||||
|
0,
|
||||||
|
buffer.size,
|
||||||
|
0,
|
||||||
|
@ptrCast(&data),
|
||||||
|
));
|
||||||
|
|
||||||
|
if (data) |ptr| {
|
||||||
|
const gpu_indices: [*]u32 = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
@memcpy(gpu_indices, indices.items[0..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk.c.vkUnmapMemory(device.handle, buffer.memory);
|
||||||
|
|
||||||
|
const index_buffer = try device.initBuffer(vk.BufferUsage{ .index_buffer = true, .transfer_dst = true, .transfer_src = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(u32) * indices.items.len);
|
||||||
|
|
||||||
|
try buffer.copyTo(device, index_buffer, 0);
|
||||||
|
buffer.deinit(device.handle);
|
||||||
|
|
||||||
|
return index_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terrain(allocator: std.mem.Allocator, device: vk.Device, width: usize, height: usize, resolution: f32) !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))};
|
||||||
|
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)));
|
||||||
|
|
||||||
|
try indices.append(top_left);
|
||||||
|
try indices.append(top_right);
|
||||||
|
try indices.append(bottom_left);
|
||||||
|
|
||||||
|
try indices.append(top_right);
|
||||||
|
try indices.append(bottom_right);
|
||||||
|
try indices.append(bottom_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vertex_buffer = try createVertexBuffer(device, vertices);
|
||||||
|
const index_buffer = try createIndexBuffer(device, indices);
|
||||||
|
|
||||||
|
return .{ vertex_buffer, index_buffer };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,14 @@ device: vk.Device,
|
||||||
render_pass: vk.RenderPass,
|
render_pass: vk.RenderPass,
|
||||||
swapchain: vk.Swapchain,
|
swapchain: vk.Swapchain,
|
||||||
graphics_pipeline: vk.GraphicsPipeline,
|
graphics_pipeline: vk.GraphicsPipeline,
|
||||||
|
terrain_pipeline: vk.TerrainPipeline,
|
||||||
current_frame: u32,
|
current_frame: u32,
|
||||||
mesh: Mesh,
|
mesh: Mesh,
|
||||||
transforms: std.ArrayList(math.Transform),
|
transforms: std.ArrayList(math.Transform),
|
||||||
previous_time: std.time.Instant,
|
previous_time: std.time.Instant,
|
||||||
current_image: usize,
|
current_image: usize,
|
||||||
|
terrain_vertex: vk.Buffer,
|
||||||
|
terrain_index: vk.Buffer,
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self {
|
pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self {
|
||||||
const instance: vk.Instance = .{ .handle = instance_handle };
|
const instance: vk.Instance = .{ .handle = instance_handle };
|
||||||
|
|
@ -41,13 +44,32 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand
|
||||||
const mesh = try pipeline_builder.addMesh("assets/models/cube.glb");
|
const mesh = try pipeline_builder.addMesh("assets/models/cube.glb");
|
||||||
var graphics_pipeline = try pipeline_builder.build(swapchain, render_pass, vertex_shader, fragment_shader);
|
var graphics_pipeline = try pipeline_builder.build(swapchain, render_pass, vertex_shader, fragment_shader);
|
||||||
|
|
||||||
// TODO: I think the renderer shouldn't have to interact with buffers. I think the API should change to
|
const terrain_vertex_shader = try device.initShader("terrain_vert");
|
||||||
// something along the lines of
|
defer device.deinitShader(terrain_vertex_shader);
|
||||||
// renderer.begin()
|
const terrain_fragment_shader = try device.initShader("terrain_frag");
|
||||||
// renderer.render(triangle);
|
defer device.deinitShader(terrain_fragment_shader);
|
||||||
// renderer.render(some_other_thing);
|
|
||||||
// ...
|
var terrain_pipeline = try vk.TerrainPipeline.init(graphics_pipeline, terrain_vertex_shader, terrain_fragment_shader);
|
||||||
// renderer.submit()
|
|
||||||
|
const perlin: math.PerlinNoise = .{ .seed = 54321 };
|
||||||
|
const heightmap = try allocator.alloc(u32, 700 * 700);
|
||||||
|
defer allocator.free(heightmap);
|
||||||
|
for (0..700) |x| {
|
||||||
|
for (0..700) |y| {
|
||||||
|
const scale = 0.01;
|
||||||
|
var pixel = (perlin.fbm(@as(f64, @floatFromInt(x)) * scale, @as(f64, @floatFromInt(y)) * scale, 8, 3, 0.5) * 3);
|
||||||
|
pixel = std.math.pow(f64, pixel, 1.2);
|
||||||
|
const gray: u32 = @intFromFloat(pixel * 255);
|
||||||
|
const color: u32 = (255 << 24) | (gray << 16) | (gray << 8) | gray;
|
||||||
|
|
||||||
|
heightmap[x*700 + y] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const terrain_vertex, const terrain_index = try Mesh.terrain(allocator, device, 700, 700, 10);
|
||||||
|
const heightmap_texture = try Texture.fromBytes(@alignCast(@ptrCast(heightmap)), device, 700, 700);
|
||||||
|
//const heightmap_texture = try Texture.init("assets/textures/heightmap.png", device);
|
||||||
|
try terrain_pipeline.setHeightmap(device, heightmap_texture);
|
||||||
const texture = try Texture.init("assets/textures/container.png", device);
|
const texture = try Texture.init("assets/textures/container.png", device);
|
||||||
const diffuse = try Texture.init("assets/textures/container_specular.png", device);
|
const diffuse = try Texture.init("assets/textures/container_specular.png", device);
|
||||||
|
|
||||||
|
|
@ -79,6 +101,7 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand
|
||||||
try transforms.append(math.Transform.init(.{0.0, 0.5, 1.0}, .{0.5, 0.5, 0.5}, .{0.0, 0.0, 0.0}));
|
try transforms.append(math.Transform.init(.{0.0, 0.5, 1.0}, .{0.5, 0.5, 0.5}, .{0.0, 0.0, 0.0}));
|
||||||
try transforms.append(math.Transform.init(.{0.0, 0.0, 0.0}, .{0.5, 0.5, 0.5}, .{0.0, 0.0, 0.0}));
|
try transforms.append(math.Transform.init(.{0.0, 0.0, 0.0}, .{0.5, 0.5, 0.5}, .{0.0, 0.0, 0.0}));
|
||||||
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.instance = instance,
|
.instance = instance,
|
||||||
.surface = surface,
|
.surface = surface,
|
||||||
|
|
@ -87,11 +110,14 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand
|
||||||
.render_pass = render_pass,
|
.render_pass = render_pass,
|
||||||
.swapchain = swapchain,
|
.swapchain = swapchain,
|
||||||
.graphics_pipeline = graphics_pipeline,
|
.graphics_pipeline = graphics_pipeline,
|
||||||
|
.terrain_pipeline = terrain_pipeline,
|
||||||
.current_frame = 0,
|
.current_frame = 0,
|
||||||
.transforms = transforms,
|
.transforms = transforms,
|
||||||
.previous_time = try std.time.Instant.now(),
|
.previous_time = try std.time.Instant.now(),
|
||||||
.mesh = mesh,
|
.mesh = mesh,
|
||||||
.current_image = undefined,
|
.current_image = undefined,
|
||||||
|
.terrain_vertex = terrain_vertex,
|
||||||
|
.terrain_index = terrain_index,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,11 +147,19 @@ pub fn begin(self: *Self) !void {
|
||||||
try self.device.resetCommand(self.current_frame);
|
try self.device.resetCommand(self.current_frame);
|
||||||
try self.device.beginCommand(self.current_frame);
|
try self.device.beginCommand(self.current_frame);
|
||||||
self.render_pass.begin(self.swapchain, self.device, image, self.current_frame);
|
self.render_pass.begin(self.swapchain, self.device, image, self.current_frame);
|
||||||
|
self.current_image = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn beginGraphics(self: *Self) !void {
|
||||||
self.graphics_pipeline.bind(self.device, self.current_frame);
|
self.graphics_pipeline.bind(self.device, self.current_frame);
|
||||||
self.device.bindVertexBuffer(self.graphics_pipeline.vertex_buffer, self.current_frame);
|
self.device.bindVertexBuffer(self.graphics_pipeline.vertex_buffer, self.current_frame);
|
||||||
self.device.bindIndexBuffer(self.graphics_pipeline.index_buffer, self.current_frame);
|
self.device.bindIndexBuffer(self.graphics_pipeline.index_buffer, self.current_frame);
|
||||||
self.device.bindDescriptorSets(self.graphics_pipeline, self.current_frame, 0);
|
self.device.bindDescriptorSets(self.graphics_pipeline, self.current_frame, 0);
|
||||||
self.current_image = image;
|
}
|
||||||
|
|
||||||
|
pub fn beginTerrain(self: *Self) !void {
|
||||||
|
self.terrain_pipeline.bind(self.device, self.current_frame);
|
||||||
|
self.device.bindTerrainSets(self.terrain_pipeline, self.current_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setLightCount(self: *Self, count: u32) void {
|
pub fn setLightCount(self: *Self, count: u32) void {
|
||||||
|
|
@ -146,5 +180,3 @@ pub fn end(self: *Self) !void {
|
||||||
|
|
||||||
self.device.waitIdle();
|
self.device.waitIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
434
src/rendering/TerrainPipeline.zig
Normal file
434
src/rendering/TerrainPipeline.zig
Normal file
|
|
@ -0,0 +1,434 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const Mesh = @import("Mesh.zig");
|
||||||
|
const Camera = @import("Camera.zig");
|
||||||
|
const vk = @import("vulkan.zig");
|
||||||
|
const Texture = vk.Texture;
|
||||||
|
const c = vk.c;
|
||||||
|
const math = @import("math");
|
||||||
|
const gltf = @import("gltf.zig");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const rendering = @import("rendering.zig");
|
||||||
|
const lights = rendering.lights;
|
||||||
|
|
||||||
|
const max_point_lights = 1024;
|
||||||
|
|
||||||
|
layout: c.VkPipelineLayout,
|
||||||
|
handle: c.VkPipeline,
|
||||||
|
//vertex_buffer: vk.Buffer,
|
||||||
|
//index_buffer: vk.Buffer,
|
||||||
|
texture_set_layout: c.VkDescriptorSetLayout,
|
||||||
|
descriptor_pool: c.VkDescriptorPool,
|
||||||
|
descriptor_set: c.VkDescriptorSet,
|
||||||
|
descriptor_set_layout: c.VkDescriptorSetLayout,
|
||||||
|
heightmap_sampler: vk.Sampler,
|
||||||
|
heightmap: c.VkDescriptorSet,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
graphics_pipeline: vk.GraphicsPipeline,
|
||||||
|
vertex_shader: c.VkShaderModule,
|
||||||
|
fragment_shader: c.VkShaderModule) !Self {
|
||||||
|
|
||||||
|
const device = graphics_pipeline.device;
|
||||||
|
const swapchain = graphics_pipeline.swapchain;
|
||||||
|
const render_pass = graphics_pipeline.render_pass;
|
||||||
|
|
||||||
|
const vertex_shader_stage_info: c.VkPipelineShaderStageCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
|
.stage = c.VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
.module = vertex_shader,
|
||||||
|
.pName = "main",
|
||||||
|
};
|
||||||
|
|
||||||
|
const fragment_shader_stage_info: c.VkPipelineShaderStageCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
|
.stage = c.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
.module = fragment_shader,
|
||||||
|
.pName = "main",
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: shouldn't this be closer to usage?
|
||||||
|
const shader_stage_infos: []const c.VkPipelineShaderStageCreateInfo = &.{ vertex_shader_stage_info, fragment_shader_stage_info };
|
||||||
|
|
||||||
|
const vertex_attributes: []const c.VkVertexInputAttributeDescription = Mesh.Vertex.attributeDescriptions();
|
||||||
|
const vertex_bindings: []const c.VkVertexInputBindingDescription = &.{Mesh.Vertex.bindingDescription()};
|
||||||
|
|
||||||
|
const vertex_input_info: c.VkPipelineVertexInputStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||||
|
.vertexBindingDescriptionCount = 1,
|
||||||
|
.pVertexBindingDescriptions = vertex_bindings.ptr,
|
||||||
|
.vertexAttributeDescriptionCount = 3,
|
||||||
|
.pVertexAttributeDescriptions = vertex_attributes.ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
const input_assembly_info: c.VkPipelineInputAssemblyStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||||
|
.topology = c.VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||||
|
.primitiveRestartEnable = c.VK_FALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewport: c.VkViewport = .{
|
||||||
|
.x = 0.0,
|
||||||
|
.y = 0.0,
|
||||||
|
.width = @floatFromInt(swapchain.extent.width),
|
||||||
|
.height = @floatFromInt(swapchain.extent.height),
|
||||||
|
.minDepth = 0.0,
|
||||||
|
.maxDepth = 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const scissor: c.VkRect2D = .{
|
||||||
|
.offset = .{
|
||||||
|
.x = 0.0,
|
||||||
|
.y = 0.0,
|
||||||
|
},
|
||||||
|
.extent = swapchain.extent,
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewport_state_info: c.VkPipelineViewportStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||||
|
.viewportCount = 1,
|
||||||
|
.pViewports = &viewport,
|
||||||
|
.scissorCount = 1,
|
||||||
|
.pScissors = &scissor,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rasterizer_info: c.VkPipelineRasterizationStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
|
.depthClampEnable = c.VK_FALSE,
|
||||||
|
.rasterizerDiscardEnable = c.VK_FALSE,
|
||||||
|
.polygonMode = c.VK_POLYGON_MODE_FILL,
|
||||||
|
.lineWidth = 1.0,
|
||||||
|
.cullMode = c.VK_CULL_MODE_BACK_BIT,
|
||||||
|
.frontFace = c.VK_FRONT_FACE_CLOCKWISE,
|
||||||
|
.depthBiasEnable = c.VK_FALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const multisampling_info: c.VkPipelineMultisampleStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
|
.sampleShadingEnable = c.VK_FALSE,
|
||||||
|
.rasterizationSamples = device.msaa_samples,
|
||||||
|
};
|
||||||
|
|
||||||
|
const color_blend_attachment: c.VkPipelineColorBlendAttachmentState = .{
|
||||||
|
.colorWriteMask = c.VK_COLOR_COMPONENT_R_BIT | c.VK_COLOR_COMPONENT_G_BIT | c.VK_COLOR_COMPONENT_B_BIT | c.VK_COLOR_COMPONENT_A_BIT,
|
||||||
|
.blendEnable = c.VK_TRUE,
|
||||||
|
.srcColorBlendFactor = c.VK_BLEND_FACTOR_SRC_ALPHA,
|
||||||
|
.dstColorBlendFactor = c.VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||||
|
.colorBlendOp = c.VK_BLEND_OP_ADD,
|
||||||
|
.srcAlphaBlendFactor = c.VK_BLEND_FACTOR_ONE,
|
||||||
|
.dstAlphaBlendFactor = c.VK_BLEND_FACTOR_ZERO,
|
||||||
|
.alphaBlendOp = c.VK_BLEND_OP_ADD,
|
||||||
|
};
|
||||||
|
|
||||||
|
const color_blend_info: c.VkPipelineColorBlendStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
|
.logicOpEnable = c.VK_FALSE,
|
||||||
|
.logicOp = c.VK_LOGIC_OP_COPY,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = &color_blend_attachment,
|
||||||
|
.blendConstants = .{ 0.0, 0.0, 0.0, 0.0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const projection_binding = c.VkDescriptorSetLayoutBinding{
|
||||||
|
.binding = 0,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const view_binding = c.VkDescriptorSetLayoutBinding{
|
||||||
|
.binding = 1,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const directional_light_binding = c.VkDescriptorSetLayoutBinding{
|
||||||
|
.binding = 2,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const point_lights_binding = c.VkDescriptorSetLayoutBinding{
|
||||||
|
.binding = 5,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const view_pos_binding = c.VkDescriptorSetLayoutBinding{
|
||||||
|
.binding = 3,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const heightmap_sampler_binding = c.VkDescriptorSetLayoutBinding{
|
||||||
|
.binding = 0,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_VERTEX_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};
|
||||||
|
|
||||||
|
var descriptor_set_layout: c.VkDescriptorSetLayout = undefined;
|
||||||
|
var texture_descriptor_set_layout: c.VkDescriptorSetLayout = undefined;
|
||||||
|
|
||||||
|
const descriptor_set_layout_info = c.VkDescriptorSetLayoutCreateInfo{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.bindingCount = 5,
|
||||||
|
.pBindings = bindings[0..].ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
const texture_descriptor_set_layout_info = c.VkDescriptorSetLayoutCreateInfo{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.bindingCount = 1,
|
||||||
|
.pBindings = texture_bindings[0..].ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
try vk.mapError(c.vkCreateDescriptorSetLayout(device.handle, &descriptor_set_layout_info, null, &descriptor_set_layout));
|
||||||
|
try vk.mapError(c.vkCreateDescriptorSetLayout(device.handle, &texture_descriptor_set_layout_info, null, &texture_descriptor_set_layout));
|
||||||
|
|
||||||
|
var set_layouts = [_]c.VkDescriptorSetLayout{descriptor_set_layout, texture_descriptor_set_layout};
|
||||||
|
|
||||||
|
const lights_range: c.VkPushConstantRange = .{
|
||||||
|
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
|
.offset = 0,
|
||||||
|
.size = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
const range: [1]c.VkPushConstantRange = .{lights_range};
|
||||||
|
|
||||||
|
const layout_info: c.VkPipelineLayoutCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.setLayoutCount = 2,
|
||||||
|
.pSetLayouts = set_layouts[0..].ptr,
|
||||||
|
.pushConstantRangeCount = 1,
|
||||||
|
.pPushConstantRanges = range[0..].ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
var layout: c.VkPipelineLayout = undefined;
|
||||||
|
|
||||||
|
try vk.mapError(c.vkCreatePipelineLayout(device.handle, &layout_info, null, @ptrCast(&layout)));
|
||||||
|
|
||||||
|
const depth_stencil: c.VkPipelineDepthStencilStateCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
|
.depthTestEnable = c.VK_TRUE,
|
||||||
|
.depthWriteEnable = c.VK_TRUE,
|
||||||
|
.depthCompareOp = c.VK_COMPARE_OP_LESS,
|
||||||
|
.depthBoundsTestEnable = c.VK_FALSE,
|
||||||
|
.minDepthBounds = 0.0,
|
||||||
|
.maxDepthBounds = 1.0,
|
||||||
|
.stencilTestEnable = c.VK_FALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const pipeline_info: c.VkGraphicsPipelineCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
|
.stageCount = 2,
|
||||||
|
.pStages = shader_stage_infos.ptr,
|
||||||
|
.pVertexInputState = &vertex_input_info,
|
||||||
|
.pInputAssemblyState = &input_assembly_info,
|
||||||
|
.pViewportState = &viewport_state_info,
|
||||||
|
.pRasterizationState = &rasterizer_info,
|
||||||
|
.pMultisampleState = &multisampling_info,
|
||||||
|
.pDepthStencilState = &depth_stencil,
|
||||||
|
.pColorBlendState = &color_blend_info,
|
||||||
|
.pDynamicState = null,
|
||||||
|
.layout = layout,
|
||||||
|
.renderPass = render_pass.handle,
|
||||||
|
.subpass = 0,
|
||||||
|
.basePipelineHandle = null,
|
||||||
|
.basePipelineIndex = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
var pipeline: c.VkPipeline = undefined;
|
||||||
|
|
||||||
|
try vk.mapError(c.vkCreateGraphicsPipelines(device.handle, null, 1, &pipeline_info, null, @ptrCast(&pipeline)));
|
||||||
|
|
||||||
|
const size = c.VkDescriptorPoolSize{
|
||||||
|
.type = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
const sampler_size = c.VkDescriptorPoolSize{
|
||||||
|
.type = c.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const sizes = [_]c.VkDescriptorPoolSize {size, sampler_size};
|
||||||
|
|
||||||
|
const descriptor_pool_info = c.VkDescriptorPoolCreateInfo{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
|
.maxSets = 2,
|
||||||
|
.poolSizeCount = 2,
|
||||||
|
.pPoolSizes = sizes[0..].ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
var descriptor_pool: c.VkDescriptorPool = undefined;
|
||||||
|
|
||||||
|
try vk.mapError(c.vkCreateDescriptorPool(device.handle, &descriptor_pool_info, null, &descriptor_pool));
|
||||||
|
|
||||||
|
const descriptor_allocate_info = c.VkDescriptorSetAllocateInfo{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
|
.descriptorPool = descriptor_pool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = set_layouts[0..].ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
var descriptor_set: c.VkDescriptorSet = undefined;
|
||||||
|
|
||||||
|
try vk.mapError(c.vkAllocateDescriptorSets(device.handle, &descriptor_allocate_info, &descriptor_set));
|
||||||
|
|
||||||
|
const descriptor_buffer_info = c.VkDescriptorBufferInfo{
|
||||||
|
.buffer = graphics_pipeline.projection_buffer.handle,
|
||||||
|
.offset = 0,
|
||||||
|
.range = graphics_pipeline.projection_buffer.size,
|
||||||
|
};
|
||||||
|
|
||||||
|
const write_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_UNIFORM_BUFFER,
|
||||||
|
.pBufferInfo = &descriptor_buffer_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
c.vkUpdateDescriptorSets(device.handle, 1, &write_descriptor_set, 0, null);
|
||||||
|
|
||||||
|
const view_descriptor_buffer_info = c.VkDescriptorBufferInfo{
|
||||||
|
.buffer = graphics_pipeline.view_buffer.handle,
|
||||||
|
.offset = 0,
|
||||||
|
.range = graphics_pipeline.view_buffer.size,
|
||||||
|
};
|
||||||
|
|
||||||
|
const write_view_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_UNIFORM_BUFFER,
|
||||||
|
.pBufferInfo = &view_descriptor_buffer_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
c.vkUpdateDescriptorSets(device.handle, 1, &write_view_descriptor_set, 0, null);
|
||||||
|
|
||||||
|
const directional_light_descriptor_buffer_info = c.VkDescriptorBufferInfo{
|
||||||
|
.buffer = graphics_pipeline.directional_light_buffer.handle,
|
||||||
|
.offset = 0,
|
||||||
|
.range = graphics_pipeline.directional_light_buffer.size,
|
||||||
|
};
|
||||||
|
|
||||||
|
const write_directional_light_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_UNIFORM_BUFFER,
|
||||||
|
.pBufferInfo = &directional_light_descriptor_buffer_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
c.vkUpdateDescriptorSets(device.handle, 1, &write_directional_light_descriptor_set, 0, null);
|
||||||
|
|
||||||
|
var point_lights_descriptor_buffer_info: c.VkDescriptorBufferInfo = undefined;
|
||||||
|
point_lights_descriptor_buffer_info.buffer = graphics_pipeline.point_lights_buffer.handle;
|
||||||
|
point_lights_descriptor_buffer_info.offset = 0;
|
||||||
|
point_lights_descriptor_buffer_info.range = @sizeOf(lights.PointLight) * max_point_lights;
|
||||||
|
|
||||||
|
const write_point_lights_descriptor_set = c.VkWriteDescriptorSet{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.dstSet = descriptor_set,
|
||||||
|
.dstBinding = 5,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.pBufferInfo = @ptrCast(&point_lights_descriptor_buffer_info),
|
||||||
|
};
|
||||||
|
|
||||||
|
c.vkUpdateDescriptorSets(device.handle, 1, &write_point_lights_descriptor_set, 0, null);
|
||||||
|
|
||||||
|
const view_pos_descriptor_buffer_info = c.VkDescriptorBufferInfo{
|
||||||
|
.buffer = graphics_pipeline.view_pos_buffer.handle,
|
||||||
|
.offset = 0,
|
||||||
|
.range = graphics_pipeline.view_pos_buffer.size,
|
||||||
|
};
|
||||||
|
|
||||||
|
const write_view_pos_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_UNIFORM_BUFFER,
|
||||||
|
.pBufferInfo = &view_pos_descriptor_buffer_info,
|
||||||
|
};
|
||||||
|
|
||||||
|
c.vkUpdateDescriptorSets(device.handle, 1, &write_view_pos_descriptor_set, 0, null);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.layout = layout,
|
||||||
|
.handle = pipeline,
|
||||||
|
.texture_set_layout = texture_descriptor_set_layout,
|
||||||
|
.descriptor_pool = descriptor_pool,
|
||||||
|
.descriptor_set = descriptor_set,
|
||||||
|
.descriptor_set_layout = descriptor_set_layout,
|
||||||
|
.heightmap_sampler = try vk.Sampler.init(device),
|
||||||
|
.heightmap = undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setHeightmap(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,
|
||||||
|
.descriptorPool = self.descriptor_pool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = set_layouts[0..].ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
var descriptor_set: c.VkDescriptorSet = undefined;
|
||||||
|
try vk.mapError(c.vkAllocateDescriptorSets(device.handle, &descriptor_allocate_info, &descriptor_set));
|
||||||
|
|
||||||
|
const texture_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{
|
||||||
|
.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,
|
||||||
|
};
|
||||||
|
|
||||||
|
c.vkUpdateDescriptorSets(device.handle, 1, &write_texture_descriptor_set, 0, null);
|
||||||
|
|
||||||
|
self.heightmap = descriptor_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind(self: Self, device: vk.Device, frame: usize) void {
|
||||||
|
std.debug.assert(frame < 2);
|
||||||
|
c.vkCmdBindPipeline(device.command_buffers[frame], c.VK_PIPELINE_BIND_POINT_GRAPHICS, self.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: Self, device: vk.Device) void {
|
||||||
|
self.textures.deinit();
|
||||||
|
self.diffuse_sampler.deinit(device);
|
||||||
|
self.specular_sampler.deinit(device);
|
||||||
|
self.projection_buffer.deinit(device.handle);
|
||||||
|
c.vkDestroyDescriptorSetLayout(device.handle, self.descriptor_set_layout, null);
|
||||||
|
c.vkDestroyDescriptorPool(device.handle, self.descriptor_pool, null);
|
||||||
|
c.vkDestroyPipeline(device.handle, self.handle, null);
|
||||||
|
c.vkDestroyPipelineLayout(device.handle, self.layout, null);
|
||||||
|
}
|
||||||
|
|
@ -9,18 +9,11 @@ image: c.VkImage,
|
||||||
image_memory: c.VkDeviceMemory,
|
image_memory: c.VkDeviceMemory,
|
||||||
image_view: c.VkImageView,
|
image_view: c.VkImageView,
|
||||||
|
|
||||||
pub fn init(path: [:0]const u8, device: anytype) !Texture {
|
pub fn fromBytes(data: []u8, device: anytype, width: u64, height: u64) !Texture {
|
||||||
var width: i32 = 0;
|
|
||||||
var height: i32 = 0;
|
|
||||||
var channels: i32 = 0;
|
|
||||||
|
|
||||||
const pixels = stb.stbi_load(path, &width, &height, &channels, stb.STBI_rgb_alpha);
|
|
||||||
defer stb.stbi_image_free(pixels);
|
|
||||||
|
|
||||||
const size: c.VkDeviceSize = @as(u64, @intCast(width)) * @as(u64, @intCast(height)) * 4;
|
const size: c.VkDeviceSize = @as(u64, @intCast(width)) * @as(u64, @intCast(height)) * 4;
|
||||||
const image_buffer = try device.initBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, size);
|
const image_buffer = try device.initBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, size);
|
||||||
|
|
||||||
const pixel_bytes: [*]u8 = @ptrCast(pixels);
|
const pixel_bytes: [*]u8 = @ptrCast(data);
|
||||||
var image_data: [*c]u8 = undefined;
|
var image_data: [*c]u8 = undefined;
|
||||||
|
|
||||||
try vk.mapError(c.vkMapMemory(
|
try vk.mapError(c.vkMapMemory(
|
||||||
|
|
@ -89,6 +82,17 @@ pub fn init(path: [:0]const u8, device: anytype) !Texture {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init(path: [:0]const u8, device: anytype) !Texture {
|
||||||
|
var width: i32 = 0;
|
||||||
|
var height: i32 = 0;
|
||||||
|
var channels: i32 = 0;
|
||||||
|
|
||||||
|
const pixels = stb.stbi_load(path, &width, &height, &channels, stb.STBI_rgb_alpha);
|
||||||
|
defer stb.stbi_image_free(pixels);
|
||||||
|
|
||||||
|
return try Texture.fromBytes(pixels[0..(@as(usize, @intCast(width*height)))], device, @intCast(width), @intCast(height));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: Texture, device: vk.Device) void {
|
pub fn deinit(self: Texture, device: vk.Device) void {
|
||||||
c.vkDestroyImageView(device.handle, self.image_view, null);
|
c.vkDestroyImageView(device.handle, self.image_view, null);
|
||||||
c.vkDestroyImage(device.handle, self.image, null);
|
c.vkDestroyImage(device.handle, self.image, null);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub const Texture = @import("Texture.zig");
|
pub const Texture = @import("Texture.zig");
|
||||||
pub const GraphicsPipeline = @import("GraphicsPipeline.zig");
|
pub const GraphicsPipeline = @import("GraphicsPipeline.zig");
|
||||||
|
pub const TerrainPipeline = @import("TerrainPipeline.zig");
|
||||||
pub const Device = @import("Device.zig");
|
pub const Device = @import("Device.zig");
|
||||||
pub const Swapchain = @import("Swapchain.zig");
|
pub const Swapchain = @import("Swapchain.zig");
|
||||||
pub const PhysicalDevice = @import("PhysicalDevice.zig");
|
pub const PhysicalDevice = @import("PhysicalDevice.zig");
|
||||||
|
|
@ -112,8 +113,8 @@ pub const Sampler = struct {
|
||||||
|
|
||||||
const create_info: c.VkSamplerCreateInfo = .{
|
const create_info: c.VkSamplerCreateInfo = .{
|
||||||
.sType = c.VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
.sType = c.VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||||
.magFilter = c.VK_FILTER_LINEAR,
|
.magFilter = c.VK_FILTER_NEAREST,
|
||||||
.minFilter = c.VK_FILTER_LINEAR,
|
.minFilter = c.VK_FILTER_NEAREST,
|
||||||
.addressModeU = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
.addressModeU = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||||
.addressModeV = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
.addressModeV = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||||
.addressModeW = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
.addressModeW = c.VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,10 @@ pub fn render(pool: *ecs.Pool) anyerror!void {
|
||||||
|
|
||||||
renderer.setLightCount(2);
|
renderer.setLightCount(2);
|
||||||
|
|
||||||
|
try renderer.beginTerrain();
|
||||||
|
renderer.device.drawTerrain(@as(u32, @intCast(renderer.terrain_index.size/@sizeOf(u32))), renderer.current_frame, renderer.terrain_vertex, renderer.terrain_index);
|
||||||
|
|
||||||
|
try renderer.beginGraphics();
|
||||||
for (renderer.transforms.items, 0..) |transform, i| {
|
for (renderer.transforms.items, 0..) |transform, i| {
|
||||||
transform_memory[i] = transform;
|
transform_memory[i] = transform;
|
||||||
renderer.setTransform(@intCast(i));
|
renderer.setTransform(@intCast(i));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue