/** * Loads a 3D model from a file into Vulkan buffers * * @param device Pointer to the Vulkan device used to generated the vertex and index buffers on * @param filename File to load (must be a model format supported by ASSIMP) * @param layout Vertex layout components (position, normals, tangents, etc.) * @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc. * @param copyQueue Queue used for the memory staging copy commands (must support transfer) * @param (Optional) flags ASSIMP model loading flags */ //public bool loadFromFile(string filename, vksVertexLayout layout, vksModelCreateInfo* createInfo, vksVulkanDevice device, VkQueue copyQueue, int flags) //{ // this.device = device.LogicalDevice; // ObjFile objFile; // using (var fs = File.OpenRead(filename)) // { // objFile = new ObjParser().Parse(fs); // } // string mtlFilename = Path.ChangeExtension(filename, "mtl"); // MtlFile mtlFile; // using (var fs = File.OpenRead(mtlFilename)) // { // mtlFile = new MtlParser().Parse(fs); // } // if (objFile != null) // { // parts.Clear(); // parts.Resize((uint)objFile.MeshGroups.Length); // Vector3 scale = new Vector3(1.0f); // Vector2 uvscale = new Vector2(1.0f); // Vector3 center = new Vector3(0.0f); // if (createInfo != null) // { // scale = createInfo->Scale; // uvscale = createInfo->UVScale; // center = createInfo->Center; // } // NativeList<float> vertexBuffer = new NativeList<float>(); // NativeList<uint> indexBuffer = new NativeList<uint>(); // vertexCount = 0; // indexCount = 0; // // Load meshes // parts.Count = (uint)objFile.MeshGroups.Length; // for (uint i = 0; i < objFile.MeshGroups.Length; i++) // { // ConstructedMeshInfo mesh = objFile.GetMesh(objFile.MeshGroups[i]); // parts[i] = new ModelPart(); // parts[i].vertexBase = vertexCount; // parts[i].indexBase = indexCount; // vertexCount += (uint)mesh.Vertices.Length; // var material = mtlFile.Definitions[objFile.MeshGroups[i].Material]; // Vector3 pColor = material.DiffuseReflectivity; // Vector3 Zero3D = Vector3.Zero; // for (uint j = 0; j < mesh.Vertices.Length; j++) // { // VertexPositionNormalTexture vertex = mesh.Vertices[j]; // Vector3* pPos = &vertex.Position; // Vector3* pNormal = &vertex.Normal; // Vector2* pTexCoord = &vertex.TextureCoordinates; // Vector3* pTangent = &Zero3D; // Vector3* pBiTangent = &Zero3D; // /* // const aiVector3D* pPos = &(paiMesh->mVertices[j]); // const aiVector3D* pNormal = &(paiMesh->mNormals[j]); // const aiVector3D* pTexCoord = (paiMesh->HasTextureCoords(0)) ? &(paiMesh->mTextureCoords[0][j]) : &Zero3D; // const aiVector3D* pTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mTangents[j]) : &Zero3D; // const aiVector3D* pBiTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mBitangents[j]) : &Zero3D; // */ // foreach (var component in layout.Components) // { // switch (component) // { // case VertexComponent.VERTEX_COMPONENT_POSITION: // vertexBuffer.Add(pPos.X * scale.X + center.X); // vertexBuffer.Add(-pPos.Y * scale.Y + center.Y); // vertexBuffer.Add(pPos.Z * scale.Z + center.Z); // break; // case VertexComponent.VERTEX_COMPONENT_NORMAL: // vertexBuffer.Add(pNormal.X); // vertexBuffer.Add(-pNormal.Y); // vertexBuffer.Add(pNormal.Z); // break; // case VertexComponent.VERTEX_COMPONENT_UV: // vertexBuffer.Add(pTexCoord.X * uvscale.X); // vertexBuffer.Add(pTexCoord.Y * uvscale.Y); // break; // case VertexComponent.VERTEX_COMPONENT_COLOR: // vertexBuffer.Add(pColor.X); // vertexBuffer.Add(pColor.Y); // vertexBuffer.Add(pColor.Z); // break; // case VertexComponent.VERTEX_COMPONENT_TANGENT: // vertexBuffer.Add(pTangent.X); // vertexBuffer.Add(pTangent.Y); // vertexBuffer.Add(pTangent.Z); // break; // case VertexComponent.VERTEX_COMPONENT_BITANGENT: // vertexBuffer.Add(pBiTangent.X); // vertexBuffer.Add(pBiTangent.Y); // vertexBuffer.Add(pBiTangent.Z); // break; // // Dummy components for padding // case VertexComponent.VERTEX_COMPONENT_DUMMY_FLOAT: // vertexBuffer.Add(0.0f); // break; // case VertexComponent.VERTEX_COMPONENT_DUMMY_VEC4: // vertexBuffer.Add(0.0f); // vertexBuffer.Add(0.0f); // vertexBuffer.Add(0.0f); // vertexBuffer.Add(0.0f); // break; // }; // } // dim.Max.X = Math.Max(pPos.X, dim.Max.X); // dim.Max.Y = Math.Max(pPos.Y, dim.Max.Y); // dim.Max.Z = Math.Max(pPos.Z, dim.Max.Z); // dim.Min.X = Math.Min(pPos.X, dim.Min.X); // dim.Min.Y = Math.Min(pPos.Y, dim.Min.Y); // dim.Min.Z = Math.Min(pPos.Z, dim.Min.Z); // } // dim.Size = dim.Max - dim.Min; // parts[i].vertexCount = (uint)mesh.Vertices.Length; // uint indexBase = indexBuffer.Count; // foreach (var index in mesh.Indices) // { // indexBuffer.Add(index); // } // indexCount += (uint)mesh.Indices.Length; // parts[i].indexCount += (uint)mesh.Indices.Length; // /* // for (uint j = 0; j < paiMesh->mNumFaces; j++) // { // const aiFace&Face = paiMesh->mFaces[j]; // if (Face.mNumIndices != 3) // continue; // indexBuffer.Add(indexBase + Face.mIndices[0]); // indexBuffer.Add(indexBase + Face.mIndices[1]); // indexBuffer.Add(indexBase + Face.mIndices[2]); // parts[i].indexCount += 3; // indexCount += 3; // } // */ // } // uint vBufferSize = vertexBuffer.Count * sizeof(float); // uint iBufferSize = indexBuffer.Count * sizeof(uint); // // Use staging buffer to move vertex and index buffer to device local memory // // Create staging buffers // vksBuffer vertexStaging = new vksBuffer(); // vksBuffer indexStaging = new vksBuffer(); // // Vertex buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.TransferSrc, // VkMemoryPropertyFlags.HostVisible, // vertexStaging, // vBufferSize, // vertexBuffer.Data.ToPointer())); // // Index buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.TransferSrc, // VkMemoryPropertyFlags.HostVisible, // indexStaging, // iBufferSize, // indexBuffer.Data.ToPointer())); // // Create device local target buffers // // Vertex buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, // VkMemoryPropertyFlags.DeviceLocal, // vertices, // vBufferSize)); // // Index buffer // Util.CheckResult(device.createBuffer( // VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, // VkMemoryPropertyFlags.DeviceLocal, // indices, // iBufferSize)); // // Copy from staging buffers // VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true); // VkBufferCopy copyRegion = new VkBufferCopy(); // copyRegion.size = vertices.size; // vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, ©Region); // copyRegion.size = indices.size; // vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, ©Region); // device.flushCommandBuffer(copyCmd, copyQueue); // // Destroy staging resources // vkDestroyBuffer(device.LogicalDevice, vertexStaging.buffer, null); // vkFreeMemory(device.LogicalDevice, vertexStaging.memory, null); // vkDestroyBuffer(device.LogicalDevice, indexStaging.buffer, null); // vkFreeMemory(device.LogicalDevice, indexStaging.memory, null); // return true; // } // else // { // Console.WriteLine("Error loading file."); // return false; // } //} /** * Loads a 3D model from a file into Vulkan buffers * * @param device Pointer to the Vulkan device used to generated the vertex and index buffers on * @param filename File to load (must be a model format supported by ASSIMP) * @param layout Vertex layout components (position, normals, tangents, etc.) * @param createInfo MeshCreateInfo structure for load time settings like scale, center, etc. * @param copyQueue Queue used for the memory staging copy commands (must support transfer) * @param (Optional) flags ASSIMP model loading flags */ bool loadFromFile(string filename, vksVertexLayout layout, vksModelCreateInfo *createInfo, vksVulkanDevice device, VkQueue copyQueue, PostProcessSteps flags = DefaultPostProcessSteps) { this.device = device.LogicalDevice; // Load file var assimpContext = new AssimpContext(); var pScene = assimpContext.ImportFile(filename, flags); parts.Clear(); parts.Count = (uint)pScene.Meshes.Count; Vector3 scale = new Vector3(1.0f); Vector2 uvscale = new Vector2(1.0f); Vector3 center = new Vector3(0.0f); if (createInfo != null) { scale = createInfo->Scale; uvscale = createInfo->UVScale; center = createInfo->Center; } NativeList <float> vertexBuffer = new NativeList <float>(); NativeList <uint> indexBuffer = new NativeList <uint>(); vertexCount = 0; indexCount = 0; // Load meshes for (int i = 0; i < pScene.Meshes.Count; i++) { var paiMesh = pScene.Meshes[i]; parts[i] = new ModelPart(); parts[i].vertexBase = vertexCount; parts[i].indexBase = indexCount; vertexCount += (uint)paiMesh.VertexCount; var pColor = pScene.Materials[paiMesh.MaterialIndex].ColorDiffuse; Vector3D Zero3D = new Vector3D(0.0f, 0.0f, 0.0f); for (int j = 0; j < paiMesh.VertexCount; j++) { Vector3D pPos = paiMesh.Vertices[j]; Vector3D pNormal = paiMesh.Normals[j]; Vector3D pTexCoord = paiMesh.HasTextureCoords(0) ? paiMesh.TextureCoordinateChannels[0][j] : Zero3D; Vector3D pTangent = paiMesh.HasTangentBasis ? paiMesh.Tangents[j] : Zero3D; Vector3D pBiTangent = paiMesh.HasTangentBasis ? paiMesh.BiTangents[j] : Zero3D; foreach (var component in layout.Components) { switch (component) { case VertexComponent.VERTEX_COMPONENT_POSITION: vertexBuffer.Add(pPos.X * scale.X + center.X); vertexBuffer.Add(-pPos.Y * scale.Y + center.Y); vertexBuffer.Add(pPos.Z * scale.Z + center.Z); break; case VertexComponent.VERTEX_COMPONENT_NORMAL: vertexBuffer.Add(pNormal.X); vertexBuffer.Add(-pNormal.Y); vertexBuffer.Add(pNormal.Z); break; case VertexComponent.VERTEX_COMPONENT_UV: vertexBuffer.Add(pTexCoord.X * uvscale.X); vertexBuffer.Add(pTexCoord.Y * uvscale.Y); break; case VertexComponent.VERTEX_COMPONENT_COLOR: vertexBuffer.Add(pColor.R); vertexBuffer.Add(pColor.G); vertexBuffer.Add(pColor.B); break; case VertexComponent.VERTEX_COMPONENT_TANGENT: vertexBuffer.Add(pTangent.X); vertexBuffer.Add(pTangent.Y); vertexBuffer.Add(pTangent.Z); break; case VertexComponent.VERTEX_COMPONENT_BITANGENT: vertexBuffer.Add(pBiTangent.X); vertexBuffer.Add(pBiTangent.Y); vertexBuffer.Add(pBiTangent.Z); break; // Dummy components for padding case VertexComponent.VERTEX_COMPONENT_DUMMY_FLOAT: vertexBuffer.Add(0.0f); break; case VertexComponent.VERTEX_COMPONENT_DUMMY_VEC4: vertexBuffer.Add(0.0f); vertexBuffer.Add(0.0f); vertexBuffer.Add(0.0f); vertexBuffer.Add(0.0f); break; } ; } dim.Max.X = (float)Math.Max(pPos.X, dim.Max.X); dim.Max.Y = (float)Math.Max(pPos.Y, dim.Max.Y); dim.Max.Z = (float)Math.Max(pPos.Z, dim.Max.Z); dim.Min.X = (float)Math.Min(pPos.X, dim.Min.X); dim.Min.Y = (float)Math.Min(pPos.Y, dim.Min.Y); dim.Min.Z = (float)Math.Min(pPos.Z, dim.Min.Z); } dim.Size = dim.Max - dim.Min; parts[i].vertexCount = (uint)paiMesh.VertexCount; uint indexBase = indexBuffer.Count; for (uint j = 0; j < paiMesh.FaceCount; j++) { var Face = paiMesh.Faces[(int)j]; if (Face.IndexCount != 3) { continue; } indexBuffer.Add(indexBase + (uint)Face.Indices[0]); indexBuffer.Add(indexBase + (uint)Face.Indices[1]); indexBuffer.Add(indexBase + (uint)Face.Indices[2]); parts[i].indexCount += 3; indexCount += 3; } } uint vBufferSize = (vertexBuffer.Count) * sizeof(float); uint iBufferSize = (indexBuffer.Count) * sizeof(uint); // Use staging buffer to move vertex and index buffer to device local memory // Create staging buffers vksBuffer vertexStaging = new vksBuffer(); vksBuffer indexStaging = new vksBuffer(); // Vertex buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible, vertexStaging, vBufferSize, vertexBuffer.Data.ToPointer())); // Index buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.TransferSrc, VkMemoryPropertyFlags.HostVisible, indexStaging, iBufferSize, indexBuffer.Data.ToPointer())); // Create device local target buffers // Vertex buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.VertexBuffer | VkBufferUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, vertices, vBufferSize)); // Index buffer Util.CheckResult(device.createBuffer( VkBufferUsageFlags.IndexBuffer | VkBufferUsageFlags.TransferDst, VkMemoryPropertyFlags.DeviceLocal, indices, iBufferSize)); // Copy from staging buffers VkCommandBuffer copyCmd = device.createCommandBuffer(VkCommandBufferLevel.Primary, true); VkBufferCopy copyRegion = new VkBufferCopy(); copyRegion.size = vertices.size; vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, ©Region); copyRegion.size = indices.size; vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, ©Region); device.flushCommandBuffer(copyCmd, copyQueue); // Destroy staging resources vkDestroyBuffer(device.LogicalDevice, vertexStaging.buffer, null); vkFreeMemory(device.LogicalDevice, vertexStaging.memory, null); vkDestroyBuffer(device.LogicalDevice, indexStaging.buffer, null); vkFreeMemory(device.LogicalDevice, indexStaging.memory, null); return(true); }
/** * Create a buffer on the device * * @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer) * @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent) * @param buffer Pointer to a vk::Vulkan buffer object * @param size Size of the buffer in byes * @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over) * * @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied */ public VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vksBuffer buffer, ulong size, void *data = null) { buffer.device = _logicalDevice; // Create the buffer handle VkBufferCreateInfo bufferCreateInfo = VkBufferCreateInfo.New(); bufferCreateInfo.usage = usageFlags; bufferCreateInfo.size = size; Util.CheckResult(vkCreateBuffer(_logicalDevice, &bufferCreateInfo, null, out buffer.buffer)); // Create the memory backing up the buffer handle VkMemoryRequirements memReqs; VkMemoryAllocateInfo memAlloc = VkMemoryAllocateInfo.New(); vkGetBufferMemoryRequirements(_logicalDevice, buffer.buffer, &memReqs); memAlloc.allocationSize = memReqs.size; // Find a memory type index that fits the properties of the buffer memAlloc.memoryTypeIndex = GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags); Util.CheckResult(vkAllocateMemory(_logicalDevice, &memAlloc, null, out buffer.memory)); buffer.alignment = memReqs.alignment; buffer.size = memAlloc.allocationSize; buffer.usageFlags = usageFlags; buffer.memoryPropertyFlags = memoryPropertyFlags; // If a pointer to the buffer data has been passed, map the buffer and copy over the data if (data != null) { Util.CheckResult(buffer.map()); Unsafe.CopyBlock(buffer.mapped, data, (uint)size); buffer.unmap(); } // Initialize a default descriptor that covers the whole buffer size buffer.setupDescriptor(); // Attach the memory to the buffer object return(buffer.bind()); }
public VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vksBuffer buffer, ulong size, IntPtr data) => createBuffer(usageFlags, memoryPropertyFlags, buffer, size, data.ToPointer());