Sketchy skybox
This commit is contained in:
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@@ -8,5 +8,11 @@
|
|||||||
"program": "${workspaceFolder}/zig-out/bin/voxel-game",
|
"program": "${workspaceFolder}/zig-out/bin/voxel-game",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Attach",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "attach",
|
||||||
|
"program": "${workspaceFolder}/zig-out/bin/voxel-game",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
29
assets/shaders/skybox.frag
Normal file
29
assets/shaders/skybox.frag
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#version 460
|
||||||
|
|
||||||
|
in Varyings {
|
||||||
|
layout(location = 0) vec3 texCoord;
|
||||||
|
} var;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 1) uniform sampler _Sampler;
|
||||||
|
layout(set = 0, binding = 2) uniform textureCube _Texture;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
vec3 toneMapAcesNarkowicz(vec3 color) {
|
||||||
|
const float A = 2.51;
|
||||||
|
const float B = 0.03;
|
||||||
|
const float C = 2.43;
|
||||||
|
const float D = 0.59;
|
||||||
|
const float E = 0.14;
|
||||||
|
return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 texel = texture(samplerCube(_Texture, _Sampler), var.texCoord);
|
||||||
|
vec3 outgoingRadiance = texel.rgb;
|
||||||
|
|
||||||
|
vec3 toneMappedLinearColor = toneMapAcesNarkowicz(outgoingRadiance);
|
||||||
|
vec3 toneMappedSrgbColor = pow(toneMappedLinearColor, vec3(1.0 / 2.2));
|
||||||
|
|
||||||
|
fragColor = vec4(toneMappedSrgbColor, 1.0);
|
||||||
|
}
|
||||||
22
assets/shaders/skybox.vert
Normal file
22
assets/shaders/skybox.vert
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#version 460
|
||||||
|
#extension GL_EXT_scalar_block_layout : require
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 directionWS;
|
||||||
|
|
||||||
|
out Varyings {
|
||||||
|
layout(location = 0) vec3 texCoord;
|
||||||
|
} var;
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0, scalar) uniform GlobalUniforms {
|
||||||
|
mat4 matrixWStoVS;
|
||||||
|
mat4 matrixVStoCS;
|
||||||
|
vec3 ambientLight;
|
||||||
|
} _Global;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 directionVS = (_Global.matrixWStoVS * vec4(directionWS, 0.0)).xyz;
|
||||||
|
vec4 directionCS = _Global.matrixVStoCS * vec4(directionVS, 0.0);
|
||||||
|
|
||||||
|
gl_Position = vec4(directionCS.xy, 0.0, directionCS.w);
|
||||||
|
var.texCoord = -directionWS;
|
||||||
|
}
|
||||||
@@ -3,3 +3,5 @@
|
|||||||
glslc --target-env=vulkan1.2 assets/shaders/equirect_to_cube.comp -o src/shaders/equirect_to_cube_comp.spv
|
glslc --target-env=vulkan1.2 assets/shaders/equirect_to_cube.comp -o src/shaders/equirect_to_cube_comp.spv
|
||||||
glslc --target-env=vulkan1.2 assets/shaders/main.frag -o src/shaders/main_frag.spv
|
glslc --target-env=vulkan1.2 assets/shaders/main.frag -o src/shaders/main_frag.spv
|
||||||
glslc --target-env=vulkan1.2 assets/shaders/main.vert -o src/shaders/main_vert.spv
|
glslc --target-env=vulkan1.2 assets/shaders/main.vert -o src/shaders/main_vert.spv
|
||||||
|
glslc --target-env=vulkan1.2 assets/shaders/skybox.frag -o src/shaders/skybox_frag.spv
|
||||||
|
glslc --target-env=vulkan1.2 assets/shaders/skybox.vert -o src/shaders/skybox_vert.spv
|
||||||
|
|||||||
@@ -618,7 +618,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
|||||||
.elements = directional_lights_data,
|
.elements = directional_lights_data,
|
||||||
});
|
});
|
||||||
|
|
||||||
var skybox = try Skybox.load("skybox.hdr", engine, 512, allocator);
|
var skybox = try Skybox.load("skybox.hdr", engine, 512, global_uniforms.buffer, swapchain.render_pass, allocator);
|
||||||
errdefer skybox.deinit(engine);
|
errdefer skybox.deinit(engine);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
@@ -849,6 +849,9 @@ fn render(self: *Game) !void {
|
|||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
chunk.draw(self.pipeline_layout, command_buffer);
|
chunk.draw(self.pipeline_layout, command_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try self.skybox.bind(command_buffer, extent);
|
||||||
|
self.skybox.draw(command_buffer);
|
||||||
}
|
}
|
||||||
try command_buffer.endCommandBuffer();
|
try command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,24 @@ const vk = @import("vulkan");
|
|||||||
|
|
||||||
const CommandBuffer = @import("CommandBuffer.zig");
|
const CommandBuffer = @import("CommandBuffer.zig");
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
|
const GenericBuffer = @import("GenericBuffer.zig").GenericBuffer;
|
||||||
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
|
|
||||||
image: vk.Image,
|
image: vk.Image,
|
||||||
image_view: vk.ImageView,
|
image_view: vk.ImageView,
|
||||||
device_memory: vk.DeviceMemory,
|
device_memory: vk.DeviceMemory,
|
||||||
|
|
||||||
pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocator: std.mem.Allocator) !Skybox {
|
vertex_buffer: GenericBuffer(void, [3]f32),
|
||||||
|
index_buffer: shaders.IndexBuffer,
|
||||||
|
sampler: vk.Sampler,
|
||||||
|
|
||||||
|
descriptor_set_layout: vk.DescriptorSetLayout,
|
||||||
|
descriptor_pool: vk.DescriptorPool,
|
||||||
|
descriptor_set: vk.DescriptorSet,
|
||||||
|
pipeline_layout: vk.PipelineLayout,
|
||||||
|
pipeline: vk.Pipeline,
|
||||||
|
|
||||||
|
pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, global_uniforms_buffer: vk.Buffer, render_pass: vk.RenderPass, temp_allocator: std.mem.Allocator) !Skybox {
|
||||||
std.log.debug("Loading skybox \"{s}\"...", .{filename});
|
std.log.debug("Loading skybox \"{s}\"...", .{filename});
|
||||||
|
|
||||||
// --- LOAD IMAGE FROM MEMORY ----------------------------------------------
|
// --- LOAD IMAGE FROM MEMORY ----------------------------------------------
|
||||||
@@ -29,7 +41,33 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
defer img.deinit();
|
defer img.deinit();
|
||||||
std.debug.assert(img.num_components == 4);
|
std.debug.assert(img.num_components == 4);
|
||||||
|
|
||||||
// --- CREATE EQUIRECTANGULAR IMAGE AND COPY INTO IT -----------------------
|
// --- SYNCHRONIZATION PRIMITIVES ------------------------------------------
|
||||||
|
|
||||||
|
const semaphore_transfer_transition = try engine.createSemaphore();
|
||||||
|
defer engine.destroySemaphore(semaphore_transfer_transition);
|
||||||
|
|
||||||
|
const semaphore_transition_compute = try engine.createSemaphore();
|
||||||
|
defer engine.destroySemaphore(semaphore_transition_compute);
|
||||||
|
|
||||||
|
const semaphore_compute_transition = try engine.createSemaphore();
|
||||||
|
defer engine.destroySemaphore(semaphore_compute_transition);
|
||||||
|
|
||||||
|
const fence = try engine.createFence(.{});
|
||||||
|
defer engine.destroyFence(fence);
|
||||||
|
|
||||||
|
// --- LOAD IMAGE INTO STAGING BUFFER --------------------------------------
|
||||||
|
|
||||||
|
var staging_buffer = try StagingBuffer.init(engine, .{
|
||||||
|
.capacity = @intCast(img.data.len),
|
||||||
|
.target_queue = .compute,
|
||||||
|
});
|
||||||
|
defer staging_buffer.deinit(engine);
|
||||||
|
|
||||||
|
const staging_memory = try staging_buffer.map(engine);
|
||||||
|
@memcpy(staging_memory, img.data);
|
||||||
|
staging_buffer.unmap(engine);
|
||||||
|
|
||||||
|
// --- CREATE EQUIRECTANGULAR IMAGE ----------------------------------------
|
||||||
|
|
||||||
const equirect_image = try engine.createImage(.{
|
const equirect_image = try engine.createImage(.{
|
||||||
.image_type = .@"2d",
|
.image_type = .@"2d",
|
||||||
@@ -42,23 +80,21 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
.mip_levels = 1,
|
.mip_levels = 1,
|
||||||
.array_layers = 1,
|
.array_layers = 1,
|
||||||
.samples = .{ .@"1_bit" = true },
|
.samples = .{ .@"1_bit" = true },
|
||||||
.tiling = .linear,
|
.tiling = .optimal,
|
||||||
.usage = .{
|
.usage = .{
|
||||||
.transfer_dst_bit = true,
|
.transfer_dst_bit = true,
|
||||||
.sampled_bit = true,
|
.sampled_bit = true,
|
||||||
},
|
},
|
||||||
.queue_family_indices = &.{
|
.queue_family_indices = &.{
|
||||||
engine.compute_queue.allocation.family,
|
engine.compute_queue.allocation.family,
|
||||||
|
engine.transfer_queue.allocation.family,
|
||||||
},
|
},
|
||||||
.initial_layout = .preinitialized,
|
.initial_layout = .undefined,
|
||||||
});
|
});
|
||||||
defer engine.destroyImage(equirect_image);
|
defer engine.destroyImage(equirect_image);
|
||||||
|
|
||||||
const equirect_memory_requirements = engine.getImageMemoryRequirements(equirect_image);
|
const equirect_memory_requirements = engine.getImageMemoryRequirements(equirect_image);
|
||||||
const equirect_device_memory = try engine.allocate(equirect_memory_requirements, .{
|
const equirect_device_memory = try engine.allocate(equirect_memory_requirements, .{ .device_local_bit = true });
|
||||||
.host_visible_bit = true,
|
|
||||||
.host_coherent_bit = true,
|
|
||||||
});
|
|
||||||
defer engine.freeMemory(equirect_device_memory);
|
defer engine.freeMemory(equirect_device_memory);
|
||||||
|
|
||||||
try engine.bindImageMemory(equirect_image, equirect_device_memory, 0);
|
try engine.bindImageMemory(equirect_image, equirect_device_memory, 0);
|
||||||
@@ -77,9 +113,94 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
});
|
});
|
||||||
defer engine.destroyImageView(equirect_image_view);
|
defer engine.destroyImageView(equirect_image_view);
|
||||||
|
|
||||||
const data = try engine.mapMemory(equirect_device_memory, 0, equirect_memory_requirements.size, .{});
|
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -------------------------
|
||||||
@memcpy(data, img.data);
|
|
||||||
engine.unmapMemory(equirect_device_memory);
|
var transfer_command_buffer = try CommandBuffer.init(engine, .transfer, .transient);
|
||||||
|
defer transfer_command_buffer.deinit(engine);
|
||||||
|
|
||||||
|
try transfer_command_buffer.beginCommandBuffer();
|
||||||
|
transfer_command_buffer.pipelineBarrier(.{
|
||||||
|
.src_stage_mask = .{ .top_of_pipe_bit = true },
|
||||||
|
.dst_stage_mask = .{ .transfer_bit = true },
|
||||||
|
.image_memory_barriers = &.{
|
||||||
|
.{
|
||||||
|
.src_access_mask = .{},
|
||||||
|
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.old_layout = .undefined,
|
||||||
|
.new_layout = .transfer_dst_optimal,
|
||||||
|
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
|
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = equirect_image,
|
||||||
|
.subresource_range = .{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.base_mip_level = 0,
|
||||||
|
.level_count = 1,
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
transfer_command_buffer.copyBufferToImage(
|
||||||
|
staging_buffer.buffer,
|
||||||
|
equirect_image,
|
||||||
|
.transfer_dst_optimal,
|
||||||
|
&.{
|
||||||
|
.{
|
||||||
|
.buffer_offset = 0,
|
||||||
|
.buffer_row_length = img.width,
|
||||||
|
.buffer_image_height = img.height,
|
||||||
|
.image_subresource = .{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.mip_level = 0,
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
},
|
||||||
|
.image_offset = .{ .x = 0, .y = 0, .z = 0 },
|
||||||
|
.image_extent = .{ .width = img.width, .height = img.height, .depth = 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
try transfer_command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
|
try transfer_command_buffer.submit(engine, .{
|
||||||
|
.signal_semaphores = &.{semaphore_transfer_transition},
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- TRANSITION TO SHADER_READ_ONLY_OPTIMAL ------------------------------
|
||||||
|
|
||||||
|
var transition1_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
|
||||||
|
defer transition1_command_buffer.deinit(engine);
|
||||||
|
|
||||||
|
try transition1_command_buffer.beginCommandBuffer();
|
||||||
|
transition1_command_buffer.pipelineBarrier(.{
|
||||||
|
.src_stage_mask = .{ .transfer_bit = true },
|
||||||
|
.dst_stage_mask = .{ .compute_shader_bit = true },
|
||||||
|
.image_memory_barriers = &.{
|
||||||
|
.{
|
||||||
|
.src_access_mask = .{ .transfer_write_bit = true },
|
||||||
|
.dst_access_mask = .{ .shader_read_bit = true },
|
||||||
|
.old_layout = .transfer_dst_optimal,
|
||||||
|
.new_layout = .shader_read_only_optimal,
|
||||||
|
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
|
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = equirect_image,
|
||||||
|
.subresource_range = .{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.base_mip_level = 0,
|
||||||
|
.level_count = 1,
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
try transition1_command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
|
try transition1_command_buffer.submit(engine, .{
|
||||||
|
.wait_semaphores = &.{.{ .semaphore = semaphore_transfer_transition }},
|
||||||
|
.signal_semaphores = &.{semaphore_transition_compute},
|
||||||
|
});
|
||||||
|
|
||||||
// --- CREATE CUBEMAP IMAGE ------------------------------------------------
|
// --- CREATE CUBEMAP IMAGE ------------------------------------------------
|
||||||
|
|
||||||
@@ -147,9 +268,9 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
.border_color = .float_transparent_black,
|
.border_color = .float_transparent_black,
|
||||||
.unnormalized_coordinates = .false,
|
.unnormalized_coordinates = .false,
|
||||||
});
|
});
|
||||||
defer engine.destroySampler(sampler);
|
errdefer engine.destroySampler(sampler);
|
||||||
|
|
||||||
const descriptor_set_layout = try engine.createDescriptorSetLayout(.{
|
const compute_descriptor_set_layout = try engine.createDescriptorSetLayout(.{
|
||||||
.bindings = &.{
|
.bindings = &.{
|
||||||
.{
|
.{
|
||||||
.binding = 0,
|
.binding = 0,
|
||||||
@@ -172,17 +293,17 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
defer engine.destroyDescriptorSetLayout(descriptor_set_layout);
|
defer engine.destroyDescriptorSetLayout(compute_descriptor_set_layout);
|
||||||
|
|
||||||
const pipeline_layout = try engine.createPipelineLayout(.{
|
const compute_pipeline_layout = try engine.createPipelineLayout(.{
|
||||||
.set_layouts = &.{descriptor_set_layout},
|
.set_layouts = &.{compute_descriptor_set_layout},
|
||||||
});
|
});
|
||||||
defer engine.destroyPipelineLayout(pipeline_layout);
|
defer engine.destroyPipelineLayout(compute_pipeline_layout);
|
||||||
|
|
||||||
const compute_shader = try engine.createShaderModule(.{ .code = &shaders.equirect_to_cube_comp_spv });
|
const compute_shader = try engine.createShaderModule(.{ .code = &shaders.equirect_to_cube_comp_spv });
|
||||||
defer engine.destroyShaderModule(compute_shader);
|
defer engine.destroyShaderModule(compute_shader);
|
||||||
|
|
||||||
var pipeline: vk.Pipeline = undefined;
|
var compute_pipeline: vk.Pipeline = undefined;
|
||||||
_ = try engine.device.createComputePipelines(.null_handle, 1, &.{
|
_ = try engine.device.createComputePipelines(.null_handle, 1, &.{
|
||||||
.{
|
.{
|
||||||
.stage = .{
|
.stage = .{
|
||||||
@@ -190,14 +311,14 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
.module = compute_shader,
|
.module = compute_shader,
|
||||||
.p_name = "main",
|
.p_name = "main",
|
||||||
},
|
},
|
||||||
.layout = pipeline_layout,
|
.layout = compute_pipeline_layout,
|
||||||
.base_pipeline_handle = .null_handle,
|
.base_pipeline_handle = .null_handle,
|
||||||
.base_pipeline_index = -1,
|
.base_pipeline_index = -1,
|
||||||
},
|
},
|
||||||
}, &engine.vk_allocator.interface, @ptrCast(&pipeline));
|
}, &engine.vk_allocator.interface, @ptrCast(&compute_pipeline));
|
||||||
defer engine.destroyPipeline(pipeline);
|
defer engine.destroyPipeline(compute_pipeline);
|
||||||
|
|
||||||
const descriptor_pool = try engine.createDescriptorPool(.{
|
const compute_descriptor_pool = try engine.createDescriptorPool(.{
|
||||||
.max_sets = 1,
|
.max_sets = 1,
|
||||||
.pool_sizes = &.{
|
.pool_sizes = &.{
|
||||||
.{
|
.{
|
||||||
@@ -214,17 +335,17 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
defer engine.destroyDescriptorPool(descriptor_pool);
|
defer engine.destroyDescriptorPool(compute_descriptor_pool);
|
||||||
|
|
||||||
const descriptor_set = try engine.allocateDescriptorSet(.{
|
const compute_descriptor_set = try engine.allocateDescriptorSet(.{
|
||||||
.descriptor_pool = descriptor_pool,
|
.descriptor_pool = compute_descriptor_pool,
|
||||||
.set_layout = descriptor_set_layout,
|
.set_layout = compute_descriptor_set_layout,
|
||||||
});
|
});
|
||||||
|
|
||||||
try engine.updateDescriptorSets(.{
|
try engine.updateDescriptorSets(.{
|
||||||
.writes = &.{
|
.writes = &.{
|
||||||
.{
|
.{
|
||||||
.dst_set = descriptor_set,
|
.dst_set = compute_descriptor_set,
|
||||||
.dst_binding = 1,
|
.dst_binding = 1,
|
||||||
.dst_array_element = 0,
|
.dst_array_element = 0,
|
||||||
.descriptor_type = .sampled_image,
|
.descriptor_type = .sampled_image,
|
||||||
@@ -239,7 +360,7 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.dst_set = descriptor_set,
|
.dst_set = compute_descriptor_set,
|
||||||
.dst_binding = 2,
|
.dst_binding = 2,
|
||||||
.dst_array_element = 0,
|
.dst_array_element = 0,
|
||||||
.descriptor_type = .storage_image,
|
.descriptor_type = .storage_image,
|
||||||
@@ -258,14 +379,6 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
|
|
||||||
// --- COMMAND BUFFERS -----------------------------------------------------
|
// --- COMMAND BUFFERS -----------------------------------------------------
|
||||||
|
|
||||||
// 0. Synchronization primitives
|
|
||||||
|
|
||||||
const semaphore = try engine.createSemaphore();
|
|
||||||
defer engine.destroySemaphore(semaphore);
|
|
||||||
|
|
||||||
const fence = try engine.createFence(.{});
|
|
||||||
defer engine.destroyFence(fence);
|
|
||||||
|
|
||||||
// 1. Run compute shader
|
// 1. Run compute shader
|
||||||
|
|
||||||
var compute_command_buffer = try CommandBuffer.init(engine, .compute, .transient);
|
var compute_command_buffer = try CommandBuffer.init(engine, .compute, .transient);
|
||||||
@@ -310,22 +423,28 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
compute_command_buffer.bindPipeline(.compute, pipeline);
|
compute_command_buffer.bindPipeline(.compute, compute_pipeline);
|
||||||
compute_command_buffer.bindDescriptorSet(.compute, pipeline_layout, 0, descriptor_set, null);
|
compute_command_buffer.bindDescriptorSet(.compute, compute_pipeline_layout, 0, compute_descriptor_set, null);
|
||||||
compute_command_buffer.proxy.dispatch(@divExact(cube_size, 8), @divExact(cube_size, 8), 6);
|
compute_command_buffer.proxy.dispatch(@divExact(cube_size, 8), @divExact(cube_size, 8), 6);
|
||||||
try compute_command_buffer.endCommandBuffer();
|
try compute_command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
try compute_command_buffer.submit(engine, .{
|
try compute_command_buffer.submit(engine, .{
|
||||||
.signal_semaphores = &.{semaphore},
|
.wait_semaphores = &.{
|
||||||
|
.{
|
||||||
|
.semaphore = semaphore_transition_compute,
|
||||||
|
.stage_flags = .{ .compute_shader_bit = true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.signal_semaphores = &.{semaphore_compute_transition},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2. Transition cubemap
|
// 2. Transition cubemap
|
||||||
|
|
||||||
var transition_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
|
var transition2_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
|
||||||
defer transition_command_buffer.deinit(engine);
|
defer transition2_command_buffer.deinit(engine);
|
||||||
|
|
||||||
try transition_command_buffer.beginCommandBuffer();
|
try transition2_command_buffer.beginCommandBuffer();
|
||||||
transition_command_buffer.pipelineBarrier(.{
|
transition2_command_buffer.pipelineBarrier(.{
|
||||||
.src_stage_mask = .{ .compute_shader_bit = true },
|
.src_stage_mask = .{ .compute_shader_bit = true },
|
||||||
.dst_stage_mask = .{ .top_of_pipe_bit = true },
|
.dst_stage_mask = .{ .top_of_pipe_bit = true },
|
||||||
.image_memory_barriers = &.{
|
.image_memory_barriers = &.{
|
||||||
@@ -347,10 +466,10 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
try transition_command_buffer.endCommandBuffer();
|
try transition2_command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
try transition_command_buffer.submit(engine, .{
|
try transition2_command_buffer.submit(engine, .{
|
||||||
.wait_semaphores = &.{.{ .semaphore = semaphore }},
|
.wait_semaphores = &.{.{ .semaphore = semaphore_compute_transition }},
|
||||||
.fence = fence,
|
.fence = fence,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -358,15 +477,319 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
|
|||||||
|
|
||||||
try engine.waitForFence(fence);
|
try engine.waitForFence(fence);
|
||||||
|
|
||||||
|
// --- SKYBOX PIPELINE -----------------------------------------------------
|
||||||
|
|
||||||
|
var vertex_buffer = try GenericBuffer(void, [3]f32).init(engine, .{
|
||||||
|
.usage = .vertex,
|
||||||
|
.target_queue = .graphics,
|
||||||
|
.array_capacity = 8,
|
||||||
|
});
|
||||||
|
errdefer vertex_buffer.deinit(engine);
|
||||||
|
|
||||||
|
// 6━━━━7
|
||||||
|
// ╱│ ╱┃
|
||||||
|
// 4━┿━━5 ┃ Z
|
||||||
|
// ┃ │ ┃ ┃ │
|
||||||
|
// ┃ 2──╂─3 │ Y
|
||||||
|
// ┃╱ ┃╱ │╱
|
||||||
|
// 0━━━━1 O────X
|
||||||
|
|
||||||
|
try vertex_buffer.write(engine, .{
|
||||||
|
.elements = &.{
|
||||||
|
.{ -1, -1, -1 },
|
||||||
|
.{ 1, -1, -1 },
|
||||||
|
.{ -1, 1, -1 },
|
||||||
|
.{ 1, 1, -1 },
|
||||||
|
.{ -1, -1, 1 },
|
||||||
|
.{ 1, -1, 1 },
|
||||||
|
.{ -1, 1, 1 },
|
||||||
|
.{ 1, 1, 1 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var index_buffer = try GenericBuffer(void, u16).init(engine, .{
|
||||||
|
.usage = .index,
|
||||||
|
.target_queue = .graphics,
|
||||||
|
.array_capacity = 36,
|
||||||
|
});
|
||||||
|
errdefer index_buffer.deinit(engine);
|
||||||
|
|
||||||
|
try index_buffer.write(engine, .{
|
||||||
|
.elements = &.{
|
||||||
|
// Positive X
|
||||||
|
3, 1, 7,
|
||||||
|
7, 1, 5,
|
||||||
|
// Negative X
|
||||||
|
0, 2, 4,
|
||||||
|
4, 2, 6,
|
||||||
|
// Positive Y
|
||||||
|
2, 3, 6,
|
||||||
|
6, 3, 7,
|
||||||
|
// Negative Y
|
||||||
|
1, 0, 5,
|
||||||
|
5, 0, 4,
|
||||||
|
// Positive Z
|
||||||
|
6, 7, 4,
|
||||||
|
4, 7, 5,
|
||||||
|
// Negative Z
|
||||||
|
0, 1, 2,
|
||||||
|
2, 1, 3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const descriptor_set_layout = try engine.createDescriptorSetLayout(.{
|
||||||
|
.bindings = &.{
|
||||||
|
.{
|
||||||
|
.binding = 0,
|
||||||
|
.descriptor_type = .uniform_buffer,
|
||||||
|
.descriptor_count = 1,
|
||||||
|
.stage_flags = .{ .vertex_bit = true },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.binding = 1,
|
||||||
|
.descriptor_type = .sampler,
|
||||||
|
.descriptor_count = 1,
|
||||||
|
.stage_flags = .{ .fragment_bit = true },
|
||||||
|
.immutable_samplers = &.{sampler},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.binding = 2,
|
||||||
|
.descriptor_type = .sampled_image,
|
||||||
|
.descriptor_count = 1,
|
||||||
|
.stage_flags = .{ .fragment_bit = true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
errdefer engine.destroyDescriptorSetLayout(descriptor_set_layout);
|
||||||
|
|
||||||
|
const pipeline_layout = try engine.createPipelineLayout(.{
|
||||||
|
.set_layouts = &.{descriptor_set_layout},
|
||||||
|
});
|
||||||
|
errdefer engine.destroyPipelineLayout(pipeline_layout);
|
||||||
|
|
||||||
|
const descriptor_pool = try engine.createDescriptorPool(.{
|
||||||
|
.max_sets = 1,
|
||||||
|
.pool_sizes = &.{
|
||||||
|
.{
|
||||||
|
.type = .uniform_buffer,
|
||||||
|
.descriptor_count = 1,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.type = .sampler,
|
||||||
|
.descriptor_count = 1,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.type = .sampled_image,
|
||||||
|
.descriptor_count = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
errdefer engine.destroyDescriptorPool(compute_descriptor_pool);
|
||||||
|
|
||||||
|
const descriptor_set = try engine.allocateDescriptorSet(.{
|
||||||
|
.descriptor_pool = descriptor_pool,
|
||||||
|
.set_layout = descriptor_set_layout,
|
||||||
|
});
|
||||||
|
|
||||||
|
try engine.updateDescriptorSets(.{
|
||||||
|
.writes = &.{
|
||||||
|
.{
|
||||||
|
.dst_set = descriptor_set,
|
||||||
|
.dst_binding = 0,
|
||||||
|
.dst_array_element = 0,
|
||||||
|
.descriptor_type = .uniform_buffer,
|
||||||
|
.descriptor_infos = .{
|
||||||
|
.buffer = &.{
|
||||||
|
.{
|
||||||
|
.buffer = global_uniforms_buffer,
|
||||||
|
.offset = 0,
|
||||||
|
.range = vk.WHOLE_SIZE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.dst_set = descriptor_set,
|
||||||
|
.dst_binding = 2,
|
||||||
|
.dst_array_element = 0,
|
||||||
|
.descriptor_type = .sampled_image,
|
||||||
|
.descriptor_infos = .{
|
||||||
|
.image = &.{
|
||||||
|
.{
|
||||||
|
.sampler = .null_handle,
|
||||||
|
.image_view = cubemap_image_view,
|
||||||
|
.image_layout = .shader_read_only_optimal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const vertex_shader = try engine.createShaderModule(.{ .code = &shaders.skybox_vert_spv });
|
||||||
|
defer engine.destroyShaderModule(vertex_shader);
|
||||||
|
|
||||||
|
const fragment_shader = try engine.createShaderModule(.{ .code = &shaders.skybox_frag_spv });
|
||||||
|
defer engine.destroyShaderModule(fragment_shader);
|
||||||
|
|
||||||
|
const pipeline = try engine.createGraphicsPipeline(.{
|
||||||
|
.stages = &.{
|
||||||
|
.{
|
||||||
|
.stage = .{ .vertex_bit = true },
|
||||||
|
.module = vertex_shader,
|
||||||
|
.name = "main",
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.stage = .{ .fragment_bit = true },
|
||||||
|
.module = fragment_shader,
|
||||||
|
.name = "main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.vertex_input_state = .{
|
||||||
|
.vertex_binding_descriptions = &.{
|
||||||
|
.{
|
||||||
|
.binding = 0,
|
||||||
|
.stride = @sizeOf([3]f32),
|
||||||
|
.input_rate = .vertex,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.vertex_attribute_descriptions = &.{
|
||||||
|
.{
|
||||||
|
.location = 0,
|
||||||
|
.binding = 0,
|
||||||
|
.format = .r32g32b32_sfloat,
|
||||||
|
.offset = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.input_assembly_state = .{
|
||||||
|
.topology = .triangle_list,
|
||||||
|
.primitive_restart_enable = .false,
|
||||||
|
},
|
||||||
|
.viewport_state = .{
|
||||||
|
.viewports = &.{undefined}, // dynamic
|
||||||
|
.scissors = &.{undefined}, // dynamic
|
||||||
|
},
|
||||||
|
.rasterization_state = .{
|
||||||
|
.depth_clamp_enable = .false,
|
||||||
|
.rasterizer_discard_enable = .false,
|
||||||
|
.polygon_mode = .fill,
|
||||||
|
.cull_mode = .{ .back_bit = true },
|
||||||
|
.front_face = .counter_clockwise,
|
||||||
|
.depth_bias_enable = .false,
|
||||||
|
.depth_bias_constant_factor = 0,
|
||||||
|
.depth_bias_clamp = 0,
|
||||||
|
.depth_bias_slope_factor = 0,
|
||||||
|
.line_width = 1,
|
||||||
|
},
|
||||||
|
.multisample_state = .{
|
||||||
|
.rasterization_samples = .{ .@"1_bit" = true },
|
||||||
|
.sample_shading_enable = .false,
|
||||||
|
.min_sample_shading = 1,
|
||||||
|
.alpha_to_coverage_enable = .false,
|
||||||
|
.alpha_to_one_enable = .false,
|
||||||
|
},
|
||||||
|
.depth_stencil_state = .{
|
||||||
|
.depth_test_enable = .true,
|
||||||
|
.depth_write_enable = .false,
|
||||||
|
.depth_compare_op = .equal,
|
||||||
|
.depth_bounds_test_enable = .false,
|
||||||
|
.stencil_test_enable = .false,
|
||||||
|
.front = undefined,
|
||||||
|
.back = undefined,
|
||||||
|
.min_depth_bounds = 0,
|
||||||
|
.max_depth_bounds = 1,
|
||||||
|
},
|
||||||
|
.color_blend_state = .{
|
||||||
|
.logic_op_enable = .false,
|
||||||
|
.logic_op = .copy,
|
||||||
|
.attachments = &.{
|
||||||
|
.{
|
||||||
|
.blend_enable = .false,
|
||||||
|
.src_color_blend_factor = .one,
|
||||||
|
.dst_color_blend_factor = .zero,
|
||||||
|
.color_blend_op = .add,
|
||||||
|
.src_alpha_blend_factor = .one,
|
||||||
|
.dst_alpha_blend_factor = .zero,
|
||||||
|
.alpha_blend_op = .add,
|
||||||
|
.color_write_mask = .{
|
||||||
|
.r_bit = true,
|
||||||
|
.g_bit = true,
|
||||||
|
.b_bit = true,
|
||||||
|
.a_bit = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.blend_constants = .{ 0, 0, 0, 0 },
|
||||||
|
},
|
||||||
|
.dynamic_state = .{
|
||||||
|
.dynamic_states = &.{ .viewport, .scissor },
|
||||||
|
},
|
||||||
|
.layout = pipeline_layout,
|
||||||
|
.render_pass = render_pass,
|
||||||
|
.subpass = 0,
|
||||||
|
});
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.image = cubemap_image,
|
.image = cubemap_image,
|
||||||
.image_view = cubemap_image_view,
|
.image_view = cubemap_image_view,
|
||||||
.device_memory = cubemap_device_memory,
|
.device_memory = cubemap_device_memory,
|
||||||
|
|
||||||
|
.vertex_buffer = vertex_buffer,
|
||||||
|
.index_buffer = index_buffer,
|
||||||
|
.sampler = sampler,
|
||||||
|
|
||||||
|
.descriptor_set_layout = descriptor_set_layout,
|
||||||
|
.descriptor_pool = descriptor_pool,
|
||||||
|
.descriptor_set = descriptor_set,
|
||||||
|
.pipeline_layout = pipeline_layout,
|
||||||
|
.pipeline = pipeline,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Skybox, engine: *Engine) void {
|
pub fn deinit(self: *Skybox, engine: *Engine) void {
|
||||||
|
engine.destroyPipeline(self.pipeline);
|
||||||
|
engine.destroyPipelineLayout(self.pipeline_layout);
|
||||||
|
engine.destroyDescriptorPool(self.descriptor_pool);
|
||||||
|
engine.destroyDescriptorSetLayout(self.descriptor_set_layout);
|
||||||
|
|
||||||
|
engine.destroySampler(self.sampler);
|
||||||
|
self.index_buffer.deinit(engine);
|
||||||
|
self.vertex_buffer.deinit(engine);
|
||||||
|
|
||||||
engine.destroyImageView(self.image_view);
|
engine.destroyImageView(self.image_view);
|
||||||
engine.freeMemory(self.device_memory);
|
engine.freeMemory(self.device_memory);
|
||||||
engine.destroyImage(self.image);
|
engine.destroyImage(self.image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bind(self: *const Skybox, command_buffer: CommandBuffer, extent: vk.Extent2D) !void {
|
||||||
|
command_buffer.setViewport(0, &.{
|
||||||
|
.{
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = @floatFromInt(extent.width),
|
||||||
|
.height = @floatFromInt(extent.height),
|
||||||
|
.min_depth = 0,
|
||||||
|
.max_depth = 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
command_buffer.setScissor(0, &.{
|
||||||
|
.{
|
||||||
|
.offset = .{ .x = 0, .y = 0 },
|
||||||
|
.extent = extent,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
command_buffer.bindPipeline(.graphics, self.pipeline);
|
||||||
|
try command_buffer.bindVertexBuffers(0, &.{
|
||||||
|
.{
|
||||||
|
.buffer = self.vertex_buffer.buffer,
|
||||||
|
.offset = 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *const Skybox, command_buffer: CommandBuffer) void {
|
||||||
|
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.descriptor_set, null);
|
||||||
|
command_buffer.drawIndexed(.{ .index_count = 36 });
|
||||||
|
}
|
||||||
|
|||||||
@@ -105,3 +105,5 @@ pub const ObjectUniforms = extern struct {
|
|||||||
pub const equirect_to_cube_comp_spv align(4) = @embedFile("shaders/equirect_to_cube_comp.spv").*;
|
pub const equirect_to_cube_comp_spv align(4) = @embedFile("shaders/equirect_to_cube_comp.spv").*;
|
||||||
pub const main_vert_spv align(4) = @embedFile("shaders/main_vert.spv").*;
|
pub const main_vert_spv align(4) = @embedFile("shaders/main_vert.spv").*;
|
||||||
pub const main_frag_spv align(4) = @embedFile("shaders/main_frag.spv").*;
|
pub const main_frag_spv align(4) = @embedFile("shaders/main_frag.spv").*;
|
||||||
|
pub const skybox_vert_spv align(4) = @embedFile("shaders/skybox_vert.spv").*;
|
||||||
|
pub const skybox_frag_spv align(4) = @embedFile("shaders/skybox_frag.spv").*;
|
||||||
|
|||||||
Reference in New Issue
Block a user