Starting to integrate mesh optimizer
This commit is contained in:
@@ -45,6 +45,8 @@ find_package(Ktx CONFIG REQUIRED)
|
|||||||
find_package(nlohmann_json CONFIG REQUIRED)
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
find_package(fmt CONFIG REQUIRED)
|
find_package(fmt CONFIG REQUIRED)
|
||||||
find_package(lunasvg CONFIG REQUIRED)
|
find_package(lunasvg CONFIG REQUIRED)
|
||||||
|
find_package(metis CONFIG REQUIRED)
|
||||||
|
find_package(meshoptimizer CONFIG REQUIRED)
|
||||||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
@@ -73,6 +75,8 @@ target_link_libraries(Engine PUBLIC crcpp)
|
|||||||
target_link_libraries(Engine PUBLIC fmt::fmt)
|
target_link_libraries(Engine PUBLIC fmt::fmt)
|
||||||
target_link_libraries(Engine PUBLIC lunasvg::lunasvg)
|
target_link_libraries(Engine PUBLIC lunasvg::lunasvg)
|
||||||
target_link_libraries(Engine PUBLIC GPUOpen::VulkanMemoryAllocator)
|
target_link_libraries(Engine PUBLIC GPUOpen::VulkanMemoryAllocator)
|
||||||
|
target_link_libraries(Engine PUBLIC metis)
|
||||||
|
target_link_libraries(Engine PUBLIC meshoptimizer::meshoptimizer)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(Engine PUBLIC ${VCPKG_BASE_FOLDER}/lib/slang.lib)
|
target_link_libraries(Engine PUBLIC ${VCPKG_BASE_FOLDER}/lib/slang.lib)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
|
|||||||
@@ -1,57 +1,58 @@
|
|||||||
const static float3 vertices[] = {
|
const static float3 vertices[] = {
|
||||||
// Right
|
// Right
|
||||||
|
float3( 1, -1, 1),
|
||||||
float3( 1, 1, 1),
|
float3( 1, 1, 1),
|
||||||
float3( 1, -1, 1),
|
|
||||||
float3( 1, 1, -1),
|
|
||||||
|
|
||||||
float3( 1, 1, -1),
|
|
||||||
float3( 1, -1, 1),
|
|
||||||
float3( 1, -1, -1),
|
float3( 1, -1, -1),
|
||||||
|
|
||||||
|
float3( 1, -1, -1),
|
||||||
|
float3( 1, 1, 1),
|
||||||
|
float3( 1, 1, -1),
|
||||||
|
|
||||||
// Left
|
// Left
|
||||||
|
float3(-1, -1, -1),
|
||||||
float3(-1, 1, -1),
|
float3(-1, 1, -1),
|
||||||
float3(-1, -1, -1),
|
|
||||||
float3(-1, 1, 1),
|
|
||||||
|
|
||||||
float3(-1, 1, 1),
|
|
||||||
float3(-1, -1, -1),
|
|
||||||
float3(-1, -1, 1),
|
float3(-1, -1, 1),
|
||||||
|
|
||||||
|
float3(-1, -1, 1),
|
||||||
|
float3(-1, 1, -1),
|
||||||
|
float3(-1, 1, 1),
|
||||||
|
|
||||||
// Bottom
|
// Bottom
|
||||||
float3(-1, -1, 1),
|
float3(-1, 1, 1),
|
||||||
float3(-1, -1, -1),
|
float3(-1, 1, -1),
|
||||||
float3( 1, -1, 1),
|
float3( 1, 1, 1),
|
||||||
|
|
||||||
float3( 1, -1, 1),
|
float3( 1, 1, 1),
|
||||||
float3(-1, -1, -1),
|
float3(-1, 1, -1),
|
||||||
float3( 1, -1, -1),
|
float3( 1, 1, -1),
|
||||||
|
|
||||||
// Top
|
// Top
|
||||||
float3(-1, 1, -1),
|
float3(-1, -1, -1),
|
||||||
float3(-1, 1, 1),
|
|
||||||
float3( 1, 1, -1),
|
|
||||||
|
|
||||||
float3( 1, 1, -1),
|
|
||||||
float3(-1, 1, 1),
|
|
||||||
float3( 1, 1, 1),
|
|
||||||
|
|
||||||
// Back
|
|
||||||
float3(-1, 1, 1),
|
|
||||||
float3(-1, -1, 1),
|
float3(-1, -1, 1),
|
||||||
float3( 1, 1, 1),
|
float3( 1, -1, -1),
|
||||||
|
|
||||||
float3( 1, 1, 1),
|
float3( 1, -1, -1),
|
||||||
float3(-1, -1, 1),
|
float3(-1, -1, 1),
|
||||||
float3( 1, -1, 1),
|
float3( 1, -1, 1),
|
||||||
|
|
||||||
// Front
|
// Front
|
||||||
float3( 1, 1, -1),
|
|
||||||
float3( 1, -1, -1),
|
float3( 1, -1, -1),
|
||||||
|
float3( 1, 1, -1),
|
||||||
|
float3(-1, -1, -1),
|
||||||
|
|
||||||
|
float3(-1, -1, -1),
|
||||||
|
float3( 1, 1, -1),
|
||||||
float3(-1, 1, -1),
|
float3(-1, 1, -1),
|
||||||
|
|
||||||
float3(-1, 1, -1),
|
// Back
|
||||||
float3( 1, -1, -1),
|
float3(-1, -1, 1),
|
||||||
float3(-1, -1, -1),
|
float3(-1, 1, 1),
|
||||||
|
float3( 1, -1, 1),
|
||||||
|
|
||||||
|
float3( 1, -1, 1),
|
||||||
|
float3(-1, 1, 1),
|
||||||
|
float3( 1, 1, 1),
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ViewParams
|
struct ViewParams
|
||||||
@@ -80,7 +81,7 @@ VertexOutput vertMain(uint vertexIndex : SV_VertexID, uint viewIndex : SV_ViewID
|
|||||||
const static float2 invAtan = float2(0.1591, 0.3183);
|
const static float2 invAtan = float2(0.1591, 0.3183);
|
||||||
float2 sampleSphericalMap(float3 v)
|
float2 sampleSphericalMap(float3 v)
|
||||||
{
|
{
|
||||||
float2 uv = float2(atan2(v.z, v.x), asin(v.y));
|
float2 uv = float2(atan2(-v.z, v.x), asin(v.y));
|
||||||
uv *= invAtan;
|
uv *= invAtan;
|
||||||
uv += 0.5;
|
uv += 0.5;
|
||||||
return uv;
|
return uv;
|
||||||
|
|||||||
+58
-57
@@ -1,5 +1,62 @@
|
|||||||
import Common;
|
import Common;
|
||||||
|
|
||||||
|
const static float3 vertices[] = {
|
||||||
|
// Right
|
||||||
|
float3(512, -512, 512),
|
||||||
|
float3(512, 512, 512),
|
||||||
|
float3(512, -512, -512),
|
||||||
|
|
||||||
|
float3(512, -512, -512),
|
||||||
|
float3(512, 512, 512),
|
||||||
|
float3(512, 512, -512),
|
||||||
|
|
||||||
|
// Left
|
||||||
|
float3(-512, -512, -512),
|
||||||
|
float3(-512, 512, -512),
|
||||||
|
float3(-512, -512, 512),
|
||||||
|
|
||||||
|
float3(-512, -512, 512),
|
||||||
|
float3(-512, 512, -512),
|
||||||
|
float3(-512, 512, 512),
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
float3(-512, 512, 512),
|
||||||
|
float3(-512, 512, -512),
|
||||||
|
float3(512, 512, 512),
|
||||||
|
|
||||||
|
float3(512, 512, 512),
|
||||||
|
float3(-512, 512, -512),
|
||||||
|
float3(512, 512, -512),
|
||||||
|
|
||||||
|
// Top
|
||||||
|
float3(-512, -512, -512),
|
||||||
|
float3(-512, -512, 512),
|
||||||
|
float3(512, -512, -512),
|
||||||
|
|
||||||
|
float3(512, -512, -512),
|
||||||
|
float3(-512, -512, 512),
|
||||||
|
float3(512, -512, 512),
|
||||||
|
|
||||||
|
// Front
|
||||||
|
float3(512, -512, -512),
|
||||||
|
float3(512, 512, -512),
|
||||||
|
float3(-512, -512, -512),
|
||||||
|
|
||||||
|
float3(-512, -512, -512),
|
||||||
|
float3(512, 512, -512),
|
||||||
|
float3(-512, 512, -512),
|
||||||
|
|
||||||
|
// Back
|
||||||
|
float3(-512, -512, 512),
|
||||||
|
float3(-512, 512, 512),
|
||||||
|
float3(512, -512, 512),
|
||||||
|
|
||||||
|
float3(512, -512, 512),
|
||||||
|
float3(-512, 512, 512),
|
||||||
|
float3(512, 512, 512),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct VertexShaderOutput
|
struct VertexShaderOutput
|
||||||
{
|
{
|
||||||
float4 clipPos : SV_Position;
|
float4 clipPos : SV_Position;
|
||||||
@@ -12,62 +69,6 @@ struct SkyboxData
|
|||||||
};
|
};
|
||||||
ParameterBlock<SkyboxData> pSkyboxData;
|
ParameterBlock<SkyboxData> pSkyboxData;
|
||||||
|
|
||||||
const static float3 vertices[] = {
|
|
||||||
// Back
|
|
||||||
float3(-512, -512, 512),
|
|
||||||
float3(-512, 512, 512),
|
|
||||||
float3( 512, -512, 512),
|
|
||||||
|
|
||||||
float3( 512, -512, 512),
|
|
||||||
float3(-512, 512, 512),
|
|
||||||
float3( 512, 512, 512),
|
|
||||||
|
|
||||||
// Front
|
|
||||||
float3( 512, -512, -512),
|
|
||||||
float3( 512, 512, -512),
|
|
||||||
float3(-512, -512, -512),
|
|
||||||
|
|
||||||
float3(-512, -512, -512),
|
|
||||||
float3( 512, 512, -512),
|
|
||||||
float3(-512, 512, -512),
|
|
||||||
|
|
||||||
// Top
|
|
||||||
float3(-512, -512, -512),
|
|
||||||
float3(-512, -512, 512),
|
|
||||||
float3( 512, -512, -512),
|
|
||||||
|
|
||||||
float3( 512, -512, -512),
|
|
||||||
float3(-512, -512, 512),
|
|
||||||
float3( 512, -512, 512),
|
|
||||||
|
|
||||||
// Bottom
|
|
||||||
float3(-512, 512, 512),
|
|
||||||
float3(-512, 512, -512),
|
|
||||||
float3( 512, 512, 512),
|
|
||||||
|
|
||||||
float3( 512, 512, 512),
|
|
||||||
float3(-512, 512, -512),
|
|
||||||
float3( 512, 512, -512),
|
|
||||||
|
|
||||||
// Left
|
|
||||||
float3(-512, -512, -512),
|
|
||||||
float3(-512, 512, -512),
|
|
||||||
float3(-512, -512, 512),
|
|
||||||
|
|
||||||
float3(-512, -512, 512),
|
|
||||||
float3(-512, 512, -512),
|
|
||||||
float3(-512, 512, 512),
|
|
||||||
|
|
||||||
// Right
|
|
||||||
float3( 512, -512, 512),
|
|
||||||
float3( 512, 512, 512),
|
|
||||||
float3( 512, -512, -512),
|
|
||||||
|
|
||||||
float3( 512, -512, -512),
|
|
||||||
float3( 512, 512, 512),
|
|
||||||
float3( 512, 512, -512),
|
|
||||||
};
|
|
||||||
|
|
||||||
[shader("vertex")]
|
[shader("vertex")]
|
||||||
VertexShaderOutput vertexMain(
|
VertexShaderOutput vertexMain(
|
||||||
uint vertexIndex : SV_VertexId)
|
uint vertexIndex : SV_VertexId)
|
||||||
@@ -101,5 +102,5 @@ float4 fragmentMain(
|
|||||||
|
|
||||||
float factor = (output.texCoords.y - lowerLimit) / (upperLimit - lowerLimit);
|
float factor = (output.texCoords.y - lowerLimit) / (upperLimit - lowerLimit);
|
||||||
factor = clamp(factor, 0.0, 1.0);
|
factor = clamp(factor, 0.0, 1.0);
|
||||||
return lerp(float4(pSkyboxData.fogBlend.xyz, 1), finalColor, factor);
|
return finalColor;//lerp(float4(pSkyboxData.fogBlend.xyz, 1), finalColor, factor);
|
||||||
}
|
}
|
||||||
@@ -113,5 +113,5 @@ float4 toneMapping(float2 uv : UV) : SV_Target
|
|||||||
value = agxLook(value);
|
value = agxLook(value);
|
||||||
value = agxEotf(value);
|
value = agxEotf(value);
|
||||||
|
|
||||||
return float4(hdrValue, 1);
|
return float4(value, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ ConstantBuffer<DrawCallOffsets> pOffsets;
|
|||||||
|
|
||||||
struct Scene
|
struct Scene
|
||||||
{
|
{
|
||||||
|
StructuredBuffer<float> positions;
|
||||||
|
StructuredBuffer<uint> indexBuffer;
|
||||||
StructuredBuffer<InstanceData> instances;
|
StructuredBuffer<InstanceData> instances;
|
||||||
StructuredBuffer<MeshData> meshData;
|
StructuredBuffer<MeshData> meshData;
|
||||||
StructuredBuffer<MeshletDescription> meshletInfos;
|
StructuredBuffer<MeshletDescription> meshletInfos;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Common;
|
import Common;
|
||||||
import VertexData;
|
import VertexData;
|
||||||
import MaterialParameter;
|
import MaterialParameter;
|
||||||
|
import Scene;
|
||||||
|
|
||||||
struct StaticMeshVertexData : IVertexData
|
struct StaticMeshVertexData : IVertexData
|
||||||
{
|
{
|
||||||
@@ -12,7 +13,7 @@ struct StaticMeshVertexData : IVertexData
|
|||||||
VertexAttributes getAttributes(uint index)
|
VertexAttributes getAttributes(uint index)
|
||||||
{
|
{
|
||||||
VertexAttributes attributes;
|
VertexAttributes attributes;
|
||||||
attributes.position_MS = float3(positions[index * 3 + 0], positions[index * 3 + 1], positions[index * 3 + 2]);
|
attributes.position_MS = float3(pScene.positions[index * 3 + 0], pScene.positions[index * 3 + 1], pScene.positions[index * 3 + 2]);
|
||||||
#ifndef POS_ONLY
|
#ifndef POS_ONLY
|
||||||
//attributes.qTangent = qTangent[index];
|
//attributes.qTangent = qTangent[index];
|
||||||
attributes.normal_MS = float3(normals[index * 3 + 0], normals[index * 3 + 1], normals[index * 3 + 2]);
|
attributes.normal_MS = float3(normals[index * 3 + 0], normals[index * 3 + 1], normals[index * 3 + 2]);
|
||||||
@@ -26,7 +27,6 @@ struct StaticMeshVertexData : IVertexData
|
|||||||
#endif
|
#endif
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
StructuredBuffer<float> positions;
|
|
||||||
//StructuredBuffer<float> qTangents;
|
//StructuredBuffer<float> qTangents;
|
||||||
StructuredBuffer<float> normals;
|
StructuredBuffer<float> normals;
|
||||||
StructuredBuffer<float> tangents;
|
StructuredBuffer<float> tangents;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic
|
|||||||
.size = {SOURCE_RESOLUTION, SOURCE_RESOLUTION},
|
.size = {SOURCE_RESOLUTION, SOURCE_RESOLUTION},
|
||||||
.offset = {0, 0},
|
.offset = {0, 0},
|
||||||
},
|
},
|
||||||
|
.fieldOfView = glm::radians(90.0f),
|
||||||
});
|
});
|
||||||
convolutionViewport = graphics->createViewport(nullptr, ViewportCreateInfo{
|
convolutionViewport = graphics->createViewport(nullptr, ViewportCreateInfo{
|
||||||
.dimensions =
|
.dimensions =
|
||||||
@@ -23,6 +24,7 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic
|
|||||||
.size = {CONVOLUTED_RESOLUTION, CONVOLUTED_RESOLUTION},
|
.size = {CONVOLUTED_RESOLUTION, CONVOLUTED_RESOLUTION},
|
||||||
.offset = {0, 0},
|
.offset = {0, 0},
|
||||||
},
|
},
|
||||||
|
.fieldOfView = glm::radians(90.0f),
|
||||||
});
|
});
|
||||||
cubeSampler = graphics->createSampler({
|
cubeSampler = graphics->createSampler({
|
||||||
.magFilter = Gfx::SE_FILTER_LINEAR,
|
.magFilter = Gfx::SE_FILTER_LINEAR,
|
||||||
@@ -106,7 +108,7 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset
|
|||||||
.height = (uint32)height,
|
.height = (uint32)height,
|
||||||
.name = "HDRRaw",
|
.name = "HDRRaw",
|
||||||
});
|
});
|
||||||
Matrix4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f);
|
Matrix4 captureProjection = cubeRenderViewport->getProjectionMatrix(0.1f, 10.0f);
|
||||||
Matrix4 captureViews[] = {
|
Matrix4 captureViews[] = {
|
||||||
glm::lookAt(Vector(0.0f, 0.0f, 0.0f), Vector(1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)),
|
glm::lookAt(Vector(0.0f, 0.0f, 0.0f), Vector(1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)),
|
||||||
glm::lookAt(Vector(0.0f, 0.0f, 0.0f), Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)),
|
glm::lookAt(Vector(0.0f, 0.0f, 0.0f), Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)),
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ Vector4 MeshLoader::encodeQTangent(Matrix3 m) {
|
|||||||
}
|
}
|
||||||
void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialInstanceAsset>& materials, Array<OMesh>& globalMeshes,
|
void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialInstanceAsset>& materials, Array<OMesh>& globalMeshes,
|
||||||
Component::Collider& collider) {
|
Component::Collider& collider) {
|
||||||
List<std::function<void()>> work;
|
//List<std::function<void()>> work;
|
||||||
for (uint32 meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) {
|
for (uint32 meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) {
|
||||||
aiMesh* mesh = scene->mMeshes[meshIndex];
|
aiMesh* mesh = scene->mMeshes[meshIndex];
|
||||||
if (!(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE))
|
if (!(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE))
|
||||||
@@ -527,9 +527,9 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialIns
|
|||||||
uint64 offset = vertexData->getMeshOffset(id);
|
uint64 offset = vertexData->getMeshOffset(id);
|
||||||
collider.boundingbox.adjust(Vector(mesh->mAABB.mMin.x, mesh->mAABB.mMin.y, mesh->mAABB.mMin.z));
|
collider.boundingbox.adjust(Vector(mesh->mAABB.mMin.x, mesh->mAABB.mMin.y, mesh->mAABB.mMin.z));
|
||||||
collider.boundingbox.adjust(Vector(mesh->mAABB.mMax.x, mesh->mAABB.mMax.y, mesh->mAABB.mMax.z));
|
collider.boundingbox.adjust(Vector(mesh->mAABB.mMax.x, mesh->mAABB.mMax.y, mesh->mAABB.mMax.z));
|
||||||
work.add([=, this, &globalMeshes]() {
|
//work.add([=, this, &globalMeshes]() {
|
||||||
// assume static mesh for now
|
// assume static mesh for now
|
||||||
Array<StaticMeshVertexData::PositionType> positions(mesh->mNumVertices);
|
Array<Vector> positions(mesh->mNumVertices);
|
||||||
StaticArray<Array<StaticMeshVertexData::TexCoordType>, MAX_TEXCOORDS> texCoords;
|
StaticArray<Array<StaticMeshVertexData::TexCoordType>, MAX_TEXCOORDS> texCoords;
|
||||||
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
||||||
texCoords[i].resize(mesh->mNumVertices);
|
texCoords[i].resize(mesh->mNumVertices);
|
||||||
@@ -572,7 +572,6 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialIns
|
|||||||
colors[i] = StaticMeshVertexData::ColorType(1, 1, 1);
|
colors[i] = StaticMeshVertexData::ColorType(1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vertexData->loadPositions(offset, positions);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
||||||
vertexData->loadTexCoords(offset, i, texCoords[i]);
|
vertexData->loadTexCoords(offset, i, texCoords[i]);
|
||||||
@@ -589,10 +588,7 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialIns
|
|||||||
indices[faceIndex * 3 + 2] = mesh->mFaces[faceIndex].mIndices[2];
|
indices[faceIndex * 3 + 2] = mesh->mFaces[faceIndex].mIndices[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Meshlet> meshlets;
|
vertexData->loadMesh(id, std::move(positions), std::move(indices));
|
||||||
meshlets.reserve(indices.size() / (3ull * Gfx::numPrimitivesPerMeshlet));
|
|
||||||
Meshlet::build(positions, indices, meshlets);
|
|
||||||
vertexData->loadMesh(id, indices, meshlets);
|
|
||||||
|
|
||||||
// collider.physicsMesh.addCollider(positions, indices, Matrix4(1.0f));
|
// collider.physicsMesh.addCollider(positions, indices, Matrix4(1.0f));
|
||||||
|
|
||||||
@@ -604,9 +600,9 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialIns
|
|||||||
.mesh = globalMeshes[meshIndex],
|
.mesh = globalMeshes[meshIndex],
|
||||||
});
|
});
|
||||||
vertexData->registerBottomLevelAccelerationStructure(globalMeshes[meshIndex]->blas);
|
vertexData->registerBottomLevelAccelerationStructure(globalMeshes[meshIndex]->blas);
|
||||||
});
|
//});
|
||||||
}
|
}
|
||||||
getThreadPool().runAndWait(std::move(work));
|
//getThreadPool().runAndWait(std::move(work));
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4 convertMatrix(aiMatrix4x4 matrix) {
|
Matrix4 convertMatrix(aiMatrix4x4 matrix) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ DirectionalLightActor::DirectionalLightActor(PScene scene, Vector color, float i
|
|||||||
float angle = std::acos(dot); // angle between vectors
|
float angle = std::acos(dot); // angle between vectors
|
||||||
rotation = glm::angleAxis(angle, axis);
|
rotation = glm::angleAxis(angle, axis);
|
||||||
}
|
}
|
||||||
attachComponent<Component::Transform>(Math::Transform(Vector(0, 0, 0), rotation));
|
getTransform().setRotation(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectionalLightActor::~DirectionalLightActor() {}
|
DirectionalLightActor::~DirectionalLightActor() {}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ PointLightActor::PointLightActor(PScene scene) : Actor(scene) { attachComponent<
|
|||||||
|
|
||||||
PointLightActor::PointLightActor(PScene scene, Vector position, float intensity, Vector color, float attenuation) : Actor(scene) {
|
PointLightActor::PointLightActor(PScene scene, Vector position, float intensity, Vector color, float attenuation) : Actor(scene) {
|
||||||
attachComponent<Component::PointLight>(color, intensity, attenuation);
|
attachComponent<Component::PointLight>(color, intensity, attenuation);
|
||||||
attachComponent<Component::Transform>(Math::Transform(position));
|
getTransform().setPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
PointLightActor::~PointLightActor() {}
|
PointLightActor::~PointLightActor() {}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ static constexpr uint32 numFramesBuffered = 3;
|
|||||||
|
|
||||||
static constexpr uint32 numVerticesPerMeshlet = 256;
|
static constexpr uint32 numVerticesPerMeshlet = 256;
|
||||||
static constexpr uint32 numPrimitivesPerMeshlet = 256;
|
static constexpr uint32 numPrimitivesPerMeshlet = 256;
|
||||||
|
static constexpr uint32 numMeshletsPerTask = 256;
|
||||||
double getCurrentFrameDelta();
|
double getCurrentFrameDelta();
|
||||||
double getCurrentFrameTime();
|
double getCurrentFrameTime();
|
||||||
uint32 getCurrentFrameIndex();
|
uint32 getCurrentFrameIndex();
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
#include "Containers/List.h"
|
#include "Containers/List.h"
|
||||||
#include "Containers/Map.h"
|
#include "Containers/Map.h"
|
||||||
#include "Containers/Set.h"
|
#include "Containers/Set.h"
|
||||||
|
#include <CRC.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <meshoptimizer.h>
|
||||||
|
#include <metis.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
@@ -185,32 +188,5 @@ bool addTriangle(const Array<Vector>& positions, Meshlet& current, Triangle& tri
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Meshlet::build(const Array<Vector>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets) {
|
void Meshlet::build(const Array<Vector>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets) {
|
||||||
Meshlet current = {
|
|
||||||
.numVertices = 0,
|
|
||||||
.numPrimitives = 0,
|
|
||||||
};
|
|
||||||
// TODO:
|
|
||||||
// Array<uint32> optimizedIndices = indices;
|
|
||||||
// tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices);
|
|
||||||
Array<Triangle> triangles(indices.size() / 3);
|
|
||||||
for (size_t i = 0; i < triangles.size(); ++i) {
|
|
||||||
triangles[i] = Triangle{
|
|
||||||
.indices =
|
|
||||||
{
|
|
||||||
indices[i * 3 + 0],
|
|
||||||
indices[i * 3 + 1],
|
|
||||||
indices[i * 3 + 2],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
while (!triangles.empty()) {
|
|
||||||
if (!addTriangle(positions, current, triangles.back())) {
|
|
||||||
completeMeshlet(meshlets, current);
|
|
||||||
addTriangle(positions, current, triangles.back());
|
|
||||||
}
|
|
||||||
triangles.pop();
|
|
||||||
}
|
|
||||||
if (current.numVertices > 0) {
|
|
||||||
completeMeshlet(meshlets, current);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ struct Meshlet {
|
|||||||
uint8 primitiveLayout[Gfx::numPrimitivesPerMeshlet * 3]; // indices into the uniqueVertices array, only uint8 needed
|
uint8 primitiveLayout[Gfx::numPrimitivesPerMeshlet * 3]; // indices into the uniqueVertices array, only uint8 needed
|
||||||
uint32 numVertices;
|
uint32 numVertices;
|
||||||
uint32 numPrimitives;
|
uint32 numPrimitives;
|
||||||
|
uint32 lod = 0;
|
||||||
static void build(const Array<Vector>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets);
|
static void build(const Array<Vector>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets);
|
||||||
};
|
};
|
||||||
} // namespace Seele
|
} // namespace Seele
|
||||||
@@ -81,7 +81,7 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics)
|
|||||||
skybox = Seele::Component::Skybox{
|
skybox = Seele::Component::Skybox{
|
||||||
.day = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(),
|
.day = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(),
|
||||||
.night = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(),
|
.night = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(),
|
||||||
.fogColor = Vector(0.1, 0.1, 0.8),
|
.fogColor = Vector(0, 0, 0),
|
||||||
.blendFactor = 0,
|
.blendFactor = 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,6 @@ StaticMeshVertexData* StaticMeshVertexData::getInstance() {
|
|||||||
return &instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StaticMeshVertexData::loadPositions(uint64 offset, const Array<PositionType>& data) {
|
|
||||||
assert(offset + data.size() <= head);
|
|
||||||
std::memcpy(posData.data() + offset, data.data(), data.size() * sizeof(PositionType));
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StaticMeshVertexData::loadTexCoords(uint64 offset, uint64 index, const Array<TexCoordType>& data) {
|
void StaticMeshVertexData::loadTexCoords(uint64 offset, uint64 index, const Array<TexCoordType>& data) {
|
||||||
assert(offset + data.size() <= head);
|
assert(offset + data.size() <= head);
|
||||||
std::memcpy(texData[index].data() + offset, data.data(), data.size() * sizeof(TexCoordType));
|
std::memcpy(texData[index].data() + offset, data.data(), data.size() * sizeof(TexCoordType));
|
||||||
@@ -67,17 +61,14 @@ void StaticMeshVertexData::serializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
|||||||
std::memcpy(tex[i].data(), texData[i].data() + offset, numVertices * sizeof(TexCoordType));
|
std::memcpy(tex[i].data(), texData[i].data() + offset, numVertices * sizeof(TexCoordType));
|
||||||
Serialization::save(buffer, tex[i]);
|
Serialization::save(buffer, tex[i]);
|
||||||
}
|
}
|
||||||
Array<PositionType> pos(numVertices);
|
|
||||||
Array<NormalType> nor(numVertices);
|
Array<NormalType> nor(numVertices);
|
||||||
Array<TangentType> tan(numVertices);
|
Array<TangentType> tan(numVertices);
|
||||||
Array<BiTangentType> bit(numVertices);
|
Array<BiTangentType> bit(numVertices);
|
||||||
Array<ColorType> col(numVertices);
|
Array<ColorType> col(numVertices);
|
||||||
std::memcpy(pos.data(), posData.data() + offset, numVertices * sizeof(PositionType));
|
|
||||||
std::memcpy(nor.data(), norData.data() + offset, numVertices * sizeof(NormalType));
|
std::memcpy(nor.data(), norData.data() + offset, numVertices * sizeof(NormalType));
|
||||||
std::memcpy(tan.data(), tanData.data() + offset, numVertices * sizeof(TangentType));
|
std::memcpy(tan.data(), tanData.data() + offset, numVertices * sizeof(TangentType));
|
||||||
std::memcpy(bit.data(), bitData.data() + offset, numVertices * sizeof(BiTangentType));
|
std::memcpy(bit.data(), bitData.data() + offset, numVertices * sizeof(BiTangentType));
|
||||||
std::memcpy(col.data(), colData.data() + offset, numVertices * sizeof(ColorType));
|
std::memcpy(col.data(), colData.data() + offset, numVertices * sizeof(ColorType));
|
||||||
Serialization::save(buffer, pos);
|
|
||||||
Serialization::save(buffer, nor);
|
Serialization::save(buffer, nor);
|
||||||
Serialization::save(buffer, tan);
|
Serialization::save(buffer, tan);
|
||||||
Serialization::save(buffer, bit);
|
Serialization::save(buffer, bit);
|
||||||
@@ -97,22 +88,18 @@ uint64 StaticMeshVertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
|||||||
loadTexCoords(offset, i, tex[i]);
|
loadTexCoords(offset, i, tex[i]);
|
||||||
result += tex[i].size() * sizeof(TexCoordType);
|
result += tex[i].size() * sizeof(TexCoordType);
|
||||||
}
|
}
|
||||||
Array<PositionType> pos;
|
|
||||||
Array<NormalType> nor;
|
Array<NormalType> nor;
|
||||||
Array<TangentType> tan;
|
Array<TangentType> tan;
|
||||||
Array<BiTangentType> bit;
|
Array<BiTangentType> bit;
|
||||||
Array<ColorType> col;
|
Array<ColorType> col;
|
||||||
Serialization::load(buffer, pos);
|
|
||||||
Serialization::load(buffer, nor);
|
Serialization::load(buffer, nor);
|
||||||
Serialization::load(buffer, tan);
|
Serialization::load(buffer, tan);
|
||||||
Serialization::load(buffer, bit);
|
Serialization::load(buffer, bit);
|
||||||
Serialization::load(buffer, col);
|
Serialization::load(buffer, col);
|
||||||
loadPositions(offset, pos);
|
|
||||||
loadNormals(offset, nor);
|
loadNormals(offset, nor);
|
||||||
loadTangents(offset, tan);
|
loadTangents(offset, tan);
|
||||||
loadBitangents(offset, bit);
|
loadBitangents(offset, bit);
|
||||||
loadColors(offset, col);
|
loadColors(offset, col);
|
||||||
result += pos.size() * sizeof(PositionType);
|
|
||||||
result += nor.size() * sizeof(NormalType);
|
result += nor.size() * sizeof(NormalType);
|
||||||
result += tan.size() * sizeof(TangentType);
|
result += tan.size() * sizeof(TangentType);
|
||||||
result += bit.size() * sizeof(BiTangentType);
|
result += bit.size() * sizeof(BiTangentType);
|
||||||
@@ -123,10 +110,6 @@ uint64 StaticMeshVertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
|||||||
void StaticMeshVertexData::init(Gfx::PGraphics _graphics) {
|
void StaticMeshVertexData::init(Gfx::PGraphics _graphics) {
|
||||||
VertexData::init(_graphics);
|
VertexData::init(_graphics);
|
||||||
descriptorLayout = _graphics->createDescriptorLayout("pVertexData");
|
descriptorLayout = _graphics->createDescriptorLayout("pVertexData");
|
||||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
|
||||||
.name = POSITIONS_NAME,
|
|
||||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
||||||
});
|
|
||||||
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
.name = NORMALS_NAME,
|
.name = NORMALS_NAME,
|
||||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
@@ -157,7 +140,6 @@ void StaticMeshVertexData::destroy() {
|
|||||||
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
||||||
texCoords[i] = nullptr;
|
texCoords[i] = nullptr;
|
||||||
}
|
}
|
||||||
positions = nullptr;
|
|
||||||
normals = nullptr;
|
normals = nullptr;
|
||||||
tangents = nullptr;
|
tangents = nullptr;
|
||||||
biTangents = nullptr;
|
biTangents = nullptr;
|
||||||
@@ -167,7 +149,7 @@ void StaticMeshVertexData::destroy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StaticMeshVertexData::resizeBuffers() {
|
void StaticMeshVertexData::resizeBuffers() {
|
||||||
posData.resize(verticesAllocated);
|
VertexData::resizeBuffers();
|
||||||
norData.resize(verticesAllocated);
|
norData.resize(verticesAllocated);
|
||||||
tanData.resize(verticesAllocated);
|
tanData.resize(verticesAllocated);
|
||||||
bitData.resize(verticesAllocated);
|
bitData.resize(verticesAllocated);
|
||||||
@@ -178,15 +160,7 @@ void StaticMeshVertexData::resizeBuffers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StaticMeshVertexData::updateBuffers() {
|
void StaticMeshVertexData::updateBuffers() {
|
||||||
positions = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
VertexData::updateBuffers();
|
||||||
.sourceData =
|
|
||||||
{
|
|
||||||
.size = verticesAllocated * sizeof(PositionType),
|
|
||||||
.data = (uint8*)posData.data(),
|
|
||||||
},
|
|
||||||
.usage = Gfx::SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
|
|
||||||
.name = "Positions",
|
|
||||||
});
|
|
||||||
normals = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
normals = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||||
.sourceData =
|
.sourceData =
|
||||||
{
|
{
|
||||||
@@ -231,7 +205,6 @@ void StaticMeshVertexData::updateBuffers() {
|
|||||||
}
|
}
|
||||||
descriptorLayout->reset();
|
descriptorLayout->reset();
|
||||||
descriptorSet = descriptorLayout->allocateDescriptorSet();
|
descriptorSet = descriptorLayout->allocateDescriptorSet();
|
||||||
descriptorSet->updateBuffer(POSITIONS_NAME, 0, positions);
|
|
||||||
descriptorSet->updateBuffer(NORMALS_NAME, 0, normals);
|
descriptorSet->updateBuffer(NORMALS_NAME, 0, normals);
|
||||||
descriptorSet->updateBuffer(TANGENTS_NAME, 0, tangents);
|
descriptorSet->updateBuffer(TANGENTS_NAME, 0, tangents);
|
||||||
descriptorSet->updateBuffer(BITANGENTS_NAME, 0, biTangents);
|
descriptorSet->updateBuffer(BITANGENTS_NAME, 0, biTangents);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
namespace Seele {
|
namespace Seele {
|
||||||
class StaticMeshVertexData : public VertexData {
|
class StaticMeshVertexData : public VertexData {
|
||||||
public:
|
public:
|
||||||
using PositionType = Vector;
|
|
||||||
using NormalType = Vector;
|
using NormalType = Vector;
|
||||||
using TangentType = Vector;
|
using TangentType = Vector;
|
||||||
using BiTangentType = Vector;
|
using BiTangentType = Vector;
|
||||||
@@ -18,7 +17,6 @@ class StaticMeshVertexData : public VertexData {
|
|||||||
StaticMeshVertexData();
|
StaticMeshVertexData();
|
||||||
virtual ~StaticMeshVertexData();
|
virtual ~StaticMeshVertexData();
|
||||||
static StaticMeshVertexData* getInstance();
|
static StaticMeshVertexData* getInstance();
|
||||||
void loadPositions(uint64 offset, const Array<PositionType>& data);
|
|
||||||
void loadTexCoords(uint64 offset, uint64 index, const Array<TexCoordType>& data);
|
void loadTexCoords(uint64 offset, uint64 index, const Array<TexCoordType>& data);
|
||||||
void loadNormals(uint64 offset, const Array<NormalType>& data);
|
void loadNormals(uint64 offset, const Array<NormalType>& data);
|
||||||
void loadTangents(uint64 offset, const Array<TangentType>& data);
|
void loadTangents(uint64 offset, const Array<TangentType>& data);
|
||||||
@@ -31,14 +29,11 @@ class StaticMeshVertexData : public VertexData {
|
|||||||
virtual Gfx::PDescriptorLayout getVertexDataLayout() override { return descriptorLayout; }
|
virtual Gfx::PDescriptorLayout getVertexDataLayout() override { return descriptorLayout; }
|
||||||
virtual Gfx::PDescriptorSet getVertexDataSet() override { return descriptorSet; }
|
virtual Gfx::PDescriptorSet getVertexDataSet() override { return descriptorSet; }
|
||||||
virtual std::string getTypeName() const override { return "StaticMeshVertexData"; }
|
virtual std::string getTypeName() const override { return "StaticMeshVertexData"; }
|
||||||
virtual Gfx::PShaderBuffer getPositionBuffer() const override { return positions; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void resizeBuffers() override;
|
virtual void resizeBuffers() override;
|
||||||
virtual void updateBuffers() override;
|
virtual void updateBuffers() override;
|
||||||
|
|
||||||
Gfx::OShaderBuffer positions;
|
|
||||||
constexpr static const char* POSITIONS_NAME = "positions";
|
|
||||||
Gfx::OShaderBuffer texCoords[MAX_TEXCOORDS];
|
Gfx::OShaderBuffer texCoords[MAX_TEXCOORDS];
|
||||||
constexpr static const char* TEXCOORDS_NAME = "texCoords";
|
constexpr static const char* TEXCOORDS_NAME = "texCoords";
|
||||||
Gfx::OShaderBuffer normals;
|
Gfx::OShaderBuffer normals;
|
||||||
@@ -49,7 +44,6 @@ class StaticMeshVertexData : public VertexData {
|
|||||||
constexpr static const char* BITANGENTS_NAME = "biTangents";
|
constexpr static const char* BITANGENTS_NAME = "biTangents";
|
||||||
Gfx::OShaderBuffer colors;
|
Gfx::OShaderBuffer colors;
|
||||||
constexpr static const char* COLORS_NAME = "colors";
|
constexpr static const char* COLORS_NAME = "colors";
|
||||||
Array<PositionType> posData;
|
|
||||||
Array<TexCoordType> texData[MAX_TEXCOORDS];
|
Array<TexCoordType> texData[MAX_TEXCOORDS];
|
||||||
Array<NormalType> norData;
|
Array<NormalType> norData;
|
||||||
Array<TangentType> tanData;
|
Array<TangentType> tanData;
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include "Material/Material.h"
|
#include "Material/Material.h"
|
||||||
#include "Material/MaterialInstance.h"
|
#include "Material/MaterialInstance.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <meshoptimizer.h>
|
||||||
|
#include <metis.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
using namespace Seele;
|
using namespace Seele;
|
||||||
|
|
||||||
@@ -58,7 +61,14 @@ void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transfo
|
|||||||
}
|
}
|
||||||
BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()];
|
BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()];
|
||||||
matInstanceData.materialInstance = referencedInstance;
|
matInstanceData.materialInstance = referencedInstance;
|
||||||
for (const auto& data : registeredMeshes[mesh->id].meshData) {
|
const auto& data = registeredMeshes[mesh->id].meshData;
|
||||||
|
uint32 numMeshlets = data.meshletRange.size;
|
||||||
|
for (uint32 i = 0; i < (numMeshlets + Gfx::numMeshletsPerTask - 1) / Gfx::numMeshletsPerTask; ++i) {
|
||||||
|
MeshData chunkMeshData = data;
|
||||||
|
chunkMeshData.meshletRange = {
|
||||||
|
.offset = data.meshletRange.offset + i * Gfx::numMeshletsPerTask,
|
||||||
|
.size = std::min(numMeshlets - i * Gfx::numMeshletsPerTask, Gfx::numMeshletsPerTask),
|
||||||
|
};
|
||||||
if (mat->hasTransparency()) {
|
if (mat->hasTransparency()) {
|
||||||
auto params = referencedInstance->getMaterialOffsets();
|
auto params = referencedInstance->getMaterialOffsets();
|
||||||
transparentData.add(TransparentDraw{
|
transparentData.add(TransparentDraw{
|
||||||
@@ -73,14 +83,14 @@ void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transfo
|
|||||||
},
|
},
|
||||||
.worldPosition = Vector(inst.transformMatrix[3]),
|
.worldPosition = Vector(inst.transformMatrix[3]),
|
||||||
.instanceData = inst,
|
.instanceData = inst,
|
||||||
.meshData = data,
|
.meshData = chunkMeshData,
|
||||||
.cullingOffset = meshletOffset,
|
.cullingOffset = meshletOffset,
|
||||||
.rayTracingScene = mesh->blas,
|
.rayTracingScene = mesh->blas,
|
||||||
});
|
});
|
||||||
} else { // opaque
|
} else { // opaque
|
||||||
matInstanceData.rayTracingData.add(mesh->blas);
|
matInstanceData.rayTracingData.add(mesh->blas);
|
||||||
matInstanceData.instanceData.add(inst);
|
matInstanceData.instanceData.add(inst);
|
||||||
matInstanceData.instanceMeshData.add(data);
|
matInstanceData.instanceMeshData.add(chunkMeshData);
|
||||||
matInstanceData.cullingOffsets.add(meshletOffset);
|
matInstanceData.cullingOffsets.add(meshletOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,6 +139,8 @@ void VertexData::createDescriptors() {
|
|||||||
|
|
||||||
instanceDataLayout->reset();
|
instanceDataLayout->reset();
|
||||||
descriptorSet = instanceDataLayout->allocateDescriptorSet();
|
descriptorSet = instanceDataLayout->allocateDescriptorSet();
|
||||||
|
descriptorSet->updateBuffer(POSITIONS_NAME, 0, positionBuffer);
|
||||||
|
descriptorSet->updateBuffer(INDEXBUFFER_NAME, 0, indexBuffer);
|
||||||
descriptorSet->updateBuffer(INSTANCES_NAME, 0, instanceBuffer);
|
descriptorSet->updateBuffer(INSTANCES_NAME, 0, instanceBuffer);
|
||||||
descriptorSet->updateBuffer(MESHDATA_NAME, 0, instanceMeshDataBuffer);
|
descriptorSet->updateBuffer(MESHDATA_NAME, 0, instanceMeshDataBuffer);
|
||||||
descriptorSet->updateBuffer(MESHLET_NAME, 0, meshletBuffer);
|
descriptorSet->updateBuffer(MESHLET_NAME, 0, meshletBuffer);
|
||||||
@@ -138,63 +150,167 @@ void VertexData::createDescriptors() {
|
|||||||
Material::updateDescriptor();
|
Material::updateDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexData::loadMesh(MeshId id, Array<uint32> loadedIndices, Array<Meshlet> loadedMeshlets) {
|
Array<VertexData::MeshletGroup> VertexData::groupMeshlets(std::span<MeshletDescription> meshlets) {
|
||||||
|
auto groupWithAllMeshets = [&]() {
|
||||||
|
MeshletGroup group;
|
||||||
|
for (uint32 i = 0; i < meshlets.size(); i++) {
|
||||||
|
group.meshlets.add(i);
|
||||||
|
}
|
||||||
|
return Array{group};
|
||||||
|
};
|
||||||
|
if (meshlets.size() < 8) {
|
||||||
|
return groupWithAllMeshets();
|
||||||
|
}
|
||||||
|
struct MeshletEdge {
|
||||||
|
explicit MeshletEdge(size_t a, size_t b) : first(std::min(a, b)), second(std::max(a, b)) {}
|
||||||
|
|
||||||
|
bool operator==(const MeshletEdge& other) const = default;
|
||||||
|
|
||||||
|
const size_t first;
|
||||||
|
const size_t second;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshletEdgeHasher {
|
||||||
|
size_t operator()(const MeshletEdge& edge) const { return CRC::Calculate(&edge, sizeof(MeshletEdge), CRC::CRC_32()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<MeshletEdge, Array<size_t>, MeshletEdgeHasher> edges2Meshlets;
|
||||||
|
std::unordered_map<size_t, Array<MeshletEdge>> meshlets2Edges;
|
||||||
|
|
||||||
|
for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); ++meshletIndex) {
|
||||||
|
const auto& meshlet = meshlets[meshletIndex];
|
||||||
|
auto getVertexIndex = [&](size_t index) {
|
||||||
|
return vertexIndices[meshlet.vertexIndices.offset + primitiveIndices[meshlet.primitiveIndices.offset + index]];
|
||||||
|
};
|
||||||
|
const size_t triangleCount = meshlet.primitiveIndices.size;
|
||||||
|
|
||||||
|
for (size_t triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex) {
|
||||||
|
for (size_t i = 0; i < 3; ++i) {
|
||||||
|
MeshletEdge edge{getVertexIndex(i + triangleIndex * 3), getVertexIndex(((i + 1) % 3) + triangleIndex * 3)};
|
||||||
|
edges2Meshlets[edge].add(meshletIndex);
|
||||||
|
meshlets2Edges[meshletIndex].emplace(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::erase_if(edges2Meshlets, [&](const auto& pair) { return pair.second.size() <= 1; });
|
||||||
|
if (edges2Meshlets.empty()) {
|
||||||
|
return groupWithAllMeshets();
|
||||||
|
}
|
||||||
|
|
||||||
|
idx_t vertexCount = meshlets.size();
|
||||||
|
idx_t ncon = 1;
|
||||||
|
idx_t nparts = meshlets.size() / 4;
|
||||||
|
assert(nparts > 1);
|
||||||
|
idx_t options[METIS_NOPTIONS];
|
||||||
|
METIS_SetDefaultOptions(options);
|
||||||
|
options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
|
||||||
|
options[METIS_OPTION_CCORDER] = 1;
|
||||||
|
|
||||||
|
Array<idx_t> partition;
|
||||||
|
partition.resize(vertexCount);
|
||||||
|
|
||||||
|
Array<idx_t> xadjacency;
|
||||||
|
xadjacency.reserve(vertexCount + 1);
|
||||||
|
|
||||||
|
Array<idx_t> edgeAdjacency;
|
||||||
|
Array<idx_t> edgeWeights;
|
||||||
|
|
||||||
|
for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); ++meshletIndex) {
|
||||||
|
size_t startIndexInEdgeAdjacency = edgeAdjacency.size();
|
||||||
|
for (const auto& edge : meshlets2Edges[meshletIndex]) {
|
||||||
|
auto connectionsIter = edges2Meshlets.find(edge);
|
||||||
|
if (connectionsIter == edges2Meshlets.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto& connections = connectionsIter->second;
|
||||||
|
for (const auto& connectedMeshlet : connections) {
|
||||||
|
if (connectedMeshlet != meshletIndex) {
|
||||||
|
auto existingEdgeIter =
|
||||||
|
std::find(edgeAdjacency.begin() + startIndexInEdgeAdjacency, edgeAdjacency.end(), connectedMeshlet);
|
||||||
|
if (existingEdgeIter == edgeAdjacency.end()) {
|
||||||
|
edgeAdjacency.emplace(connectedMeshlet);
|
||||||
|
edgeWeights.emplace(1);
|
||||||
|
} else {
|
||||||
|
ptrdiff_t d = std::distance(edgeAdjacency.begin(), existingEdgeIter);
|
||||||
|
assert(d >= 0);
|
||||||
|
assert(d < edgeWeights.size());
|
||||||
|
edgeWeights[d]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xadjacency.add(startIndexInEdgeAdjacency);
|
||||||
|
}
|
||||||
|
xadjacency.add(edgeAdjacency.size());
|
||||||
|
assert(xadjacency.size() == meshlets.size() + 1);
|
||||||
|
assert(edgeAdjacency.size() == edgeWeights.size());
|
||||||
|
|
||||||
|
idx_t edgeCut;
|
||||||
|
int result = METIS_PartGraphKway(&vertexCount, &ncon, xadjacency.data(), edgeAdjacency.data(), nullptr, nullptr, edgeWeights.data(),
|
||||||
|
&nparts, nullptr, nullptr, options, &edgeCut, partition.data());
|
||||||
|
|
||||||
|
assert(result == METIS_OK);
|
||||||
|
|
||||||
|
Array<MeshletGroup> groups;
|
||||||
|
groups.resize(nparts);
|
||||||
|
for (size_t i = 0; i < meshlets.size(); ++i) {
|
||||||
|
idx_t partitionNumber = partition[i];
|
||||||
|
groups[partitionNumber].meshlets.add(i);
|
||||||
|
}
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexData::loadMesh(MeshId id, Array<Vector> loadedPositions, Array<uint32> loadedIndices) {
|
||||||
std::unique_lock l(vertexDataLock);
|
std::unique_lock l(vertexDataLock);
|
||||||
RegisteredMesh& mesh = registeredMeshes[id];
|
RegisteredMesh& mesh = registeredMeshes[id];
|
||||||
assert(mesh.meshData.empty()); // TODO: update if not empty
|
MeshData& data = mesh.meshData;
|
||||||
uint32 numChunks = (loadedMeshlets.size() + 2047) / 2048;
|
|
||||||
for (uint32 chunkIdx = 0; chunkIdx < numChunks; ++chunkIdx) {
|
|
||||||
uint32 chunkOffset = chunkIdx * 2048;
|
|
||||||
uint32 numRemaining = loadedMeshlets.size() - chunkOffset;
|
|
||||||
|
|
||||||
AABB meshAABB;
|
// generate an LOD hierarchy for the given source mesh
|
||||||
uint32 meshletOffset = meshlets.size();
|
// load LOD 0
|
||||||
for (uint32 chunk = 0; chunk < std::min(numRemaining, 2048u); chunk++) {
|
loadMeshlets(id, loadedPositions, loadedIndices);
|
||||||
Meshlet& m = loadedMeshlets[chunkOffset + chunk];
|
size_t previousMeshletsStart = data.meshletRange.offset; // todo:
|
||||||
//...
|
|
||||||
meshAABB = meshAABB.combine(m.boundingBox);
|
|
||||||
|
|
||||||
uint32 vertexOffset = (uint32)vertexIndices.size();
|
/* const int maxLod = 25;
|
||||||
vertexIndices.resize(vertexOffset + m.numVertices);
|
for (int lod = 0; lod < maxLod; ++lod) {
|
||||||
std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32));
|
float tLod = lod / (float)maxLod;
|
||||||
|
|
||||||
uint32 primitiveOffset = (uint32)primitiveIndices.size();
|
std::span<MeshletDescription> previousLevelMeshlets =
|
||||||
primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3));
|
std::span{meshlets.data() + previousMeshletsStart, data.meshletRange.size};
|
||||||
std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8));
|
if (previousLevelMeshlets.size() <= 1) {
|
||||||
|
return;
|
||||||
meshlets.add(MeshletDescription{
|
|
||||||
.bounding = m.boundingBox, //.toSphere(),
|
|
||||||
.vertexIndices =
|
|
||||||
{
|
|
||||||
.offset = vertexOffset,
|
|
||||||
.size = m.numVertices,
|
|
||||||
},
|
|
||||||
.primitiveIndices =
|
|
||||||
{
|
|
||||||
.offset = primitiveOffset,
|
|
||||||
.size = m.numPrimitives,
|
|
||||||
},
|
|
||||||
.color = Vector((float)rand() / RAND_MAX, (float)rand() / RAND_MAX, (float)rand() / RAND_MAX),
|
|
||||||
.indicesOffset = (uint32)registeredMeshes[id].vertexOffset,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
registeredMeshes[id].meshData.add(MeshData{
|
auto groups = groupMeshlets(previousLevelMeshlets);
|
||||||
.bounding = meshAABB, //.toSphere(),
|
const uint32 newMeshletStart = ;
|
||||||
.meshletRange =
|
for (const auto& group : groups) {
|
||||||
{
|
Array<uint32> groupVertexIndices;
|
||||||
.offset = meshletOffset,
|
for (const auto& meshletIndex : group.meshlets) {
|
||||||
.size = std::min(numRemaining, 2048u),
|
const auto& meshlet = meshlets[meshletIndex];
|
||||||
},
|
size_t start = groupVertexIndices.size();
|
||||||
});
|
groupVertexIndices.resize(start + meshlet.numPrimitives * 3);
|
||||||
|
for (size_t j = 0; j < meshlet.numPrimitives * 3; ++j) {
|
||||||
|
groupVertexIndices[j + start] = meshlet.uniqueVertices[meshlet.primitiveLayout[j]];
|
||||||
}
|
}
|
||||||
// todo: in case of a index split for 16 bit, do something here
|
}
|
||||||
registeredMeshes[id].meshData[0].indicesRange = {
|
float targetError = 0.01f;
|
||||||
.offset = (uint32)indices.size(),
|
const float threshold = 0.5f;
|
||||||
.size = (uint32)loadedIndices.size(),
|
size_t targetIndexCount = groupVertexIndices.size() * threshold;
|
||||||
};
|
uint32 options = meshopt_SimplifyLockBorder;
|
||||||
indices.resize(indices.size() + loadedIndices.size());
|
|
||||||
std::memcpy(indices.data() + registeredMeshes[id].meshData[0].indicesRange.offset, loadedIndices.data(),
|
Array<uint32> simplifiedIndexBuffer;
|
||||||
loadedIndices.size() * sizeof(uint32));
|
simplifiedIndexBuffer.resize(groupVertexIndices.size());
|
||||||
|
float simplificationError = 0.f;
|
||||||
|
|
||||||
|
size_t simplifiedIndexCount = meshopt_simplify(
|
||||||
|
simplifiedIndexBuffer.data(), groupVertexIndices.data(), groupVertexIndices.size(), (float*)loadedPositions.data(),
|
||||||
|
loadedPositions.size(), sizeof(Vector), targetIndexCount, targetError, options, &simplificationError);
|
||||||
|
simplifiedIndexBuffer.resize(simplifiedIndexCount);
|
||||||
|
if (simplifiedIndexCount > 0) {
|
||||||
|
// loadMeshlets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
std::memcpy(positions.data() + mesh.vertexOffset, loadedPositions.data(), loadedPositions.size() * sizeof(Vector));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexData::removeMesh(MeshId id) {
|
void VertexData::removeMesh(MeshId id) {
|
||||||
@@ -205,9 +321,9 @@ void VertexData::removeMesh(MeshId id) {
|
|||||||
uint32 numVertexIndices = 0;
|
uint32 numVertexIndices = 0;
|
||||||
uint32 primitiveIndicesOffset = primitiveIndices.size();
|
uint32 primitiveIndicesOffset = primitiveIndices.size();
|
||||||
uint32 numPrimitiveIndices = 0;
|
uint32 numPrimitiveIndices = 0;
|
||||||
uint32 indicesOffset = removing.meshData[0].indicesRange.offset;
|
uint32 indicesOffset = removing.meshData.indicesRange.offset;
|
||||||
uint32 numIndices = removing.meshData[0].indicesRange.size;
|
uint32 numIndices = removing.meshData.indicesRange.size;
|
||||||
for (const auto& data : removing.meshData) {
|
const auto& data = removing.meshData;
|
||||||
meshletOffset = std::min(meshletOffset, data.meshletRange.offset);
|
meshletOffset = std::min(meshletOffset, data.meshletRange.offset);
|
||||||
numMeshlets += data.meshletRange.size;
|
numMeshlets += data.meshletRange.size;
|
||||||
for (uint32 m = 0; m < data.meshletRange.size; ++m) {
|
for (uint32 m = 0; m < data.meshletRange.size; ++m) {
|
||||||
@@ -217,9 +333,9 @@ void VertexData::removeMesh(MeshId id) {
|
|||||||
primitiveIndicesOffset = std::min(primitiveIndicesOffset, meshlet.primitiveIndices.offset);
|
primitiveIndicesOffset = std::min(primitiveIndicesOffset, meshlet.primitiveIndices.offset);
|
||||||
numPrimitiveIndices += meshlet.primitiveIndices.size;
|
numPrimitiveIndices += meshlet.primitiveIndices.size;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (auto& mesh : registeredMeshes) {
|
for (auto& mesh : registeredMeshes) {
|
||||||
for (auto& data : mesh.meshData) {
|
auto& data = mesh.meshData;
|
||||||
if (data.meshletRange.offset > meshletOffset) {
|
if (data.meshletRange.offset > meshletOffset) {
|
||||||
for (uint32 i = 0; i < data.meshletRange.size; ++i) {
|
for (uint32 i = 0; i < data.meshletRange.size; ++i) {
|
||||||
MeshletDescription& m = meshlets[data.meshletRange.offset + i];
|
MeshletDescription& m = meshlets[data.meshletRange.offset + i];
|
||||||
@@ -234,7 +350,6 @@ void VertexData::removeMesh(MeshId id) {
|
|||||||
data.indicesRange.offset -= numIndices;
|
data.indicesRange.offset -= numIndices;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
uint32 numMeshletsToMove = meshlets.size() - (meshletOffset + numMeshlets);
|
uint32 numMeshletsToMove = meshlets.size() - (meshletOffset + numMeshlets);
|
||||||
uint32 numVertexIndicesToMove = vertexIndices.size() - (vertexIndicesOffset + numVertexIndices);
|
uint32 numVertexIndicesToMove = vertexIndices.size() - (vertexIndicesOffset + numVertexIndices);
|
||||||
uint32 numPrimitiveIndicesToMove = primitiveIndices.size() - (primitiveIndicesOffset + numPrimitiveIndices);
|
uint32 numPrimitiveIndicesToMove = primitiveIndices.size() - (primitiveIndicesOffset + numPrimitiveIndices);
|
||||||
@@ -305,6 +420,7 @@ MeshId VertexData::allocateVertexData(uint64 numVertices) {
|
|||||||
if (head > verticesAllocated) {
|
if (head > verticesAllocated) {
|
||||||
verticesAllocated = 2 * head; // double capacity
|
verticesAllocated = 2 * head; // double capacity
|
||||||
std::cout << "Resizing buffers to " << verticesAllocated << std::endl;
|
std::cout << "Resizing buffers to " << verticesAllocated << std::endl;
|
||||||
|
|
||||||
resizeBuffers();
|
resizeBuffers();
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
@@ -312,34 +428,22 @@ MeshId VertexData::allocateVertexData(uint64 numVertices) {
|
|||||||
|
|
||||||
void VertexData::serializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
void VertexData::serializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
||||||
std::unique_lock l(vertexDataLock);
|
std::unique_lock l(vertexDataLock);
|
||||||
Array<Meshlet> out;
|
Array<uint32> ind(registeredMeshes[id].meshData.indicesRange.size);
|
||||||
for (uint32 n = 0; n < registeredMeshes[id].meshData.size(); ++n) {
|
std::memcpy(ind.data(), indices.data() + registeredMeshes[id].meshData.indicesRange.offset,
|
||||||
MeshData data = registeredMeshes[id].meshData[n];
|
registeredMeshes[id].meshData.indicesRange.size * sizeof(uint32));
|
||||||
for (size_t i = 0; i < data.meshletRange.size; ++i) {
|
Array<Vector> pos(registeredMeshes[id].vertexCount);
|
||||||
MeshletDescription& desc = meshlets[i + data.meshletRange.offset];
|
std::memcpy(pos.data(), positions.data() + registeredMeshes[id].vertexOffset, registeredMeshes[id].vertexCount * sizeof(Vector));
|
||||||
Meshlet m;
|
|
||||||
std::memcpy(m.uniqueVertices, &vertexIndices[desc.vertexIndices.offset], desc.vertexIndices.size * sizeof(uint32));
|
|
||||||
std::memcpy(m.primitiveLayout, &primitiveIndices[desc.primitiveIndices.offset], desc.primitiveIndices.size * 3 * sizeof(uint8));
|
|
||||||
m.numPrimitives = desc.primitiveIndices.size;
|
|
||||||
m.numVertices = desc.vertexIndices.size;
|
|
||||||
m.boundingBox = desc.bounding;
|
|
||||||
out.add(std::move(m));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Array<uint32> ind(registeredMeshes[id].meshData[0].indicesRange.size);
|
|
||||||
std::memcpy(ind.data(), &indices[registeredMeshes[id].meshData[0].indicesRange.offset],
|
|
||||||
registeredMeshes[id].meshData[0].indicesRange.size * sizeof(uint32));
|
|
||||||
Serialization::save(buffer, out);
|
|
||||||
Serialization::save(buffer, ind);
|
Serialization::save(buffer, ind);
|
||||||
|
Serialization::save(buffer, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 VertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
uint64 VertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) {
|
||||||
Array<Meshlet> in;
|
Array<Vector> pos;
|
||||||
Array<uint32> ind;
|
Array<uint32> ind;
|
||||||
Serialization::load(buffer, in);
|
|
||||||
Serialization::load(buffer, ind);
|
Serialization::load(buffer, ind);
|
||||||
loadMesh(id, ind, in);
|
Serialization::load(buffer, pos);
|
||||||
uint64 result = in.size() * sizeof(MeshletDescription);
|
loadMesh(id, pos, ind);
|
||||||
|
uint64 result = pos.size() * sizeof(Vector);
|
||||||
result += ind.size() * sizeof(uint32);
|
result += ind.size() * sizeof(uint32);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -364,6 +468,16 @@ void VertexData::init(Gfx::PGraphics _graphics) {
|
|||||||
verticesAllocated = NUM_DEFAULT_ELEMENTS;
|
verticesAllocated = NUM_DEFAULT_ELEMENTS;
|
||||||
instanceDataLayout = graphics->createDescriptorLayout("pScene");
|
instanceDataLayout = graphics->createDescriptorLayout("pScene");
|
||||||
|
|
||||||
|
// positions
|
||||||
|
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
|
.name = POSITIONS_NAME,
|
||||||
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
});
|
||||||
|
// indexBuffer
|
||||||
|
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
|
.name = INDEXBUFFER_NAME,
|
||||||
|
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
});
|
||||||
// instanceData
|
// instanceData
|
||||||
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||||
.name = INSTANCES_NAME,
|
.name = INSTANCES_NAME,
|
||||||
@@ -430,10 +544,91 @@ void VertexData::destroy() {
|
|||||||
|
|
||||||
uint32 VertexData::addCullingMapping(MeshId id) {
|
uint32 VertexData::addCullingMapping(MeshId id) {
|
||||||
uint32 result = (uint32)meshletCount;
|
uint32 result = (uint32)meshletCount;
|
||||||
for (const auto& md : getMeshData(id)) {
|
const auto& md = getMeshData(id);
|
||||||
meshletCount += md.meshletRange.size;
|
meshletCount += md.meshletRange.size;
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VertexData::resizeBuffers() { positions.resize(verticesAllocated); }
|
||||||
|
|
||||||
|
void VertexData::updateBuffers() {
|
||||||
|
positionBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||||
|
.sourceData =
|
||||||
|
{
|
||||||
|
.size = verticesAllocated * sizeof(Vector),
|
||||||
|
.data = (uint8*)positions.data(),
|
||||||
|
},
|
||||||
|
.usage = Gfx::SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
|
||||||
|
.name = "Positions",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexData::loadMeshlets(MeshId id, const Array<Vector>& loadedPositions, const Array<uint32>& loadedIndices) {
|
||||||
|
// Array<uint32> optimizedIndices = indices;
|
||||||
|
// tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices);
|
||||||
|
|
||||||
|
const float coneWeight = 0.0f;
|
||||||
|
|
||||||
|
const uint32 meshletOffset = meshlets.size();
|
||||||
|
const uint32 vertexOffset = vertexIndices.size();
|
||||||
|
const uint32 primitiveOffset = primitiveIndices.size();
|
||||||
|
const uint32 maxMeshlets = meshopt_buildMeshletsBound(loadedIndices.size(), Gfx::numVerticesPerMeshlet, Gfx::numPrimitivesPerMeshlet);
|
||||||
|
Array<meshopt_Meshlet> meshoptMeshlets;
|
||||||
|
meshoptMeshlets.resize(maxMeshlets);
|
||||||
|
|
||||||
|
Array<uint32> meshletVertexIndices;
|
||||||
|
Array<uint8> meshletTriangles;
|
||||||
|
meshletVertexIndices.resize(maxMeshlets * Gfx::numVerticesPerMeshlet);
|
||||||
|
meshletTriangles.resize(maxMeshlets * Gfx::numVerticesPerMeshlet * 3);
|
||||||
|
|
||||||
|
const uint32 meshletCount =
|
||||||
|
meshopt_buildMeshlets(meshoptMeshlets.data(), meshletVertexIndices.data(), meshletTriangles.data(), loadedIndices.data(),
|
||||||
|
loadedIndices.size(), (float*)loadedPositions.data(), loadedPositions.size(), sizeof(Vector),
|
||||||
|
Gfx::numVerticesPerMeshlet, Gfx::numPrimitivesPerMeshlet, coneWeight);
|
||||||
|
|
||||||
|
const meshopt_Meshlet& last = meshoptMeshlets[meshletCount - 1];
|
||||||
|
const uint32 vertexCount = last.vertex_offset + last.vertex_count;
|
||||||
|
const uint32 indexCount = last.triangle_offset + ((last.triangle_count * 3 + 3) & ~3);
|
||||||
|
vertexIndices.resize(vertexOffset + vertexCount);
|
||||||
|
primitiveIndices.resize(primitiveOffset + indexCount);
|
||||||
|
meshlets.resize(meshletOffset + meshletCount);
|
||||||
|
|
||||||
|
std::memcpy(vertexIndices.data() + vertexOffset, meshletVertexIndices.data(), vertexCount * sizeof(uint32));
|
||||||
|
std::memcpy(primitiveIndices.data() + primitiveOffset, meshletTriangles.data(), indexCount * sizeof(uint8));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < meshletCount; ++i) {
|
||||||
|
MeshletDescription& m = meshlets[meshletOffset + i];
|
||||||
|
m.vertexIndices = {
|
||||||
|
.offset = vertexOffset + meshoptMeshlets[i].vertex_offset,
|
||||||
|
.size = meshoptMeshlets[i].vertex_count,
|
||||||
|
};
|
||||||
|
m.primitiveIndices = {
|
||||||
|
.offset = primitiveOffset + meshoptMeshlets[i].triangle_offset,
|
||||||
|
.size = meshoptMeshlets[i].triangle_count,
|
||||||
|
};
|
||||||
|
// todo: use meshopt for bb generation
|
||||||
|
m.bounding = AABB();
|
||||||
|
for (size_t j = 0; j < m.vertexIndices.size; ++j) {
|
||||||
|
m.bounding.adjust(loadedPositions[vertexIndices[meshoptMeshlets[i].vertex_offset + j]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registeredMeshes[id].meshData = MeshData{
|
||||||
|
.bounding = AABB(),
|
||||||
|
.meshletRange =
|
||||||
|
{
|
||||||
|
.offset = meshletOffset,
|
||||||
|
.size = meshletCount,
|
||||||
|
},
|
||||||
|
.indicesRange =
|
||||||
|
{
|
||||||
|
.offset = (uint32)indices.size(),
|
||||||
|
.size = (uint32)loadedIndices.size(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// todo: in case of a index split for 16 bit, do something here
|
||||||
|
indices.resize(indices.size() + loadedIndices.size());
|
||||||
|
std::memcpy(indices.data() + registeredMeshes[id].meshData.indicesRange.offset, loadedIndices.data(),
|
||||||
|
loadedIndices.size() * sizeof(uint32));
|
||||||
|
}
|
||||||
|
|
||||||
VertexData::VertexData() : idCounter(0), head(0), verticesAllocated(0), dirty(false) {}
|
VertexData::VertexData() : idCounter(0), head(0), verticesAllocated(0), dirty(false) {}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class VertexData {
|
|||||||
void resetMeshData();
|
void resetMeshData();
|
||||||
void updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transform& transform);
|
void updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transform& transform);
|
||||||
virtual void createDescriptors();
|
virtual void createDescriptors();
|
||||||
void loadMesh(MeshId id, Array<uint32> indices, Array<Meshlet> meshlets);
|
void loadMesh(MeshId id, Array<Vector> positions, Array<uint32> indices);
|
||||||
virtual void removeMesh(MeshId id);
|
virtual void removeMesh(MeshId id);
|
||||||
void commitMeshes();
|
void commitMeshes();
|
||||||
MeshId allocateVertexData(uint64 numVertices);
|
MeshId allocateVertexData(uint64 numVertices);
|
||||||
@@ -68,7 +68,7 @@ class VertexData {
|
|||||||
virtual Gfx::PDescriptorLayout getVertexDataLayout() = 0;
|
virtual Gfx::PDescriptorLayout getVertexDataLayout() = 0;
|
||||||
virtual Gfx::PDescriptorSet getVertexDataSet() = 0;
|
virtual Gfx::PDescriptorSet getVertexDataSet() = 0;
|
||||||
virtual std::string getTypeName() const = 0;
|
virtual std::string getTypeName() const = 0;
|
||||||
virtual Gfx::PShaderBuffer getPositionBuffer() const = 0;
|
Gfx::PShaderBuffer getPositionBuffer() const { return positionBuffer; }
|
||||||
Gfx::PIndexBuffer getIndexBuffer() const { return indexBuffer; }
|
Gfx::PIndexBuffer getIndexBuffer() const { return indexBuffer; }
|
||||||
uint32* getIndexData() const { return indices.data(); }
|
uint32* getIndexData() const { return indices.data(); }
|
||||||
Gfx::PDescriptorLayout getInstanceDataLayout() { return instanceDataLayout; }
|
Gfx::PDescriptorLayout getInstanceDataLayout() { return instanceDataLayout; }
|
||||||
@@ -76,7 +76,7 @@ class VertexData {
|
|||||||
const Array<MaterialData>& getMaterialData() const { return materialData; }
|
const Array<MaterialData>& getMaterialData() const { return materialData; }
|
||||||
const Array<TransparentDraw>& getTransparentData() const { return transparentData; }
|
const Array<TransparentDraw>& getTransparentData() const { return transparentData; }
|
||||||
const Array<Gfx::PBottomLevelAS>& getRayTracingData() const { return rayTracingScene; }
|
const Array<Gfx::PBottomLevelAS>& getRayTracingData() const { return rayTracingScene; }
|
||||||
const Array<MeshData>& getMeshData(MeshId id) const { return registeredMeshes[id].meshData; }
|
const MeshData& getMeshData(MeshId id) const { return registeredMeshes[id].meshData; }
|
||||||
void registerBottomLevelAccelerationStructure(Gfx::PBottomLevelAS blas) { dataToBuild.add(blas); }
|
void registerBottomLevelAccelerationStructure(Gfx::PBottomLevelAS blas) { dataToBuild.add(blas); }
|
||||||
uint32 getIndicesOffset(uint32 meshletIndex) { return meshlets[meshletIndex].indicesOffset; }
|
uint32 getIndicesOffset(uint32 meshletIndex) { return meshlets[meshletIndex].indicesOffset; }
|
||||||
uint64 getNumInstances() const { return instanceData.size(); }
|
uint64 getNumInstances() const { return instanceData.size(); }
|
||||||
@@ -91,8 +91,10 @@ class VertexData {
|
|||||||
constexpr static const char* CULLINGDATA_NAME = "cullingData";
|
constexpr static const char* CULLINGDATA_NAME = "cullingData";
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void resizeBuffers() = 0;
|
virtual void resizeBuffers();
|
||||||
virtual void updateBuffers() = 0;
|
virtual void updateBuffers();
|
||||||
|
void loadMeshlets(MeshId id, const Array<Vector>& positions, const Array<uint32>& indices);
|
||||||
|
|
||||||
VertexData();
|
VertexData();
|
||||||
struct MeshletDescription {
|
struct MeshletDescription {
|
||||||
AABB bounding;
|
AABB bounding;
|
||||||
@@ -100,9 +102,11 @@ class VertexData {
|
|||||||
PoolRange vertexIndices;
|
PoolRange vertexIndices;
|
||||||
// range into primitiveIndices array
|
// range into primitiveIndices array
|
||||||
PoolRange primitiveIndices;
|
PoolRange primitiveIndices;
|
||||||
Vector color;
|
|
||||||
// gets added to vertex indices so that they reference the global mesh pool
|
// gets added to vertex indices so that they reference the global mesh pool
|
||||||
uint32 indicesOffset = 0;
|
uint32 indicesOffset = 0;
|
||||||
|
uint32 lod = 0;
|
||||||
|
uint32 pad0;
|
||||||
|
uint32 pad1;
|
||||||
};
|
};
|
||||||
std::mutex materialDataLock;
|
std::mutex materialDataLock;
|
||||||
Array<MaterialData> materialData;
|
Array<MaterialData> materialData;
|
||||||
@@ -111,8 +115,8 @@ class VertexData {
|
|||||||
std::mutex vertexDataLock;
|
std::mutex vertexDataLock;
|
||||||
struct RegisteredMesh
|
struct RegisteredMesh
|
||||||
{
|
{
|
||||||
// each mesh id can have multiple meshdata, in case it needs to be split for having too many meshlets
|
// this mesh data can have an unlimited number of meshlets, gets split when updating shader buffers
|
||||||
Array<MeshData> meshData;
|
MeshData meshData;
|
||||||
uint64 vertexOffset;
|
uint64 vertexOffset;
|
||||||
uint64 vertexCount;
|
uint64 vertexCount;
|
||||||
};
|
};
|
||||||
@@ -121,6 +125,7 @@ class VertexData {
|
|||||||
Array<MeshletDescription> meshlets;
|
Array<MeshletDescription> meshlets;
|
||||||
Array<uint8> primitiveIndices;
|
Array<uint8> primitiveIndices;
|
||||||
Array<uint32> vertexIndices;
|
Array<uint32> vertexIndices;
|
||||||
|
Array<Vector> positions;
|
||||||
Array<uint32> indices;
|
Array<uint32> indices;
|
||||||
|
|
||||||
static uint64 meshletCount;
|
static uint64 meshletCount;
|
||||||
@@ -128,6 +133,10 @@ class VertexData {
|
|||||||
Gfx::PGraphics graphics;
|
Gfx::PGraphics graphics;
|
||||||
Gfx::ODescriptorLayout instanceDataLayout;
|
Gfx::ODescriptorLayout instanceDataLayout;
|
||||||
// for mesh shading
|
// for mesh shading
|
||||||
|
Gfx::OShaderBuffer positionBuffer;
|
||||||
|
constexpr static const char* POSITIONS_NAME = "positions";
|
||||||
|
Gfx::OIndexBuffer indexBuffer;
|
||||||
|
constexpr static const char* INDEXBUFFER_NAME = "indexBuffer";
|
||||||
Gfx::OShaderBuffer meshletBuffer;
|
Gfx::OShaderBuffer meshletBuffer;
|
||||||
constexpr static const char* MESHLET_NAME = "meshlets";
|
constexpr static const char* MESHLET_NAME = "meshlets";
|
||||||
Gfx::OShaderBuffer vertexIndicesBuffer;
|
Gfx::OShaderBuffer vertexIndicesBuffer;
|
||||||
@@ -137,9 +146,6 @@ class VertexData {
|
|||||||
Gfx::OShaderBuffer cullingOffsetBuffer;
|
Gfx::OShaderBuffer cullingOffsetBuffer;
|
||||||
constexpr static const char* CULLINGOFFSETS_NAME = "cullingOffsets";
|
constexpr static const char* CULLINGOFFSETS_NAME = "cullingOffsets";
|
||||||
|
|
||||||
// for legacy pipeline
|
|
||||||
Gfx::OIndexBuffer indexBuffer;
|
|
||||||
constexpr static const char* INDEXBUFFER_NAME = "indexBuffer";
|
|
||||||
Array<Gfx::PBottomLevelAS> dataToBuild;
|
Array<Gfx::PBottomLevelAS> dataToBuild;
|
||||||
// Material data
|
// Material data
|
||||||
Array<InstanceData> instanceData;
|
Array<InstanceData> instanceData;
|
||||||
@@ -157,5 +163,10 @@ class VertexData {
|
|||||||
uint64 head;
|
uint64 head;
|
||||||
uint64 verticesAllocated;
|
uint64 verticesAllocated;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
|
||||||
|
struct MeshletGroup {
|
||||||
|
Array<size_t> meshlets;
|
||||||
|
};
|
||||||
|
Array<MeshletGroup> groupMeshlets(std::span<MeshletDescription> meshlets);
|
||||||
};
|
};
|
||||||
} // namespace Seele
|
} // namespace Seele
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ BottomLevelAS::BottomLevelAS(PGraphics graphics, const Gfx::BottomLevelASCreateI
|
|||||||
};
|
};
|
||||||
VertexData* vertexData = createInfo.mesh->vertexData;
|
VertexData* vertexData = createInfo.mesh->vertexData;
|
||||||
//todo: indices might be split as well
|
//todo: indices might be split as well
|
||||||
MeshData meshData = vertexData->getMeshData(createInfo.mesh->id)[0];
|
MeshData meshData = vertexData->getMeshData(createInfo.mesh->id);
|
||||||
vertexOffset = vertexData->getMeshOffset(createInfo.mesh->id) * sizeof(Vector);
|
vertexOffset = vertexData->getMeshOffset(createInfo.mesh->id) * sizeof(Vector);
|
||||||
vertexCount = vertexData->getMeshVertexCount(createInfo.mesh->id);
|
vertexCount = vertexData->getMeshVertexCount(createInfo.mesh->id);
|
||||||
indexOffset = meshData.indicesRange.offset * sizeof(uint32);
|
indexOffset = meshData.indicesRange.offset * sizeof(uint32);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ MeshUpdater::MeshUpdater(PScene scene) : ComponentSystem<Component::Transform, C
|
|||||||
MeshUpdater::~MeshUpdater() {}
|
MeshUpdater::~MeshUpdater() {}
|
||||||
|
|
||||||
void MeshUpdater::update(entt::entity id, Component::Transform& transform, Component::Mesh& comp) {
|
void MeshUpdater::update(entt::entity id, Component::Transform& transform, Component::Mesh& comp) {
|
||||||
scene->accessComponent<Component::Camera>(id);
|
|
||||||
if (comp.meshletOffsets.empty()) {
|
if (comp.meshletOffsets.empty()) {
|
||||||
for (uint32 i = 0; i < comp.asset->meshes.size(); ++i) {
|
for (uint32 i = 0; i < comp.asset->meshes.size(); ++i) {
|
||||||
comp.meshletOffsets.add(comp.asset->meshes[i]->vertexData->addCullingMapping(comp.asset->meshes[i]->id));
|
comp.meshletOffsets.add(comp.asset->meshes[i]->vertexData->addCullingMapping(comp.asset->meshes[i]->id));
|
||||||
|
|||||||
+3
-1
@@ -14,6 +14,8 @@
|
|||||||
"vulkan-memory-allocator",
|
"vulkan-memory-allocator",
|
||||||
"lunasvg",
|
"lunasvg",
|
||||||
"harfbuzz",
|
"harfbuzz",
|
||||||
"shader-slang"
|
"shader-slang",
|
||||||
|
"metis",
|
||||||
|
"meshoptimizer"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user