// Physics.cpp (implementation)
void PhysicsSystem::InitializeVulkanResources() {
// Get Vulkan device from the engine
auto& device = m_Engine.GetVulkanDevice();
// Create compute shader modules
auto integrateShaderCode = LoadShaderFile("shaders/physics_integrate.comp.spv");
vk::ShaderModuleCreateInfo integrateShaderModuleCreateInfo({}, integrateShaderCode.size() * sizeof(uint32_t),
reinterpret_cast<const uint32_t*>(integrateShaderCode.data()));
m_VulkanResources.integrateShaderModule = vk::raii::ShaderModule(device, integrateShaderModuleCreateInfo);
auto broadPhaseShaderCode = LoadShaderFile("shaders/physics_broad_phase.comp.spv");
vk::ShaderModuleCreateInfo broadPhaseShaderModuleCreateInfo({}, broadPhaseShaderCode.size() * sizeof(uint32_t),
reinterpret_cast<const uint32_t*>(broadPhaseShaderCode.data()));
m_VulkanResources.broadPhaseShaderModule = vk::raii::ShaderModule(device, broadPhaseShaderModuleCreateInfo);
auto narrowPhaseShaderCode = LoadShaderFile("shaders/physics_narrow_phase.comp.spv");
vk::ShaderModuleCreateInfo narrowPhaseShaderModuleCreateInfo({}, narrowPhaseShaderCode.size() * sizeof(uint32_t),
reinterpret_cast<const uint32_t*>(narrowPhaseShaderCode.data()));
m_VulkanResources.narrowPhaseShaderModule = vk::raii::ShaderModule(device, narrowPhaseShaderModuleCreateInfo);
auto resolveShaderCode = LoadShaderFile("shaders/physics_resolve.comp.spv");
vk::ShaderModuleCreateInfo resolveShaderModuleCreateInfo({}, resolveShaderCode.size() * sizeof(uint32_t),
reinterpret_cast<const uint32_t*>(resolveShaderCode.data()));
m_VulkanResources.resolveShaderModule = vk::raii::ShaderModule(device, resolveShaderModuleCreateInfo);
// Create descriptor set layout
std::array<vk::DescriptorSetLayoutBinding, 4> bindings = {
// Physics data buffer
vk::DescriptorSetLayoutBinding(0, vk::DescriptorType::eStorageBuffer, 1,
vk::ShaderStageFlagBits::eCompute),
// Collision data buffer
vk::DescriptorSetLayoutBinding(1, vk::DescriptorType::eStorageBuffer, 1,
vk::ShaderStageFlagBits::eCompute),
// Pair buffer (for broad phase)
vk::DescriptorSetLayoutBinding(2, vk::DescriptorType::eStorageBuffer, 1,
vk::ShaderStageFlagBits::eCompute),
// Counter buffer
vk::DescriptorSetLayoutBinding(3, vk::DescriptorType::eStorageBuffer, 1,
vk::ShaderStageFlagBits::eCompute)
};
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo({}, bindings);
m_VulkanResources.descriptorSetLayout = vk::raii::DescriptorSetLayout(device, descriptorSetLayoutCreateInfo);
// Create pipeline layout
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo({}, *m_VulkanResources.descriptorSetLayout);
m_VulkanResources.pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutCreateInfo);
// Create compute pipelines
vk::PipelineShaderStageCreateInfo integrateShaderStageCreateInfo({}, vk::ShaderStageFlagBits::eCompute,
*m_VulkanResources.integrateShaderModule, "main");
vk::ComputePipelineCreateInfo integrateComputePipelineCreateInfo({}, integrateShaderStageCreateInfo,
*m_VulkanResources.pipelineLayout);
m_VulkanResources.integratePipeline = vk::raii::Pipeline(device, nullptr, integrateComputePipelineCreateInfo);
vk::PipelineShaderStageCreateInfo broadPhaseShaderStageCreateInfo({}, vk::ShaderStageFlagBits::eCompute,
*m_VulkanResources.broadPhaseShaderModule, "main");
vk::ComputePipelineCreateInfo broadPhaseComputePipelineCreateInfo({}, broadPhaseShaderStageCreateInfo,
*m_VulkanResources.pipelineLayout);
m_VulkanResources.broadPhasePipeline = vk::raii::Pipeline(device, nullptr, broadPhaseComputePipelineCreateInfo);
vk::PipelineShaderStageCreateInfo narrowPhaseShaderStageCreateInfo({}, vk::ShaderStageFlagBits::eCompute,
*m_VulkanResources.narrowPhaseShaderModule, "main");
vk::ComputePipelineCreateInfo narrowPhaseComputePipelineCreateInfo({}, narrowPhaseShaderStageCreateInfo,
*m_VulkanResources.pipelineLayout);
m_VulkanResources.narrowPhasePipeline = vk::raii::Pipeline(device, nullptr, narrowPhaseComputePipelineCreateInfo);
vk::PipelineShaderStageCreateInfo resolveShaderStageCreateInfo({}, vk::ShaderStageFlagBits::eCompute,
*m_VulkanResources.resolveShaderModule, "main");
vk::ComputePipelineCreateInfo resolveComputePipelineCreateInfo({}, resolveShaderStageCreateInfo,
*m_VulkanResources.pipelineLayout);
m_VulkanResources.resolvePipeline = vk::raii::Pipeline(device, nullptr, resolveComputePipelineCreateInfo);
// Create descriptor pool
std::array<vk::DescriptorPoolSize, 1> poolSizes = {
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 4)
};
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo({}, 1, poolSizes);
m_VulkanResources.descriptorPool = vk::raii::DescriptorPool(device, descriptorPoolCreateInfo);
// Allocate descriptor sets
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo(*m_VulkanResources.descriptorPool,
1, &*m_VulkanResources.descriptorSetLayout);
m_VulkanResources.descriptorSets = vk::raii::DescriptorSets(device, descriptorSetAllocateInfo);
// Create buffers for physics data
CreateBuffer(device, sizeof(GPUPhysicsData) * m_MaxGPUObjects,
vk::BufferUsageFlagBits::eStorageBuffer,
m_VulkanResources.physicsBuffer, m_VulkanResources.physicsBufferMemory);
CreateBuffer(device, sizeof(GPUCollisionData) * m_MaxGPUCollisions,
vk::BufferUsageFlagBits::eStorageBuffer,
m_VulkanResources.collisionBuffer, m_VulkanResources.collisionBufferMemory);
CreateBuffer(device, sizeof(uint32_t) * 2 * m_MaxGPUCollisions,
vk::BufferUsageFlagBits::eStorageBuffer,
m_VulkanResources.pairBuffer, m_VulkanResources.pairBufferMemory);
CreateBuffer(device, sizeof(uint32_t) * 2,
vk::BufferUsageFlagBits::eStorageBuffer,
m_VulkanResources.counterBuffer, m_VulkanResources.counterBufferMemory);
// Update descriptor sets
std::array<vk::DescriptorBufferInfo, 4> bufferInfos = {
vk::DescriptorBufferInfo(*m_VulkanResources.physicsBuffer, 0, VK_WHOLE_SIZE),
vk::DescriptorBufferInfo(*m_VulkanResources.collisionBuffer, 0, VK_WHOLE_SIZE),
vk::DescriptorBufferInfo(*m_VulkanResources.pairBuffer, 0, VK_WHOLE_SIZE),
vk::DescriptorBufferInfo(*m_VulkanResources.counterBuffer, 0, VK_WHOLE_SIZE)
};
std::array<vk::WriteDescriptorSet, 4> descriptorWrites = {
vk::WriteDescriptorSet(*m_VulkanResources.descriptorSets[0], 0, 0, 1,
vk::DescriptorType::eStorageBuffer, nullptr, &bufferInfos[0]),
vk::WriteDescriptorSet(*m_VulkanResources.descriptorSets[0], 1, 0, 1,
vk::DescriptorType::eStorageBuffer, nullptr, &bufferInfos[1]),
vk::WriteDescriptorSet(*m_VulkanResources.descriptorSets[0], 2, 0, 1,
vk::DescriptorType::eStorageBuffer, nullptr, &bufferInfos[2]),
vk::WriteDescriptorSet(*m_VulkanResources.descriptorSets[0], 3, 0, 1,
vk::DescriptorType::eStorageBuffer, nullptr, &bufferInfos[3])
};
device.updateDescriptorSets(descriptorWrites, {});
// Create command pool and command buffer
vk::CommandPoolCreateInfo commandPoolCreateInfo({}, m_Engine.GetVulkanQueueFamilyIndex());
m_VulkanResources.commandPool = vk::raii::CommandPool(device, commandPoolCreateInfo);
vk::CommandBufferAllocateInfo commandBufferAllocateInfo(*m_VulkanResources.commandPool,
vk::CommandBufferLevel::ePrimary, 1);
auto commandBuffers = vk::raii::CommandBuffers(device, commandBufferAllocateInfo);
m_VulkanResources.commandBuffer = std::move(commandBuffers[0]);
// Initialize counter buffer
uint32_t initialCounters[2] = { 0, 0 }; // [0] = pair count, [1] = collision count
void* data;
vkMapMemory(device, *m_VulkanResources.counterBufferMemory, 0, sizeof(initialCounters), 0, &data);
memcpy(data, initialCounters, sizeof(initialCounters));
vkUnmapMemory(device, *m_VulkanResources.counterBufferMemory);
}
void PhysicsSystem::UpdateGPUPhysicsData() {
auto& device = m_Engine.GetVulkanDevice();
// Map the physics buffer
void* data;
vkMapMemory(device, *m_VulkanResources.physicsBufferMemory, 0,
sizeof(GPUPhysicsData) * m_RigidBodies.size(), 0, &data);
// Copy physics data to the buffer
GPUPhysicsData* gpuData = static_cast<GPUPhysicsData*>(data);
for (size_t i = 0; i < m_RigidBodies.size(); i++) {
auto& body = m_RigidBodies[i];
gpuData[i].position = glm::vec4(body->GetPosition(), body->GetInverseMass());
gpuData[i].rotation = glm::vec4(body->GetRotation().x, body->GetRotation().y,
body->GetRotation().z, body->GetRotation().w);
gpuData[i].linearVelocity = glm::vec4(body->GetLinearVelocity(), body->GetRestitution());
gpuData[i].angularVelocity = glm::vec4(body->GetAngularVelocity(), body->GetFriction());
gpuData[i].force = glm::vec4(body->m_AccumulatedForce, body->IsKinematic() ? 1.0f : 0.0f);
gpuData[i].torque = glm::vec4(body->m_AccumulatedTorque, body->IsGravityEnabled() ? 1.0f : 0.0f);
// Set collider data based on collider type
auto collider = body->GetCollider();
if (collider) {
switch (collider->GetType()) {
case ColliderType::Sphere: {
auto sphereCollider = std::static_pointer_cast<SphereCollider>(collider);
gpuData[i].colliderData = glm::vec4(sphereCollider->GetRadius(), 0.0f, 0.0f,
static_cast<float>(ColliderType::Sphere));
gpuData[i].colliderData2 = glm::vec4(collider->GetOffset(), 0.0f);
break;
}
case ColliderType::Box: {
auto boxCollider = std::static_pointer_cast<BoxCollider>(collider);
gpuData[i].colliderData = glm::vec4(boxCollider->GetHalfExtents(),
static_cast<float>(ColliderType::Box));
gpuData[i].colliderData2 = glm::vec4(collider->GetOffset(), 0.0f);
break;
}
default:
// Unsupported collider type
gpuData[i].colliderData = glm::vec4(0.0f, 0.0f, 0.0f, -1.0f);
gpuData[i].colliderData2 = glm::vec4(0.0f);
break;
}
} else {
// No collider
gpuData[i].colliderData = glm::vec4(0.0f, 0.0f, 0.0f, -1.0f);
gpuData[i].colliderData2 = glm::vec4(0.0f);
}
}
vkUnmapMemory(device, *m_VulkanResources.physicsBufferMemory);
// Reset counters
uint32_t initialCounters[2] = { 0, 0 }; // [0] = pair count, [1] = collision count
vkMapMemory(device, *m_VulkanResources.counterBufferMemory, 0, sizeof(initialCounters), 0, &data);
memcpy(data, initialCounters, sizeof(initialCounters));
vkUnmapMemory(device, *m_VulkanResources.counterBufferMemory);
}
void PhysicsSystem::ReadbackGPUPhysicsData() {
auto& device = m_Engine.GetVulkanDevice();
// Map the physics buffer
void* data;
vkMapMemory(device, *m_VulkanResources.physicsBufferMemory, 0,
sizeof(GPUPhysicsData) * m_RigidBodies.size(), 0, &data);
// Copy physics data from the buffer
GPUPhysicsData* gpuData = static_cast<GPUPhysicsData*>(data);
for (size_t i = 0; i < m_RigidBodies.size(); i++) {
auto& body = m_RigidBodies[i];
// Skip kinematic bodies
if (body->IsKinematic()) {
continue;
}
body->SetPosition(glm::vec3(gpuData[i].position));
body->SetRotation(glm::quat(gpuData[i].rotation.w, gpuData[i].rotation.x,
gpuData[i].rotation.y, gpuData[i].rotation.z));
body->SetLinearVelocity(glm::vec3(gpuData[i].linearVelocity));
body->SetAngularVelocity(glm::vec3(gpuData[i].angularVelocity));
}
vkUnmapMemory(device, *m_VulkanResources.physicsBufferMemory);
}
void PhysicsSystem::SimulatePhysicsOnGPU(float deltaTime) {
auto& device = m_Engine.GetVulkanDevice();
auto& queue = m_Engine.GetVulkanComputeQueue();
// Update physics data on the GPU
UpdateGPUPhysicsData();
// Record command buffer
vk::CommandBufferBeginInfo beginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
m_VulkanResources.commandBuffer.begin(beginInfo);
// Bind descriptor set
m_VulkanResources.commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
*m_VulkanResources.pipelineLayout, 0,
*m_VulkanResources.descriptorSets[0], {});
// Push constants for simulation parameters
struct {
float deltaTime;
float gravity[3];
uint32_t numBodies;
} pushConstants;
pushConstants.deltaTime = deltaTime;
pushConstants.gravity[0] = m_Gravity.x;
pushConstants.gravity[1] = m_Gravity.y;
pushConstants.gravity[2] = m_Gravity.z;
pushConstants.numBodies = static_cast<uint32_t>(m_RigidBodies.size());
m_VulkanResources.commandBuffer.pushConstants(*m_VulkanResources.pipelineLayout,
vk::ShaderStageFlagBits::eCompute, 0,
sizeof(pushConstants), &pushConstants);
// Step 1: Integrate forces and velocities
m_VulkanResources.commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute,
*m_VulkanResources.integratePipeline);
m_VulkanResources.commandBuffer.dispatch((pushConstants.numBodies + 63) / 64, 1, 1);
// Memory barrier to ensure integration is complete before collision detection
vk::MemoryBarrier memoryBarrier(vk::AccessFlagBits::eShaderWrite, vk::AccessFlagBits::eShaderRead);
m_VulkanResources.commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eComputeShader,
{}, memoryBarrier, {}, {});
// Step 2: Broad-phase collision detection
m_VulkanResources.commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute,
*m_VulkanResources.broadPhasePipeline);
// Each thread checks one pair of objects
uint32_t numPairs = (pushConstants.numBodies * (pushConstants.numBodies - 1)) / 2;
m_VulkanResources.commandBuffer.dispatch((numPairs + 63) / 64, 1, 1);
// Memory barrier to ensure broad phase is complete before narrow phase
m_VulkanResources.commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eComputeShader,
{}, memoryBarrier, {}, {});
// Step 3: Narrow-phase collision detection
m_VulkanResources.commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute,
*m_VulkanResources.narrowPhasePipeline);
// We don't know how many pairs were generated, so we use a conservative estimate
m_VulkanResources.commandBuffer.dispatch((m_MaxGPUCollisions + 63) / 64, 1, 1);
// Memory barrier to ensure narrow phase is complete before resolution
m_VulkanResources.commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader,
vk::PipelineStageFlagBits::eComputeShader,
{}, memoryBarrier, {}, {});
// Step 4: Collision resolution
m_VulkanResources.commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute,
*m_VulkanResources.resolvePipeline);
// We don't know how many collisions were detected, so we use a conservative estimate
m_VulkanResources.commandBuffer.dispatch((m_MaxGPUCollisions + 63) / 64, 1, 1);
m_VulkanResources.commandBuffer.end();
// Submit command buffer
vk::SubmitInfo submitInfo({}, {}, *m_VulkanResources.commandBuffer);
queue.submit(submitInfo, nullptr);
queue.waitIdle();
// Read back physics data from the GPU
ReadbackGPUPhysicsData();
}
void PhysicsSystem::Update(float deltaTime) {
if (m_GPUAccelerationEnabled && m_RigidBodies.size() <= m_MaxGPUObjects) {
// Use GPU-accelerated physics
SimulatePhysicsOnGPU(deltaTime);
} else {
// Fall back to CPU physics
// ... existing CPU physics code ...
}
}