collada: animated eidelwind

This commit is contained in:
Zack Buhman 2026-04-18 18:24:09 -05:00
parent 440272ad7a
commit dbd36f2d2c
17 changed files with 18169 additions and 74 deletions

View File

@ -49,7 +49,8 @@ OBJS = \
src/collada/animate.o src/collada/animate.o
SCENES = \ SCENES = \
data/scenes/shadow_test/shadow_test.o data/scenes/shadow_test/shadow_test.o \
data/scenes/eidelwind/eidelwind.o
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)
LIBS = \ LIBS = \

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
namespace eidelwind {
extern collada::types::descriptor const descriptor;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -2,3 +2,8 @@ shader/collada.spv
data/scenes/shadow_test/shadow_test.vtx data/scenes/shadow_test/shadow_test.vtx
data/scenes/shadow_test/shadow_test.idx data/scenes/shadow_test/shadow_test.idx
data/scenes/shadow_test/images/0_leaf_white.dds data/scenes/shadow_test/images/0_leaf_white.dds
data/scenes/eidelwind/eidelwind.vtx
data/scenes/eidelwind/eidelwind.vjw
data/scenes/eidelwind/eidelwind.idx
data/scenes/eidelwind/images/0_EidelWindTextureTest.dds

View File

@ -18,6 +18,9 @@ namespace collada::scene {
struct Node { struct Node {
XMFLOAT4X4 world; XMFLOAT4X4 world;
}; };
struct Joint {
XMFLOAT4X4 transform;
};
struct MaterialColor { struct MaterialColor {
XMFLOAT4 emission; XMFLOAT4 emission;
XMFLOAT4 ambient; XMFLOAT4 ambient;
@ -41,12 +44,13 @@ namespace collada::scene {
struct vulkan { struct vulkan {
static constexpr uint32_t maxFrames = 2; static constexpr uint32_t maxFrames = 2;
static constexpr uint32_t perFrameDescriptorCount = 2; static constexpr uint32_t perFrameDescriptorCount = 3;
static constexpr uint32_t constantDescriptorCount = 1; static constexpr uint32_t constantDescriptorCount = 1;
static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount; static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount;
// +3: linear sampler, shadow sampled image, scene sampled image (array) // +3: linear sampler, shadow sampled image, scene sampled image (array)
static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 3; static constexpr uint32_t bindingCount = uniformBufferDescriptorCount + 3;
static constexpr int shaderVariantCount = 3; static constexpr int shaderVariantCount = 3;
static constexpr uint32_t maxJointsCount = 128;
// externally initialized, opaque handle // externally initialized, opaque handle
VkInstance instance; VkInstance instance;
@ -70,6 +74,7 @@ namespace collada::scene {
VkShaderModule shaderModule; VkShaderModule shaderModule;
VkPipeline * pipelines; // per-scene, one per descriptor->inputs_list_count VkPipeline * pipelines; // per-scene, one per descriptor->inputs_list_count
struct { struct {
VkDeviceSize jointWeightOffset;
VkDeviceSize indexOffset; VkDeviceSize indexOffset;
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VkDeviceMemory memory;
@ -107,6 +112,11 @@ namespace collada::scene {
VkDeviceAddress nodesOffset; VkDeviceAddress nodesOffset;
VkDeviceAddress nodesSize; VkDeviceAddress nodesSize;
void * nodesMapped; void * nodesMapped;
VkBuffer jointsBuffer;
VkDeviceAddress jointsOffset;
VkDeviceAddress jointsSize;
void * jointsMapped;
} frame[maxFrames]; } frame[maxFrames];
struct { // must match constantDescriptorCount struct { // must match constantDescriptorCount
VkBuffer materialColorImagesBuffer; VkBuffer materialColorImagesBuffer;
@ -151,6 +161,7 @@ namespace collada::scene {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
void load_vertex_index_buffer(char const * vertex_filename, void load_vertex_index_buffer(char const * vertex_filename,
char const * vertex_joint_weight_filename,
char const * index_filename); char const * index_filename);
void create_pipelines(collada::types::descriptor const * const descriptor); void create_pipelines(collada::types::descriptor const * const descriptor);
@ -171,9 +182,18 @@ namespace collada::scene {
void draw_instance_geometries(types::instance_geometry const * const instance_geometries, void draw_instance_geometries(types::instance_geometry const * const instance_geometries,
int const instance_geometries_count); int const instance_geometries_count);
void draw_skin(types::skin const & skin,
types::instance_material const * const instance_materials,
int const instance_materials_count);
void draw_instance_controllers(types::instance_controller const * const instance_controllers,
int const instance_controllers_count,
instance_types::node const * const node_instances);
void draw_node(int32_t node_index, void draw_node(int32_t node_index,
types::node const & node, types::node const & node,
instance_types::node const & node_instance); instance_types::node const & node_instance,
instance_types::node const * const node_instances);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// called by state::update // called by state::update

View File

@ -5,6 +5,15 @@ struct VSInput
float3 Texture : TEXCOORD0; float3 Texture : TEXCOORD0;
}; };
struct VSSkinnedInput
{
float3 Position : POSITION0;
float3 Normal : NORMAL0;
float3 Texture : TEXCOORD0;
int4 BlendIndices : BLENDINDICES0;
float4 BlendWeight : BLENDWEIGHT0;
};
struct VSOutput struct VSOutput
{ {
float4 Position : SV_POSITION; float4 Position : SV_POSITION;
@ -26,6 +35,11 @@ struct Node
column_major float4x4 World; column_major float4x4 World;
}; };
struct Joint
{
column_major float4x4 Transform;
};
struct Scene struct Scene
{ {
column_major float4x4 Projection; column_major float4x4 Projection;
@ -58,6 +72,7 @@ struct MaterialColorImage
// set 0: per-frame // set 0: per-frame
[[vk::binding(0, 0)]] ConstantBuffer<Scene> Scene; [[vk::binding(0, 0)]] ConstantBuffer<Scene> Scene;
[[vk::binding(1, 0)]] StructuredBuffer<Node> Nodes; [[vk::binding(1, 0)]] StructuredBuffer<Node> Nodes;
[[vk::binding(2, 0)]] StructuredBuffer<Joint> Joints;
// set 1: constant // set 1: constant
[[vk::binding(0, 1)]] StructuredBuffer<MaterialColorImage> MaterialColorImages; [[vk::binding(0, 1)]] StructuredBuffer<MaterialColorImage> MaterialColorImages;
@ -72,10 +87,9 @@ struct PushConstant {
[[vk::push_constant]] PushConstant constants; [[vk::push_constant]] PushConstant constants;
float4 getView(float4x4 view, float3 position) float4 getView(float4x4 view, float4 position)
{ {
float4x4 world = Nodes[constants.NodeIndex].World; return mul(view, position);
return mul(view, mul(world, float4(position.xyz, 1.0)));
} }
float4 getProjection(float4x4 projection, float4 viewPosition) float4 getProjection(float4x4 projection, float4 viewPosition)
@ -83,17 +97,40 @@ float4 getProjection(float4x4 projection, float4 viewPosition)
return mul(projection, viewPosition) * float4(-1, -1, 1, 1); return mul(projection, viewPosition) * float4(-1, -1, 1, 1);
} }
[shader("vertex")] float2 yf(float2 v)
VSOutput VSMain(VSInput input)
{ {
float4 viewPosition = getView(Scene.View, input.Position); return float2(v.x, 1.0 - v.y);
float4 shadowPosition = getProjection(Scene.ShadowProjection, getView(Scene.ShadowView, input.Position)); }
float4x4 getWorld(VSSkinnedInput input)
{
float4x4 world
= input.BlendWeight.x * Joints[input.BlendIndices.x].Transform
+ input.BlendWeight.y * Joints[input.BlendIndices.y].Transform
+ input.BlendWeight.z * Joints[input.BlendIndices.z].Transform
+ input.BlendWeight.w * Joints[input.BlendIndices.w].Transform
;
//float4x4 world = Nodes[constants.NodeIndex].World;
return world;
}
[shader("vertex")]
VSOutput VSMain(VSSkinnedInput input)
{
float4x4 world = getWorld(input);
float4 worldPosition = mul(world, float4(input.Position, 1.0));
float4 viewPosition = getView(Scene.View, worldPosition);
float4 shadowPosition = getProjection(Scene.ShadowProjection, getView(Scene.ShadowView, worldPosition));
VSOutput output = (VSOutput)0; VSOutput output = (VSOutput)0;
//output.Position = getProjection(Scene.ShadowProjection, viewPosition);
output.Position = getProjection(Scene.Projection, viewPosition); output.Position = getProjection(Scene.Projection, viewPosition);
output.ShadowPosition = shadowPosition * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0.0, 0.0); output.ShadowPosition = shadowPosition * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0.0, 0.0);
output.Normal = mul((float3x3)Scene.View, mul((float3x3)Nodes[constants.NodeIndex].World, input.Normal)); output.Normal = mul((float3x3)Scene.View, mul((float3x3)Nodes[constants.NodeIndex].World, input.Normal));
output.Texture = input.Texture.xy * 1.0; output.Texture = yf(input.Texture.xy);
output.LightDirection = (Scene.LightPosition - viewPosition).xyz; output.LightDirection = (Scene.LightPosition - viewPosition).xyz;
output.ViewDirection = -viewPosition.xyz; output.ViewDirection = -viewPosition.xyz;
@ -135,17 +172,17 @@ float4 PSMain(VSOutput input) : SV_TARGET
float4 specularColor; float4 specularColor;
float4 emissionColor; float4 emissionColor;
if (MCI.Image.Diffuse >= 0) { if (MCI.Image.Diffuse >= 0) {
diffuseColor = SceneTexture[MCI.Image.Diffuse].Sample(LinearSampler, input.Texture).bgra; diffuseColor = SceneTexture[MCI.Image.Diffuse].Sample(LinearSampler, input.Texture).rgba;
} else { } else {
diffuseColor = MCI.Color.Diffuse; diffuseColor = MCI.Color.Diffuse;
} }
if (MCI.Image.Specular >= 0) { if (MCI.Image.Specular >= 0) {
specularColor = SceneTexture[MCI.Image.Specular].Sample(LinearSampler, input.Texture).bgra; specularColor = SceneTexture[MCI.Image.Specular].Sample(LinearSampler, input.Texture).rgba;
} else { } else {
specularColor = MCI.Color.Specular; specularColor = MCI.Color.Specular;
} }
if (MCI.Image.Emission >= 0) { if (MCI.Image.Emission >= 0) {
emissionColor = SceneTexture[MCI.Image.Emission].Sample(LinearSampler, input.Texture).bgra; emissionColor = SceneTexture[MCI.Image.Emission].Sample(LinearSampler, input.Texture).rgba;
} else { } else {
emissionColor = MCI.Color.Emission; emissionColor = MCI.Color.Emission;
} }
@ -195,7 +232,7 @@ struct GSGeometryOutput
[maxvertexcount(6)] [maxvertexcount(6)]
void GSGeometryMain(triangle VSGeometryOutput input[3], inout LineStream<GSGeometryOutput> outputStream) void GSGeometryMain(triangle VSGeometryOutput input[3], inout LineStream<GSGeometryOutput> outputStream)
{ {
float normalLength = 2.0; float normalLength = 0.1;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
float3 position = input[i].Position.xyz; float3 position = input[i].Position.xyz;
@ -203,11 +240,11 @@ void GSGeometryMain(triangle VSGeometryOutput input[3], inout LineStream<GSGeome
float3 positionNormal = position + normal * normalLength; float3 positionNormal = position + normal * normalLength;
GSGeometryOutput output = (GSGeometryOutput)0; GSGeometryOutput output = (GSGeometryOutput)0;
output.Position = getProjection(Scene.Projection, getView(Scene.View, position)); output.Position = getProjection(Scene.Projection, getView(Scene.View, float4(position, 1.0)));
output.Color = float3(1, 0, 0); output.Color = float3(1, 0, 0);
outputStream.Append(output); outputStream.Append(output);
output.Position = getProjection(Scene.Projection, getView(Scene.View, positionNormal)); output.Position = getProjection(Scene.Projection, getView(Scene.View, float4(positionNormal, 1.0)));
output.Color = float3(0, 1, 0); output.Color = float3(0, 1, 0);
outputStream.Append(output); outputStream.Append(output);
@ -222,9 +259,12 @@ float4 PSGeometryMain(GSGeometryOutput input) : SV_TARGET
} }
[shader("vertex")] [shader("vertex")]
VSShadowOutput VSShadowMain(VSInput input) VSShadowOutput VSShadowMain(VSSkinnedInput input)
{ {
float4 viewPosition = getView(Scene.ShadowView, input.Position); float4x4 world = getWorld(input);
float4 worldPosition = mul(world, float4(input.Position, 1.0));
float4 viewPosition = getView(Scene.ShadowView, worldPosition);
VSShadowOutput output = (VSShadowOutput)0; VSShadowOutput output = (VSShadowOutput)0;
output.Position = getProjection(Scene.ShadowProjection, viewPosition); output.Position = getProjection(Scene.ShadowProjection, viewPosition);

View File

@ -12,6 +12,7 @@ namespace collada::scene {
this->descriptor = descriptor; this->descriptor = descriptor;
vulkan.load_vertex_index_buffer(descriptor->position_normal_texture_buffer, vulkan.load_vertex_index_buffer(descriptor->position_normal_texture_buffer,
descriptor->joint_weight_buffer,
descriptor->index_buffer); descriptor->index_buffer);
vulkan.create_uniform_buffers(descriptor); vulkan.create_uniform_buffers(descriptor);
vulkan.create_descriptor_sets(descriptor); vulkan.create_descriptor_sets(descriptor);
@ -29,13 +30,13 @@ namespace collada::scene {
types::node const & node = *descriptor->nodes[i]; types::node const & node = *descriptor->nodes[i];
instance_types::node const & node_instance = node_state.node_instances[i]; instance_types::node const & node_instance = node_state.node_instances[i];
if (node.instance_geometries_count <= 0) if (node.type != types::node_type::NODE)
continue; continue;
vulkan.draw_node(i, vulkan.draw_node(i,
node, node,
node_instance); node_instance,
node_state.node_instances);
} }
} }
@ -63,7 +64,7 @@ namespace collada::scene {
void state::update(float t) void state::update(float t)
{ {
t = animate::loop(t, 3.3f); t = animate::loop(t, 1.0f);
for (int i = 0; i < descriptor->nodes_count; i++) { for (int i = 0; i < descriptor->nodes_count; i++) {
animate::animate_node(node_state.node_instances[i], t); animate::animate_node(node_state.node_instances[i], t);

View File

@ -79,25 +79,46 @@ inline static void vulkan_vertex_input_states(collada::types::descriptor const *
{ {
for (int i = 0; i < descriptor->inputs_list_count; i++) { for (int i = 0; i < descriptor->inputs_list_count; i++) {
collada::types::inputs const & inputs = descriptor->inputs_list[i]; collada::types::inputs const & inputs = descriptor->inputs_list[i];
VkVertexInputAttributeDescription * vertexAttributeDescriptions = NewM<VkVertexInputAttributeDescription>(inputs.elements_count); VkVertexInputAttributeDescription * vertexAttributeDescriptions = NewM<VkVertexInputAttributeDescription>(inputs.elements_count + collada::inputs::skin_inputs.elements_count);
uint32_t stride = vulkan_load_layout(inputs, uint32_t stride = vulkan_load_layout(inputs,
0, // binding 0, // binding
0, // start_offset 0, // start_offset
vertexAttributeDescriptions); vertexAttributeDescriptions);
vertexBindingDescriptions[i] = { uint32_t vertexJointWeightStride = vulkan_load_layout(collada::inputs::skin_inputs,
1, // binding
0, // start_offset
&vertexAttributeDescriptions[inputs.elements_count]);
vertexBindingDescriptions[i * 2 + 0] = {
.binding = 0, .binding = 0,
.stride = stride, .stride = stride,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
}; };
vertexInputStates[i] = { vertexBindingDescriptions[i * 2 + 1] = {
.binding = 1,
.stride = vertexJointWeightStride,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
};
// non-skinned
vertexInputStates[i * 2 + 0] = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1, .vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &vertexBindingDescriptions[i], .pVertexBindingDescriptions = &vertexBindingDescriptions[i * 2 + 0],
.vertexAttributeDescriptionCount = (uint32_t)inputs.elements_count, .vertexAttributeDescriptionCount = (uint32_t)inputs.elements_count,
.pVertexAttributeDescriptions = vertexAttributeDescriptions, .pVertexAttributeDescriptions = vertexAttributeDescriptions,
}; };
// skinned
vertexInputStates[i * 2 + 1] = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 2,
.pVertexBindingDescriptions = &vertexBindingDescriptions[i * 2 + 0],
.vertexAttributeDescriptionCount = (uint32_t)(inputs.elements_count + collada::inputs::skin_inputs.elements_count),
.pVertexAttributeDescriptions = vertexAttributeDescriptions,
};
} }
} }
@ -136,18 +157,22 @@ namespace collada::scene {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
void vulkan::load_vertex_index_buffer(char const * vertex_filename, void vulkan::load_vertex_index_buffer(char const * vertex_filename,
char const * vertex_joint_weight_filename,
char const * index_filename) char const * index_filename)
{ {
uint32_t vertexSize; uint32_t vertexSize;
void const * vertexStart = file::open(vertex_filename, &vertexSize); void const * vertexStart = file::open(vertex_filename, &vertexSize);
uint32_t vertexJointWeightSize;
void const * vertexJointWeightStart = file::open(vertex_joint_weight_filename, &vertexJointWeightSize);
uint32_t indexSize; uint32_t indexSize;
void const * indexStart = file::open(index_filename, &indexSize); void const * indexStart = file::open(index_filename, &indexSize);
vertexIndex.indexOffset = vertexSize; // + vertexJWStart; vertexIndex.jointWeightOffset = vertexSize;
vertexIndex.indexOffset = vertexSize + vertexJointWeightSize;
// create buffer // create buffer
VkDeviceSize bufferSize{ vertexSize + indexSize }; VkDeviceSize bufferSize{ vertexSize + vertexJointWeightSize + indexSize };
VkBufferCreateInfo vertexIndexBufferCreateInfo{ VkBufferCreateInfo vertexIndexBufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = bufferSize, .size = bufferSize,
@ -180,7 +205,8 @@ namespace collada::scene {
void * vertexIndexMappedData; void * vertexIndexMappedData;
VK_CHECK(vkMapMemory(device, vertexIndex.memory, 0, VK_WHOLE_SIZE, 0, &vertexIndexMappedData)); VK_CHECK(vkMapMemory(device, vertexIndex.memory, 0, VK_WHOLE_SIZE, 0, &vertexIndexMappedData));
memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + 0), vertexStart, vertexSize); memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + 0), vertexStart, vertexSize);
memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + vertexSize), indexStart, indexSize); memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + vertexSize), vertexJointWeightStart, vertexJointWeightSize);
memcpy((void *)(((ptrdiff_t)vertexIndexMappedData) + vertexSize + vertexJointWeightSize), indexStart, indexSize);
VkMappedMemoryRange mappedMemoryRange{ VkMappedMemoryRange mappedMemoryRange{
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
@ -229,6 +255,16 @@ namespace collada::scene {
}; };
VK_CHECK(vkCreateBuffer(device, &nodesBufferCreateInfo, nullptr, &shaderDataDevice.frame[i].nodesBuffer)); VK_CHECK(vkCreateBuffer(device, &nodesBufferCreateInfo, nullptr, &shaderDataDevice.frame[i].nodesBuffer));
vkGetBufferMemoryRequirements(device, shaderDataDevice.frame[i].nodesBuffer, &memoryRequirements[memoryRequirementsIndex++]); vkGetBufferMemoryRequirements(device, shaderDataDevice.frame[i].nodesBuffer, &memoryRequirements[memoryRequirementsIndex++]);
// joints buffer
VkBufferCreateInfo jointsBufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = (sizeof (Joint)) * maxJointsCount,
.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
};
VK_CHECK(vkCreateBuffer(device, &jointsBufferCreateInfo, nullptr, &shaderDataDevice.frame[i].jointsBuffer));
vkGetBufferMemoryRequirements(device, shaderDataDevice.frame[i].jointsBuffer, &memoryRequirements[memoryRequirementsIndex++]);
}; };
// material color buffer // material color buffer
@ -272,6 +308,11 @@ namespace collada::scene {
shaderDataDevice.frame[i].nodesSize = memoryRequirements[offsetsIndex++].size; shaderDataDevice.frame[i].nodesSize = memoryRequirements[offsetsIndex++].size;
shaderDataDevice.frame[i].nodesMapped = (void *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.frame[i].nodesOffset); shaderDataDevice.frame[i].nodesMapped = (void *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.frame[i].nodesOffset);
VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.frame[i].nodesBuffer, shaderDataDevice.memory, shaderDataDevice.frame[i].nodesOffset)); VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.frame[i].nodesBuffer, shaderDataDevice.memory, shaderDataDevice.frame[i].nodesOffset));
shaderDataDevice.frame[i].jointsOffset = offsets[offsetsIndex];
shaderDataDevice.frame[i].jointsSize = memoryRequirements[offsetsIndex++].size;
shaderDataDevice.frame[i].jointsMapped = (void *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.frame[i].jointsOffset);
VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.frame[i].jointsBuffer, shaderDataDevice.memory, shaderDataDevice.frame[i].jointsOffset));
} }
shaderDataDevice.constant.materialColorImagesOffset = offsets[offsetsIndex]; shaderDataDevice.constant.materialColorImagesOffset = offsets[offsetsIndex];
shaderDataDevice.constant.materialColorImagesSize = memoryRequirements[offsetsIndex++].size; shaderDataDevice.constant.materialColorImagesSize = memoryRequirements[offsetsIndex++].size;
@ -294,11 +335,11 @@ namespace collada::scene {
VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{ VkDescriptorPoolSize descriptorPoolSizes[descriptorPoolSizesCount]{
{ {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = maxFrames, .descriptorCount = (maxFrames * 1),
}, },
{ {
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = maxFrames + 1, // +1 for materialColorImages .descriptorCount = (maxFrames * 2) + 1, // +1 for materialColorImages
}, },
{ {
.type = VK_DESCRIPTOR_TYPE_SAMPLER, .type = VK_DESCRIPTOR_TYPE_SAMPLER,
@ -321,7 +362,7 @@ namespace collada::scene {
// uniform buffer descriptor set layout/allocation (set 0, per-frame) // uniform buffer descriptor set layout/allocation (set 0, per-frame)
// //
{ {
constexpr int bindingCount = 2; constexpr int bindingCount = 3;
VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{ VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{
{ {
.binding = 0, .binding = 0,
@ -334,6 +375,12 @@ namespace collada::scene {
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT
},
{
.binding = 2,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT
} }
}; };
@ -418,6 +465,7 @@ namespace collada::scene {
VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames]; VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames];
VkDescriptorBufferInfo nodesDescriptorBufferInfos[maxFrames]; VkDescriptorBufferInfo nodesDescriptorBufferInfos[maxFrames];
VkDescriptorBufferInfo jointsDescriptorBufferInfos[maxFrames];
for (uint32_t i = 0; i < maxFrames; i++) { for (uint32_t i = 0; i < maxFrames; i++) {
sceneDescriptorBufferInfos[i] = { sceneDescriptorBufferInfos[i] = {
@ -446,6 +494,19 @@ namespace collada::scene {
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &nodesDescriptorBufferInfos[i] .pBufferInfo = &nodesDescriptorBufferInfos[i]
}; };
jointsDescriptorBufferInfos[i] = {
.buffer = shaderDataDevice.frame[i].jointsBuffer,
.offset = 0,
.range = shaderDataDevice.frame[i].jointsSize,
};
writeDescriptorSets[writeIndex++] = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptorSets0[i],
.dstBinding = 2,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &jointsDescriptorBufferInfos[i]
};
} }
VkDescriptorBufferInfo materialColorImagesDescriptorBufferInfo{ VkDescriptorBufferInfo materialColorImagesDescriptorBufferInfo{
@ -758,6 +819,15 @@ namespace collada::scene {
.writeMask = 0x01, .writeMask = 0x01,
.reference = 1, .reference = 1,
}, },
.back = {
.failOp = VK_STENCIL_OP_REPLACE,
.passOp = VK_STENCIL_OP_REPLACE,
.depthFailOp = VK_STENCIL_OP_REPLACE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.compareMask = 0x01,
.writeMask = 0x01,
.reference = 1,
},
}; };
VkPipelineRenderingCreateInfo renderingCreateInfo{ VkPipelineRenderingCreateInfo renderingCreateInfo{
@ -786,8 +856,8 @@ namespace collada::scene {
}; };
VkPipelineRasterizationStateCreateInfo rasterizationState{ VkPipelineRasterizationStateCreateInfo rasterizationState{
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.cullMode = VK_CULL_MODE_BACK_BIT, //.cullMode = VK_CULL_MODE_BACK_BIT,
//.cullMode = VK_CULL_MODE_NONE, .cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.lineWidth = 1.0f .lineWidth = 1.0f
}; };
@ -803,8 +873,8 @@ namespace collada::scene {
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
}; };
VkPipelineVertexInputStateCreateInfo * vertexInputStates = NewM<VkPipelineVertexInputStateCreateInfo>(descriptor->inputs_list_count); VkPipelineVertexInputStateCreateInfo * vertexInputStates = NewM<VkPipelineVertexInputStateCreateInfo>(descriptor->inputs_list_count * 2);
VkVertexInputBindingDescription * vertexBindingDescriptions = NewM<VkVertexInputBindingDescription>(descriptor->inputs_list_count); VkVertexInputBindingDescription * vertexBindingDescriptions = NewM<VkVertexInputBindingDescription>(descriptor->inputs_list_count * 2);
vulkan_vertex_input_states(descriptor, vulkan_vertex_input_states(descriptor,
vertexInputStates, vertexInputStates,
vertexBindingDescriptions); vertexBindingDescriptions);
@ -819,7 +889,7 @@ namespace collada::scene {
.pNext = &shadowRenderingCreateInfo, .pNext = &shadowRenderingCreateInfo,
.stageCount = 2, .stageCount = 2,
.pStages = shadowShaderStages, .pStages = shadowShaderStages,
.pVertexInputState = &vertexInputStates[i], .pVertexInputState = &vertexInputStates[i * 2 + 1],
.pInputAssemblyState = &inputAssemblyState, .pInputAssemblyState = &inputAssemblyState,
.pViewportState = &viewportState, .pViewportState = &viewportState,
.pRasterizationState = &shadowRasterizationState, .pRasterizationState = &shadowRasterizationState,
@ -836,7 +906,7 @@ namespace collada::scene {
.pNext = &renderingCreateInfo, .pNext = &renderingCreateInfo,
.stageCount = 2, .stageCount = 2,
.pStages = shaderStages, .pStages = shaderStages,
.pVertexInputState = &vertexInputStates[i], .pVertexInputState = &vertexInputStates[i * 2 + 1],
.pInputAssemblyState = &inputAssemblyState, .pInputAssemblyState = &inputAssemblyState,
.pViewportState = &viewportState, .pViewportState = &viewportState,
.pRasterizationState = &rasterizationState, .pRasterizationState = &rasterizationState,
@ -853,7 +923,7 @@ namespace collada::scene {
.pNext = &renderingCreateInfo, .pNext = &renderingCreateInfo,
.stageCount = 3, .stageCount = 3,
.pStages = geometryShaderStages, .pStages = geometryShaderStages,
.pVertexInputState = &vertexInputStates[i], .pVertexInputState = &vertexInputStates[i * 2 + 1],
.pInputAssemblyState = &inputAssemblyState, .pInputAssemblyState = &inputAssemblyState,
.pViewportState = &viewportState, .pViewportState = &viewportState,
.pRasterizationState = &rasterizationState, .pRasterizationState = &rasterizationState,
@ -872,7 +942,7 @@ namespace collada::scene {
free(vertexBindingDescriptions); free(vertexBindingDescriptions);
for (int i = 0; i < descriptor->inputs_list_count; i++) { for (int i = 0; i < descriptor->inputs_list_count; i++) {
free((void *)vertexInputStates[i].pVertexAttributeDescriptions); free((void *)vertexInputStates[i * 2 + 0].pVertexAttributeDescriptions); // [i * 2 + 1] uses same pointer
} }
free(vertexInputStates); free(vertexInputStates);
} }
@ -885,6 +955,7 @@ namespace collada::scene {
types::instance_material const * const instance_materials, types::instance_material const * const instance_materials,
int const instance_materials_count) int const instance_materials_count)
{ {
assert(false);
types::mesh const& mesh = geometry.mesh; types::mesh const& mesh = geometry.mesh;
vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset + mesh.index_buffer_offset, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset + mesh.index_buffer_offset, VK_INDEX_TYPE_UINT32);
@ -921,6 +992,99 @@ namespace collada::scene {
} }
} }
void vulkan::draw_skin(types::skin const & skin,
types::instance_material const * const instance_materials,
int const instance_materials_count)
{
types::mesh const& mesh = skin.geometry->mesh;
vkCmdBindIndexBuffer(commandBuffer, vertexIndex.buffer, vertexIndex.indexOffset + mesh.index_buffer_offset, VK_INDEX_TYPE_UINT32);
for (int j = 0; j < instance_materials_count; j++) {
types::instance_material const& instance_material = instance_materials[j];
int materialIndex = instance_material.material_index;
if (materialIndex == excludeMaterialIndex) {
continue;
}
types::triangles const& triangles = mesh.triangles[instance_material.element_index];
VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT };
constexpr uint32_t offset{ (offsetof (PushConstant, materialIndex)) };
vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &materialIndex);
VkBuffer buffers[2] = {
vertexIndex.buffer,
vertexIndex.buffer,
};
VkDeviceSize offsets[2] = {
(VkDeviceSize)mesh.vertex_buffer_offset,
vertexIndex.jointWeightOffset + (VkDeviceSize)skin.vertex_buffer_offset,
};
vkCmdBindVertexBuffers(commandBuffer, 0, 2, buffers, offsets);
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[triangles.inputs_index * shaderVariantCount + pipelineIndex]);
uint32_t indexCount = triangles.count * 3;
vkCmdDrawIndexed(commandBuffer, indexCount, 1, triangles.index_offset, 0, 0);
}
}
void vulkan::draw_instance_controllers(types::instance_controller const * const instance_controllers,
int const instance_controllers_count,
instance_types::node const * const node_instances)
{
static Joint joints[maxJointsCount];
for (int i = 0; i < instance_controllers_count; i++) {
types::instance_controller const &instance_controller = instance_controllers[i];
types::skin const &skin = instance_controller.controller->skin;
XMMATRIX bsm = XMLoadFloat4x4((XMFLOAT4X4*)&skin.bind_shape_matrix);
assert((uint32_t)instance_controller.joint_count <= maxJointsCount);
for (int joint_index = 0; joint_index < instance_controller.joint_count; joint_index++) {
XMMATRIX ibm = XMLoadFloat4x4((XMFLOAT4X4*)&skin.inverse_bind_matrices[joint_index]);
int node_index = instance_controller.joint_node_indices[joint_index];
instance_types::node const & node_instance = node_instances[node_index];
XMStoreFloat4x4(&joints[joint_index].transform,
XMMatrixTranspose(bsm) * XMMatrixTranspose(ibm) * node_instance.world);
}
// copy
memcpy(shaderDataDevice.frame[frameIndex].jointsMapped, &joints[0], (sizeof (Joint)) * instance_controller.joint_count);
// flush
VkMappedMemoryRange mappedMemoryRanges[1]{
{
.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
.memory = shaderDataDevice.memory,
.offset = shaderDataDevice.frame[frameIndex].jointsOffset,
.size = shaderDataDevice.frame[frameIndex].jointsSize,
},
};
alignMappedMemoryRanges(physicalDeviceProperties.limits.nonCoherentAtomSize,
shaderDataDevice.memorySize,
1,
mappedMemoryRanges);
vkFlushMappedMemoryRanges(device, 1, mappedMemoryRanges);
/*
int joints_size = (sizeof (XMFLOAT4X4)) * instance_controller.joint_count;
glBindBuffer(GL_UNIFORM_BUFFER, joint_uniform_buffer);
glBufferData(GL_UNIFORM_BUFFER, joints_size, (void *)&joints[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
glBindBufferRange(GL_UNIFORM_BUFFER, layout.binding.joint, joint_uniform_buffer, 0, joints_size);
*/
draw_skin(skin,
instance_controller.instance_materials,
instance_controller.instance_materials_count);
}
}
void vulkan::transfer_transforms(XMMATRIX const & projection, void vulkan::transfer_transforms(XMMATRIX const & projection,
XMMATRIX const & view, XMMATRIX const & view,
XMMATRIX const & shadowProjection, XMMATRIX const & shadowProjection,
@ -970,13 +1134,15 @@ namespace collada::scene {
void vulkan::draw_node(int32_t node_index, void vulkan::draw_node(int32_t node_index,
types::node const & node, types::node const & node,
instance_types::node const & node_instance) instance_types::node const & node_instance,
instance_types::node const * const node_instances)
{ {
VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT }; VkShaderStageFlags stageFlags{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_GEOMETRY_BIT };
constexpr uint32_t offset{ (offsetof (PushConstant, nodeIndex)) }; constexpr uint32_t offset{ (offsetof (PushConstant, nodeIndex)) };
vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &node_index); vkCmdPushConstants(commandBuffer, pipelineLayout, stageFlags, offset, (sizeof (uint32_t)), &node_index);
draw_instance_geometries(node.instance_geometries, node.instance_geometries_count); draw_instance_geometries(node.instance_geometries, node.instance_geometries_count);
draw_instance_controllers(node.instance_controllers, node.instance_controllers_count, node_instances);
} }
void vulkan::change_frame(VkCommandBuffer commandBuffer, uint32_t frameIndex) void vulkan::change_frame(VkCommandBuffer commandBuffer, uint32_t frameIndex)
@ -1012,6 +1178,7 @@ namespace collada::scene {
for (uint32_t i = 0; i < maxFrames; i++) { for (uint32_t i = 0; i < maxFrames; i++) {
vkDestroyBuffer(device, shaderDataDevice.frame[i].sceneBuffer, nullptr); vkDestroyBuffer(device, shaderDataDevice.frame[i].sceneBuffer, nullptr);
vkDestroyBuffer(device, shaderDataDevice.frame[i].nodesBuffer, nullptr); vkDestroyBuffer(device, shaderDataDevice.frame[i].nodesBuffer, nullptr);
vkDestroyBuffer(device, shaderDataDevice.frame[i].jointsBuffer, nullptr);
} }
vkDestroyBuffer(device, shaderDataDevice.constant.materialColorImagesBuffer, nullptr); vkDestroyBuffer(device, shaderDataDevice.constant.materialColorImagesBuffer, nullptr);
vkFreeMemory(device, shaderDataDevice.memory, nullptr); vkFreeMemory(device, shaderDataDevice.memory, nullptr);

View File

@ -19,6 +19,7 @@
#include "collada/scene/vulkan.h" #include "collada/scene/vulkan.h"
#include "scenes/shadow_test/shadow_test.h" #include "scenes/shadow_test/shadow_test.h"
#include "scenes/eidelwind/eidelwind.h"
VkInstance instance{ VK_NULL_HANDLE }; VkInstance instance{ VK_NULL_HANDLE };
VkDevice device{ VK_NULL_HANDLE }; VkDevice device{ VK_NULL_HANDLE };
@ -591,7 +592,7 @@ int main()
textureSamplers[0], textureSamplers[0],
shadowDepthImageViewDepth); shadowDepthImageViewDepth);
collada::types::descriptor const * collada_scene_descriptor = &shadow_test::descriptor; collada::types::descriptor const * collada_scene_descriptor = &eidelwind::descriptor;
collada_state.load_scene(collada_scene_descriptor); collada_state.load_scene(collada_scene_descriptor);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -608,9 +609,10 @@ int main()
int cameraIndex = collada_state.find_node_index_by_name("Camera001"); int cameraIndex = collada_state.find_node_index_by_name("Camera001");
int cameraTargetIndex = collada_state.find_node_index_by_name("Camera001.Target"); int cameraTargetIndex = collada_state.find_node_index_by_name("Camera001.Target");
int lightIndex = collada_state.find_node_index_by_name("DirectLight"); int lightIndex = collada_state.find_node_index_by_name("Camera001");
int lightTargetIndex = collada_state.find_node_index_by_name("DirectLight.Target"); int lightTargetIndex = collada_state.find_node_index_by_name("Torso");
int lightMaterialIndex = collada_state.find_material_index_by_name("LightMaterial"); //int lightMaterialIndex = collada_state.find_material_index_by_name("LightMaterial");
int lightMaterialIndex = -1;
while (quit == false) { while (quit == false) {
SDL_Event event; SDL_Event event;
@ -647,7 +649,7 @@ int main()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
double time = getTime(start_time); double time = getTime(start_time);
collada_state.update(time / 8.0f); collada_state.update(time / 1.5f);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// fence // fence
@ -669,12 +671,37 @@ int main()
}; };
VK_CHECK(vkBeginCommandBuffer(commandBuffer, &commandBufferBeginInfo)); VK_CHECK(vkBeginCommandBuffer(commandBuffer, &commandBufferBeginInfo));
//////////////////////////////////////////////////////////////////////
// transfer
//////////////////////////////////////////////////////////////////////
{
collada_state.vulkan.change_frame(commandBuffer, frameIndex);
XMMATRIX projection = currentProjection();
XMMATRIX view = currentView(collada_state.node_state.node_instances[cameraIndex],
collada_state.node_state.node_instances[cameraTargetIndex]);
XMMATRIX shadowProjection = XMMatrixOrthographicLH(300, 300, 0.1, 500);
XMMATRIX shadowView = currentView(collada_state.node_state.node_instances[lightIndex],
collada_state.node_state.node_instances[lightTargetIndex]);
collada::instance_types::node const & lightNode = collada_state.node_state.node_instances[lightIndex];
XMVECTOR lightPositionWorld = XMVector3Transform(XMVectorZero(), lightNode.world);
collada_state.vulkan.transfer_transforms(projection,
view,
shadowProjection,
shadowView,
lightPositionWorld,
collada_state.descriptor->nodes_count,
collada_state.node_state.node_instances);
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// shadow render // shadow render
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// barrier // barrier
VkImageMemoryBarrier2 shadowBarriers[1]{ VkImageMemoryBarrier2 shadowBarriers[1]{
VkImageMemoryBarrier2{ VkImageMemoryBarrier2{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
@ -739,30 +766,6 @@ int main()
}; };
vkCmdSetScissor(commandBuffer, 0, 1, &shadowScissor); vkCmdSetScissor(commandBuffer, 0, 1, &shadowScissor);
// transfer
{
collada_state.vulkan.change_frame(commandBuffer, frameIndex);
XMMATRIX projection = currentProjection();
XMMATRIX view = currentView(collada_state.node_state.node_instances[cameraIndex],
collada_state.node_state.node_instances[cameraTargetIndex]);
XMMATRIX shadowProjection = XMMatrixOrthographicLH(300, 300, 0.1, 500);
XMMATRIX shadowView = currentView(collada_state.node_state.node_instances[lightIndex],
collada_state.node_state.node_instances[lightTargetIndex]);
collada::instance_types::node const & lightNode = collada_state.node_state.node_instances[lightIndex];
XMVECTOR lightPositionWorld = XMVector3Transform(XMVectorZero(), lightNode.world);
collada_state.vulkan.transfer_transforms(projection,
view,
shadowProjection,
shadowView,
lightPositionWorld,
collada_state.descriptor->nodes_count,
collada_state.node_state.node_instances);
}
// draw // draw
collada_state.vulkan.excludeMaterialIndex = lightMaterialIndex; collada_state.vulkan.excludeMaterialIndex = lightMaterialIndex;
@ -889,8 +892,8 @@ int main()
collada_state.vulkan.excludeMaterialIndex = -1; collada_state.vulkan.excludeMaterialIndex = -1;
collada_state.vulkan.pipelineIndex = 1; // non-shadow pipeline collada_state.vulkan.pipelineIndex = 1; // non-shadow pipeline
collada_state.draw(); collada_state.draw();
collada_state.vulkan.pipelineIndex = 2; // geometry shader pipeline //collada_state.vulkan.pipelineIndex = 2; // geometry shader pipeline
collada_state.draw(); //collada_state.draw();
vkCmdEndRendering(commandBuffer); vkCmdEndRendering(commandBuffer);

1
texconv.sh Normal file
View File

@ -0,0 +1 @@
WINEDEBUG=-all wine $HOME/Texconv.exe -nogpu -nowic -dx10 --format BC7_UNORM_SRGB $1