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 += -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
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/global.dump
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 perFrameDescriptorCount = 1;
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 perInstanceSize = (3 + 1 + 3 + 1) * 2;
@ -43,6 +43,9 @@ namespace minecraft::vulkan {
VkFormat colorFormat;
VkFormat depthFormat;
VkSampler linearSampler;
VkImageView shadowDepthImageView;
//
// method initialized
//
@ -54,8 +57,16 @@ namespace minecraft::vulkan {
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 descriptorSet1;
struct Image {
VkImage image;
VkDeviceMemory memory;
VkImageView imageView;
};
Image terrainImage;
struct {
VkDeviceMemory memory;
@ -76,7 +87,9 @@ namespace minecraft::vulkan {
VkPhysicalDeviceProperties physicalDeviceProperties,
VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties,
VkFormat colorFormat,
VkFormat depthFormat);
VkFormat depthFormat,
VkSampler linearSampler,
VkImageView shadowDepthImageView);
void init();
void load_vertex_index_buffer(char const * vertex_filename,
char const * index_filename);
@ -89,6 +102,8 @@ namespace minecraft::vulkan {
void transfer_transforms(XMMATRIX const & projection,
XMMATRIX const & view,
uint32_t frameIndex);
void load_image(char const * filename,
Image & image);
void draw(VkCommandBuffer commandBuffer,
uint32_t frameIndex);

View File

@ -14,6 +14,7 @@ struct VSInput
struct VSOutput
{
float4 Position : SV_POSITION;
float4 Texture : TEXCOORD0;
};
struct Scene
@ -28,17 +29,33 @@ struct Scene
// set 0: per-frame
[[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")]
VSOutput VSMain(VSInput input)
{
VSOutput output = (VSOutput)0;
float4 Position = float4(input.Position.xyz + input.BlockPosition, 1.0);
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;
}
[shader("pixel")]
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,
physicalDeviceMemoryProperties,
surfaceFormat.format,
depthFormat);
depthFormat,
textureSamplers[0],
shadowDepthImageViewDepth);
minecraft_state.init();
//////////////////////////////////////////////////////////////////////

View File

@ -29,7 +29,9 @@ namespace minecraft::vulkan {
VkPhysicalDeviceProperties physicalDeviceProperties,
VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties,
VkFormat colorFormat,
VkFormat depthFormat)
VkFormat depthFormat,
VkSampler linearSampler,
VkImageView shadowDepthImageView)
{
this->instance = instance;
this->device = device;
@ -41,12 +43,16 @@ namespace minecraft::vulkan {
this->colorFormat = colorFormat;
this->depthFormat = depthFormat;
this->linearSampler = linearSampler;
this->shadowDepthImageView = shadowDepthImageView;
}
void vulkan::init()
{
load_vertex_index_buffer("data/minecraft/per_vertex.vtx", "data/minecraft/configuration.idx");
load_shader();
load_image("data/minecraft/terrain2.dds", terrainImage);
create_uniform_buffers();
create_descriptor_sets();
write_descriptor_sets();
@ -142,7 +148,7 @@ namespace minecraft::vulkan {
{
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.setLayoutCount = 2,
.pSetLayouts = descriptorSetLayouts,
//.pushConstantRangeCount = 0,
//.pPushConstantRanges = nullptr
@ -388,6 +394,49 @@ namespace minecraft::vulkan {
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
//////////////////////////////////////////////////////////////////////
@ -397,16 +446,24 @@ namespace minecraft::vulkan {
//
// pool
//
constexpr int descriptorPoolSizesCount = 1;
constexpr int descriptorPoolSizesCount = 3;
VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{
{
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.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{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = maxFrames,
.maxSets = maxFrames + 1,
.poolSizeCount = descriptorPoolSizesCount,
.pPoolSizes = descriptorPoolSizes
};
@ -446,6 +503,48 @@ namespace minecraft::vulkan {
};
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];
// set0 bindings
for (uint32_t i = 0; i < maxFrames; i++) {
sceneDescriptorBufferInfos[i] = {
.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);
vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr);
}
@ -529,11 +666,12 @@ namespace minecraft::vulkan {
{
VkDescriptorSet descriptorSets[2] = {
descriptorSets0[frameIndex],
descriptorSet1,
};
vkCmdBindDescriptorSets(commandBuffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout,
0, 1, descriptorSets,
0, 2, descriptorSets,
0, nullptr);
vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset, VK_INDEX_TYPE_UINT16);