Files
face_sdk/vulkan/FaceApp.cpp
T

299 lines
8.8 KiB
C++

#include "FaceApp.h"
#include "hardcode_data.h"
#include <sstream>
FaceApp* FaceApp::faceIns = nullptr;
FaceApp::FaceApp(/* args */)
{
faceIns = this;
}
FaceApp::~FaceApp()
{
}
bool FaceApp::LoadOBJ(const std::string& filename,
std::vector<TextureLoadingVertexStructure>& vertices,
std::vector<uint32_t>& indices) {
// 临时存储从OBJ文件读取的原始数据
std::vector<float> temp_positions;
std::vector<float> temp_texcoords;
std::vector<float> temp_normals;
// 用于处理顶点索引
std::vector<int> vertexIndices, uvIndices, normalIndices;
std::vector<char> data = readFile(filename);
// 将 vector<char> 转换为以 null 结尾的字符串(安全做法)
std::string content(data.begin(), data.end());
std::istringstream iss(content); // 用字符串创建字符串流
std::string line;
while (std::getline(iss, line)) {
// 跳过空行和注释行
if (line.empty() || line[0] == '#') {
continue;
}
std::istringstream iss(line);
std::string type;
iss >> type;
if (type == "v") { // 顶点位置
float x, y, z;
iss >> x >> y >> z;
temp_positions.push_back(x);
temp_positions.push_back(y);
temp_positions.push_back(z);
}
else if (type == "vt") { // 纹理坐标
float u, v;
iss >> u >> v;
temp_texcoords.push_back(u);
temp_texcoords.push_back(1 - v);
}
else if (type == "vn") { // 法线
float nx, ny, nz;
iss >> nx >> ny >> nz;
temp_normals.push_back(nx);
temp_normals.push_back(ny);
temp_normals.push_back(nz);
}
else if (type == "f") { // 面(三角形)
std::string vertex1, vertex2, vertex3;
iss >> vertex1 >> vertex2 >> vertex3;
// 处理每个顶点的索引
for (const std::string& vertex : { vertex1, vertex2, vertex3 }) {
std::istringstream viss(vertex);
std::string v, vt, vn;
// 解析顶点索引格式:v/vt/vn 或 v//vn 或 v
std::getline(viss, v, '/');
std::getline(viss, vt, '/');
std::getline(viss, vn, '/');
int posIndex = std::stoi(v) - 1; // OBJ索引从1开始
int texIndex = -1, normIndex = -1;
if (!vt.empty()) texIndex = std::stoi(vt) - 1;
if (!vn.empty()) normIndex = std::stoi(vn) - 1;
vertexIndices.push_back(posIndex);
uvIndices.push_back(texIndex);
normalIndices.push_back(normIndex);
}
}
}
// 创建顶点数据
vertices.clear();
indices.clear();
// 用于去重的哈希映射
std::map<std::string, uint32_t> vertexMap;
for (size_t i = 0; i < vertexIndices.size(); i++) {
int posIndex = vertexIndices[i];
int texIndex = uvIndices[i];
int normIndex = normalIndices[i];
// 创建唯一标识符
std::string vertexKey = std::to_string(posIndex) + "/" +
std::to_string(texIndex) + "/" +
std::to_string(normIndex);
// 检查是否已经存在相同的顶点
if (vertexMap.find(vertexKey) != vertexMap.end()) {
// 使用现有顶点的索引
indices.push_back(vertexMap[vertexKey]);
}
else {
// 创建新顶点
TextureLoadingVertexStructure vertex;
// 设置位置
if (posIndex >= 0 && posIndex * 3 + 2 < temp_positions.size()) {
vertex.pos[0] = temp_positions[posIndex * 3];
vertex.pos[1] = temp_positions[posIndex * 3 + 1];
vertex.pos[2] = temp_positions[posIndex * 3 + 2];
}
else {
vertex.pos[0] = vertex.pos[1] = vertex.pos[2] = 0.0f;
}
// 设置纹理坐标
if (texIndex >= 0 && texIndex * 2 + 1 < temp_texcoords.size()) {
vertex.uv[0] = temp_texcoords[texIndex * 2];
vertex.uv[1] = temp_texcoords[texIndex * 2 + 1];
}
else {
vertex.uv[0] = vertex.uv[1] = 0.0f;
}
// 设置法线
if (normIndex >= 0 && normIndex * 3 + 2 < temp_normals.size()) {
vertex.normal[0] = temp_normals[normIndex * 3];
vertex.normal[1] = temp_normals[normIndex * 3 + 1];
vertex.normal[2] = temp_normals[normIndex * 3 + 2];
}
else {
vertex.normal[0] = vertex.normal[1] = 0.0f;
vertex.normal[2] = 1.0f; // 默认法线
}
// 添加新顶点并记录索引
uint32_t newIndex = static_cast<uint32_t>(vertices.size());
vertices.push_back(vertex);
indices.push_back(newIndex);
obj_vertices_map[newIndex] = posIndex;
vertexMap[vertexKey] = newIndex;
}
}
return true;
}
void FaceApp::render(VkCommandBuffer commandBuffer)
{
Application::render(commandBuffer);
}
void FaceApp::initVulkan()
{
Application::initVulkan();
VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.physicalDevice = physicalDevice;
allocatorInfo.device = device;
allocatorInfo.instance = instance;
vmaCreateAllocator(&allocatorInfo, &allocator);
createVertexBuffer();
LoadOBJ("face_picture_3dmax.obj", obj_vertices, obj_indices);
uploadVertexData();
}
void FaceApp::createVertexBuffer()
{
VkDeviceSize vertexBufferSize = sizeof(TextureLoadingVertexStructure) * obj_vertices.capacity();
VkDeviceSize indexBufferSize = sizeof(uint32_t) * obj_indices.capacity();
// 创建顶点缓冲区(设备本地,用于渲染)
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = vertexBufferSize;
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocInfo = {};
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &m_vertexBuffer, &m_vertexBufferAllocation, nullptr);
// 创建暂存缓冲区(CPU可见,用于上传数据)
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &m_stagingBuffer, &m_stagingBufferAllocation, nullptr);
// 创建索引缓冲区
bufferInfo.size = indexBufferSize;
bufferInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, &m_indexBuffer, &m_indexBufferAllocation, nullptr);
}
void ReceiveFacePoint(float* pos, int pointCount, int width, int height)
{
FaceApp* self = FaceApp::Get();
if (self != nullptr)
{
FaceApp::Get()->update_face_vertex_buffer(pos, pointCount);
}
}
void FaceApp::update_face_vertex_buffer(float* pos, int pointCount)
{
std::lock_guard<std::mutex> lock(mtx_point);
last_update_time = getCurrentTimeMillis();
for (int i = 0; i < obj_vertices.size(); ++i)
{
int face_index = obj_vertices_map[HardCodeData::Get().indexMap[i]];
float x = pos[face_index * 3 + 0];
float y = pos[face_index * 3 + 1];
float z = pos[face_index * 3 + 2];
obj_vertices[i].pos[0] = x;
obj_vertices[i].pos[1] = y;
obj_vertices[i].pos[2] = z;
}
uploadVertexData();
}
void FaceApp::uploadVertexData() {
// 上传顶点数据
void* data;
vmaMapMemory(allocator, m_stagingBufferAllocation, &data);
memcpy(data, obj_vertices.data(), sizeof(TextureLoadingVertexStructure) * obj_vertices.size());
vmaUnmapMemory(allocator, m_stagingBufferAllocation);
// 复制到设备内存
copyBuffer(m_stagingBuffer, m_vertexBuffer, sizeof(TextureLoadingVertexStructure) * obj_vertices.size());
// 上传索引数据(如果需要暂存缓冲区,可以创建另一个)
vmaMapMemory(allocator, m_stagingBufferAllocation, &data);
memcpy(data, obj_indices.data(), sizeof(uint32_t) * obj_indices.size());
vmaUnmapMemory(allocator, m_stagingBufferAllocation);
copyBuffer(m_stagingBuffer, m_indexBuffer, sizeof(uint32_t) * obj_indices.size());
}
void FaceApp::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
{
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkBufferCopy copyRegion = {};
copyRegion.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
endSingleTimeCommands(commandBuffer);
}
VkCommandBuffer FaceApp::beginSingleTimeCommands() {
VkCommandBufferAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
VkCommandBufferBeginInfo beginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
return commandBuffer;
}
void FaceApp::endSingleTimeCommands(VkCommandBuffer commandBuffer) {
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(graphicsQueue);
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
}