Sketchy skybox

This commit is contained in:
2025-12-07 23:27:42 +01:00
parent df00e3052f
commit 7c438d1284
7 changed files with 534 additions and 47 deletions

6
.vscode/launch.json vendored
View File

@@ -8,5 +8,11 @@
"program": "${workspaceFolder}/zig-out/bin/voxel-game",
"cwd": "${workspaceFolder}",
},
{
"name": "Attach",
"type": "lldb",
"request": "attach",
"program": "${workspaceFolder}/zig-out/bin/voxel-game",
},
],
}

View 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);
}

View 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;
}

View File

@@ -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/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/skybox.frag -o src/shaders/skybox_frag.spv
glslc --target-env=vulkan1.2 assets/shaders/skybox.vert -o src/shaders/skybox_vert.spv

View File

@@ -618,7 +618,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
.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);
return .{
@@ -849,6 +849,9 @@ fn render(self: *Game) !void {
while (it.next()) |chunk| {
chunk.draw(self.pipeline_layout, command_buffer);
}
try self.skybox.bind(command_buffer, extent);
self.skybox.draw(command_buffer);
}
try command_buffer.endCommandBuffer();

View File

@@ -7,12 +7,24 @@ const vk = @import("vulkan");
const CommandBuffer = @import("CommandBuffer.zig");
const Engine = @import("Engine.zig");
const GenericBuffer = @import("GenericBuffer.zig").GenericBuffer;
const StagingBuffer = @import("StagingBuffer.zig");
image: vk.Image,
image_view: vk.ImageView,
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});
// --- LOAD IMAGE FROM MEMORY ----------------------------------------------
@@ -29,7 +41,33 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
defer img.deinit();
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(.{
.image_type = .@"2d",
@@ -42,23 +80,21 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
.mip_levels = 1,
.array_layers = 1,
.samples = .{ .@"1_bit" = true },
.tiling = .linear,
.tiling = .optimal,
.usage = .{
.transfer_dst_bit = true,
.sampled_bit = true,
},
.queue_family_indices = &.{
engine.compute_queue.allocation.family,
engine.transfer_queue.allocation.family,
},
.initial_layout = .preinitialized,
.initial_layout = .undefined,
});
defer engine.destroyImage(equirect_image);
const equirect_memory_requirements = engine.getImageMemoryRequirements(equirect_image);
const equirect_device_memory = try engine.allocate(equirect_memory_requirements, .{
.host_visible_bit = true,
.host_coherent_bit = true,
});
const equirect_device_memory = try engine.allocate(equirect_memory_requirements, .{ .device_local_bit = true });
defer engine.freeMemory(equirect_device_memory);
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);
const data = try engine.mapMemory(equirect_device_memory, 0, equirect_memory_requirements.size, .{});
@memcpy(data, img.data);
engine.unmapMemory(equirect_device_memory);
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -------------------------
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 ------------------------------------------------
@@ -147,9 +268,9 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
.border_color = .float_transparent_black,
.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 = &.{
.{
.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(.{
.set_layouts = &.{descriptor_set_layout},
const compute_pipeline_layout = try engine.createPipelineLayout(.{
.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 });
defer engine.destroyShaderModule(compute_shader);
var pipeline: vk.Pipeline = undefined;
var compute_pipeline: vk.Pipeline = undefined;
_ = try engine.device.createComputePipelines(.null_handle, 1, &.{
.{
.stage = .{
@@ -190,14 +311,14 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
.module = compute_shader,
.p_name = "main",
},
.layout = pipeline_layout,
.layout = compute_pipeline_layout,
.base_pipeline_handle = .null_handle,
.base_pipeline_index = -1,
},
}, &engine.vk_allocator.interface, @ptrCast(&pipeline));
defer engine.destroyPipeline(pipeline);
}, &engine.vk_allocator.interface, @ptrCast(&compute_pipeline));
defer engine.destroyPipeline(compute_pipeline);
const descriptor_pool = try engine.createDescriptorPool(.{
const compute_descriptor_pool = try engine.createDescriptorPool(.{
.max_sets = 1,
.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(.{
.descriptor_pool = descriptor_pool,
.set_layout = descriptor_set_layout,
const compute_descriptor_set = try engine.allocateDescriptorSet(.{
.descriptor_pool = compute_descriptor_pool,
.set_layout = compute_descriptor_set_layout,
});
try engine.updateDescriptorSets(.{
.writes = &.{
.{
.dst_set = descriptor_set,
.dst_set = compute_descriptor_set,
.dst_binding = 1,
.dst_array_element = 0,
.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_array_element = 0,
.descriptor_type = .storage_image,
@@ -258,14 +379,6 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
// --- 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
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.bindDescriptorSet(.compute, pipeline_layout, 0, descriptor_set, null);
compute_command_buffer.bindPipeline(.compute, compute_pipeline);
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);
try compute_command_buffer.endCommandBuffer();
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
var transition_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
defer transition_command_buffer.deinit(engine);
var transition2_command_buffer = try CommandBuffer.init(engine, .graphics, .transient);
defer transition2_command_buffer.deinit(engine);
try transition_command_buffer.beginCommandBuffer();
transition_command_buffer.pipelineBarrier(.{
try transition2_command_buffer.beginCommandBuffer();
transition2_command_buffer.pipelineBarrier(.{
.src_stage_mask = .{ .compute_shader_bit = true },
.dst_stage_mask = .{ .top_of_pipe_bit = true },
.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, .{
.wait_semaphores = &.{.{ .semaphore = semaphore }},
try transition2_command_buffer.submit(engine, .{
.wait_semaphores = &.{.{ .semaphore = semaphore_compute_transition }},
.fence = fence,
});
@@ -358,15 +477,319 @@ pub fn load(filename: []const u8, engine: *Engine, cube_size: u32, temp_allocato
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 .{
.image = cubemap_image,
.image_view = cubemap_image_view,
.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 {
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.freeMemory(self.device_memory);
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 });
}

View File

@@ -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 main_vert_spv align(4) = @embedFile("shaders/main_vert.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").*;