minecraft: texture sampling

This commit is contained in:
Zack Buhman 2026-04-30 15:43:28 -05:00
parent 46924c8451
commit b79473a881
8 changed files with 185 additions and 11 deletions

View File

@ -25,7 +25,7 @@ CFLAGS += -I./data
CFLAGS += -I../SDL3-dist/include CFLAGS += -I../SDL3-dist/include
CFLAGS += -fpic CFLAGS += -fpic
FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address #FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address
LDFLAGS += -lm LDFLAGS += -lm
ifeq ($(UNAME),Linux) ifeq ($(UNAME),Linux)

BIN
data/minecraft/terrain2.dds Normal file

Binary file not shown.

BIN
data/minecraft/terrain2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -33,3 +33,5 @@ data/minecraft/midnightmeadow/region.0.-1.instance.cfg
data/minecraft/midnightmeadow/region.-1.-1.instance.cfg data/minecraft/midnightmeadow/region.-1.-1.instance.cfg
data/minecraft/midnightmeadow/global.dump data/minecraft/midnightmeadow/global.dump
data/minecraft/midnightmeadow/global.lights.vtx data/minecraft/midnightmeadow/global.lights.vtx
data/minecraft/terrain2.dds

View File

@ -19,7 +19,7 @@ namespace minecraft::vulkan {
static constexpr uint32_t maxFrames = 2; static constexpr uint32_t maxFrames = 2;
static constexpr uint32_t perFrameDescriptorCount = 1; static constexpr uint32_t perFrameDescriptorCount = 1;
static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount; static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount;
static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 0; static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 3;
static constexpr int perVertexSize = (3 + 3 + 2) * 2; static constexpr int perVertexSize = (3 + 3 + 2) * 2;
static constexpr int perInstanceSize = (3 + 1 + 3 + 1) * 2; static constexpr int perInstanceSize = (3 + 1 + 3 + 1) * 2;
@ -43,6 +43,9 @@ namespace minecraft::vulkan {
VkFormat colorFormat; VkFormat colorFormat;
VkFormat depthFormat; VkFormat depthFormat;
VkSampler linearSampler;
VkImageView shadowDepthImageView;
// //
// method initialized // method initialized
// //
@ -54,8 +57,16 @@ namespace minecraft::vulkan {
VkDescriptorPool descriptorPool{ VK_NULL_HANDLE }; VkDescriptorPool descriptorPool{ VK_NULL_HANDLE };
VkDescriptorSetLayout descriptorSetLayouts[1]; // unrelated to maxFrames, unrelated to descriptorCount VkDescriptorSetLayout descriptorSetLayouts[2]; // unrelated to maxFrames, unrelated to descriptorCount
VkDescriptorSet descriptorSets0[maxFrames]; VkDescriptorSet descriptorSets0[maxFrames];
VkDescriptorSet descriptorSet1;
struct Image {
VkImage image;
VkDeviceMemory memory;
VkImageView imageView;
};
Image terrainImage;
struct { struct {
VkDeviceMemory memory; VkDeviceMemory memory;
@ -76,7 +87,9 @@ namespace minecraft::vulkan {
VkPhysicalDeviceProperties physicalDeviceProperties, VkPhysicalDeviceProperties physicalDeviceProperties,
VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties, VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties,
VkFormat colorFormat, VkFormat colorFormat,
VkFormat depthFormat); VkFormat depthFormat,
VkSampler linearSampler,
VkImageView shadowDepthImageView);
void init(); void init();
void load_vertex_index_buffer(char const * vertex_filename, void load_vertex_index_buffer(char const * vertex_filename,
char const * index_filename); char const * index_filename);
@ -89,6 +102,8 @@ namespace minecraft::vulkan {
void transfer_transforms(XMMATRIX const & projection, void transfer_transforms(XMMATRIX const & projection,
XMMATRIX const & view, XMMATRIX const & view,
uint32_t frameIndex); uint32_t frameIndex);
void load_image(char const * filename,
Image & image);
void draw(VkCommandBuffer commandBuffer, void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex); uint32_t frameIndex);

View File

@ -14,6 +14,7 @@ struct VSInput
struct VSOutput struct VSOutput
{ {
float4 Position : SV_POSITION; float4 Position : SV_POSITION;
float4 Texture : TEXCOORD0;
}; };
struct Scene struct Scene
@ -28,17 +29,33 @@ struct Scene
// set 0: per-frame // set 0: per-frame
[[vk::binding(0, 0)]] ConstantBuffer<Scene> Scene; [[vk::binding(0, 0)]] ConstantBuffer<Scene> Scene;
// set 1: constant
[[vk::binding(0, 1)]] SamplerState LinearSampler;
[[vk::binding(1, 1)]] Texture2DArray ShadowTexture;
[[vk::binding(2, 1)]] Texture2D TerrainTexture;
float2 yf(float2 v, float scale)
{
return float2(v.x, 1.0 - v.y) * scale;
}
[shader("vertex")] [shader("vertex")]
VSOutput VSMain(VSInput input) VSOutput VSMain(VSInput input)
{ {
VSOutput output = (VSOutput)0; VSOutput output = (VSOutput)0;
float4 Position = float4(input.Position.xyz + input.BlockPosition, 1.0); float4 Position = float4(input.Position.xyz + input.BlockPosition, 1.0);
output.Position = mul(Scene.Projection, mul(Scene.View, Position)); output.Position = mul(Scene.Projection, mul(Scene.View, Position));
float2 textureOffset = float2(input.TextureID % 8, input.TextureID / 8) * 16;
output.Texture = float4(yf(input.Texture.xy, 16), textureOffset);
return output; return output;
} }
[shader("pixel")] [shader("pixel")]
float4 PSMain(VSOutput input) : SV_TARGET float4 PSMain(VSOutput input) : SV_TARGET
{ {
return float4(1, 0, 0, 1); float2 texture = input.Texture.xy + input.Texture.zw;
float4 color = TerrainTexture.Load(int3(texture, 0)).xyzw;
return float4(color.xyz, 1);
} }

View File

@ -609,7 +609,9 @@ int main()
physicalDeviceProperties, physicalDeviceProperties,
physicalDeviceMemoryProperties, physicalDeviceMemoryProperties,
surfaceFormat.format, surfaceFormat.format,
depthFormat); depthFormat,
textureSamplers[0],
shadowDepthImageViewDepth);
minecraft_state.init(); minecraft_state.init();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -29,7 +29,9 @@ namespace minecraft::vulkan {
VkPhysicalDeviceProperties physicalDeviceProperties, VkPhysicalDeviceProperties physicalDeviceProperties,
VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties, VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties,
VkFormat colorFormat, VkFormat colorFormat,
VkFormat depthFormat) VkFormat depthFormat,
VkSampler linearSampler,
VkImageView shadowDepthImageView)
{ {
this->instance = instance; this->instance = instance;
this->device = device; this->device = device;
@ -41,12 +43,16 @@ namespace minecraft::vulkan {
this->colorFormat = colorFormat; this->colorFormat = colorFormat;
this->depthFormat = depthFormat; this->depthFormat = depthFormat;
this->linearSampler = linearSampler;
this->shadowDepthImageView = shadowDepthImageView;
} }
void vulkan::init() void vulkan::init()
{ {
load_vertex_index_buffer("data/minecraft/per_vertex.vtx", "data/minecraft/configuration.idx"); load_vertex_index_buffer("data/minecraft/per_vertex.vtx", "data/minecraft/configuration.idx");
load_shader(); load_shader();
load_image("data/minecraft/terrain2.dds", terrainImage);
create_uniform_buffers(); create_uniform_buffers();
create_descriptor_sets(); create_descriptor_sets();
write_descriptor_sets(); write_descriptor_sets();
@ -142,7 +148,7 @@ namespace minecraft::vulkan {
{ {
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{ VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1, .setLayoutCount = 2,
.pSetLayouts = descriptorSetLayouts, .pSetLayouts = descriptorSetLayouts,
//.pushConstantRangeCount = 0, //.pushConstantRangeCount = 0,
//.pPushConstantRanges = nullptr //.pPushConstantRanges = nullptr
@ -388,6 +394,49 @@ namespace minecraft::vulkan {
assert(offsetsIndex == uniformBufferDescriptorCount); assert(offsetsIndex == uniformBufferDescriptorCount);
} }
//////////////////////////////////////////////////////////////////////
// images
//////////////////////////////////////////////////////////////////////
void vulkan::load_image(char const * filename,
Image & image)
{
VkCommandBuffer commandBuffer{};
VkCommandBufferAllocateInfo commandBufferAllocateInfo{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = commandPool,
.commandBufferCount = 1
};
VK_CHECK(vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, &commandBuffer));
VkFenceCreateInfo fenceCreateInfo{
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
};
VkFence fence{};
VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
// load
createImageFromFilenameDDS(device,
queue,
commandBuffer,
fence,
physicalDeviceProperties.limits.nonCoherentAtomSize,
physicalDeviceMemoryProperties,
filename,
&image.image,
&image.memory,
&image.imageView);
// cleanup
vkDestroyFence(device, fence, nullptr);
vkFreeCommandBuffers(device,
commandPool,
1,
&commandBuffer);
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// descriptor sets // descriptor sets
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -397,16 +446,24 @@ namespace minecraft::vulkan {
// //
// pool // pool
// //
constexpr int descriptorPoolSizesCount = 1; constexpr int descriptorPoolSizesCount = 3;
VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{ VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{
{ {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = (maxFrames * 1), .descriptorCount = (maxFrames * 1),
}, },
{ // linear sampler
.type = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = 1,
},
{
.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1 + 1, // +1 for shadow sampler
}
}; };
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = maxFrames, .maxSets = maxFrames + 1,
.poolSizeCount = descriptorPoolSizesCount, .poolSizeCount = descriptorPoolSizesCount,
.pPoolSizes = descriptorPoolSizes .pPoolSizes = descriptorPoolSizes
}; };
@ -446,6 +503,48 @@ namespace minecraft::vulkan {
}; };
VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, descriptorSets0)); VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, descriptorSets0));
} }
//
// uniform buffer descriptor set layout/allocation (set 1, constant)
//
{
constexpr int bindingCount = 3;
VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
{ // shadow sampled image
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
{ // terrain sampled image
.binding = 2,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
}
};
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = bindingCount,
.pBindings = descriptorSetLayoutBindings
};
VK_CHECK(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayouts[1]));
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = descriptorPool,
.descriptorSetCount = 1,
.pSetLayouts = &descriptorSetLayouts[1]
};
VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet1));
}
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -459,6 +558,7 @@ namespace minecraft::vulkan {
VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames]; VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames];
// set0 bindings
for (uint32_t i = 0; i < maxFrames; i++) { for (uint32_t i = 0; i < maxFrames; i++) {
sceneDescriptorBufferInfos[i] = { sceneDescriptorBufferInfos[i] = {
.buffer = shaderDataDevice.frame[i].sceneBuffer, .buffer = shaderDataDevice.frame[i].sceneBuffer,
@ -475,6 +575,43 @@ namespace minecraft::vulkan {
}; };
} }
// set1 bindings
VkDescriptorImageInfo samplerDescriptorImageInfo = {
.sampler = linearSampler,
};
writeDescriptorSets[writeIndex++] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptorSet1,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
.pImageInfo = &samplerDescriptorImageInfo
};
VkDescriptorImageInfo shadowDepthDescriptorImageInfo = {
.imageView = shadowDepthImageView,
.imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL
};
writeDescriptorSets[writeIndex++] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptorSet1,
.dstBinding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.pImageInfo = &shadowDepthDescriptorImageInfo
};
VkDescriptorImageInfo terrainDescriptorImageInfo = {
.imageView = terrainImage.imageView,
.imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL
};
writeDescriptorSets[writeIndex++] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptorSet1,
.dstBinding = 2,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.pImageInfo = &terrainDescriptorImageInfo
};
assert(writeIndex == bindingCount); assert(writeIndex == bindingCount);
vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr); vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr);
} }
@ -529,11 +666,12 @@ namespace minecraft::vulkan {
{ {
VkDescriptorSet descriptorSets[2] = { VkDescriptorSet descriptorSets[2] = {
descriptorSets0[frameIndex], descriptorSets0[frameIndex],
descriptorSet1,
}; };
vkCmdBindDescriptorSets(commandBuffer, vkCmdBindDescriptorSets(commandBuffer,
VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout, pipelineLayout,
0, 1, descriptorSets, 0, 2, descriptorSets,
0, nullptr); 0, nullptr);
vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset, VK_INDEX_TYPE_UINT16); vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset, VK_INDEX_TYPE_UINT16);