Skip to content
Snippets Groups Projects
Commit a0746f0f authored by Alexander Gauggel's avatar Alexander Gauggel
Browse files

[87] WIP meshlet frustum culling

parent 9478ce49
Branches
Tags
1 merge request!74Resolve "Mesh Shader Implementation"
This commit is part of merge request !74. Comments created here will be created in the context of that merge request.
struct Meshlet{
uint vertexOffset;
uint vertexCount;
uint indexOffset;
uint indexCount;
vec3 meanPosition;
float boundingSphereRadius;
};
\ No newline at end of file
#version 460
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#extension GL_NV_mesh_shader : require
#include "meshlet.inc"
layout(local_size_x=32) in;
layout(triangles) out;
layout(max_vertices=64, max_primitives=126) out;
layout( push_constant ) uniform constants{
mat4 mvp;
};
layout(location = 0) out vec3 passNormal[];
layout(location = 1) out uint passTaskIndex[];
......@@ -30,15 +29,6 @@ layout(std430, binding = 1) readonly buffer indexBuffer
uint localIndices[]; // breaks for 16 bit indices
};
struct Meshlet{
uint vertexOffset;
uint vertexCount;
uint indexOffset;
uint indexCount;
vec3 meanPosition;
float boundingSphereRadius;
};
layout(std430, binding = 2) readonly buffer meshletBuffer
{
Meshlet meshlets[];
......@@ -46,6 +36,7 @@ layout(std430, binding = 2) readonly buffer meshletBuffer
taskNV in Task {
uint meshletIndices[32];
mat4 mvp;
} IN;
void main() {
......@@ -64,7 +55,7 @@ void main() {
uint vertexIndex = meshlet.vertexOffset + workIndex;
Vertex vertex = vertices[vertexIndex];
gl_MeshVerticesNV[workIndex].gl_Position = mvp * vec4(vertex.position, 1);
gl_MeshVerticesNV[workIndex].gl_Position = IN.mvp * vec4(vertex.position, 1);
passNormal[workIndex] = vertex.normal;
passTaskIndex[workIndex] = meshletIndex;
}
......
#version 460
#extension GL_ARB_separate_shader_objects : enable
#extension GL_NV_mesh_shader : require
#extension GL_GOOGLE_include_directive : enable
#include "meshlet.inc"
layout(local_size_x=32) in;
taskNV out Task {
uint meshletIndices[32];
mat4 mvp;
} OUT;
layout( push_constant ) uniform constants{
mat4 mvp;
uint meshletCount;
uint matrixIndex;
};
layout(std430, binding = 2) readonly buffer meshletBuffer
{
Meshlet meshlets[];
};
struct Plane{
vec3 pointOnPlane;
float padding0;
vec3 normal;
float padding1;
};
layout(set=0, binding=3, std140) uniform cameraPlaneBuffer{
Plane cameraPlanes[6];
};
struct ObjectMatrices{
mat4 model;
mat4 mvp;
};
layout(std430, binding = 4) readonly buffer matrixBuffer
{
ObjectMatrices objectMatrices[];
};
shared uint taskCount;
bool isSphereInsideFrustum(vec3 spherePos, float sphereRadius, Plane cameraPlanes[6]){
bool isInside = true;
for(int i = 0; i < 6; i++){
Plane p = cameraPlanes[i];
isInside = isInside && dot(p.normal, spherePos - p.pointOnPlane) + sphereRadius < 0;
}
return isInside;
}
void main() {
if(gl_LocalInvocationID.x >= meshletCount){
return;
}
uint meshletIndex = gl_GlobalInvocationID.x;
Meshlet meshlet = meshlets[meshletIndex];
if(gl_LocalInvocationID.x == 0){
taskCount = 0;
}
if(isSphereInsideFrustum(meshlet.meanPosition, meshlet.boundingSphereRadius, cameraPlanes)){
uint outIndex = atomicAdd(taskCount, 1);
OUT.meshletIndices[outIndex] = gl_GlobalInvocationID.x;
}
if(gl_LocalInvocationID.x == 0){
int taskCount = int(gl_WorkGroupID.x * 32);
// use signed ints to avoid underflow
int superflousTaskCount = max(taskCount - int(meshletCount), 0);
gl_TaskCountNV = 32 - superflousTaskCount;
gl_TaskCountNV = taskCount;
OUT.mvp = objectMatrices[matrixIndex].mvp;
}
OUT.meshletIndices[gl_LocalInvocationID.x] = gl_GlobalInvocationID.x;
}
\ No newline at end of file
......@@ -10,6 +10,70 @@
#include <vkcv/meshlet/Meshlet.hpp>
//#include <vkcv/meshlet/Tipsify.hpp>
struct Plane {
glm::vec3 pointOnPlane;
float padding0;
glm::vec3 normal;
float padding1;
};
struct CameraPlanes {
Plane planes[6];
};
CameraPlanes computeCameraPlanes(const vkcv::camera::Camera& camera) {
const float fov = camera.getFov();
const glm::vec3 pos = camera.getPosition();
const float ratio = camera.getRatio();
const glm::vec3 forward = glm::normalize(camera.getFront());
float near;
float far;
camera.getNearFar(near, far);
glm::vec3 up = glm::dot(forward, glm::vec3(0, -1, 0)) < 0.99 ? glm::vec3(0, -1, 0) : glm::vec3(1, 0, 0);
glm::vec3 right = glm::normalize(glm::cross(forward, up));
up = glm::cross(forward, right);
const glm::vec3 nearCenter = pos + forward * near;
const glm::vec3 farCenter = pos + forward * far;
const float tanFovHalf = glm::tan(fov / 2);
const glm::vec3 nearUpCenter = nearCenter + up * tanFovHalf * near;
const glm::vec3 nearDownCenter = nearCenter - up * tanFovHalf * near;
const glm::vec3 nearRightCenter = nearCenter + right * tanFovHalf * near * ratio;
const glm::vec3 nearLeftCenter = nearCenter - right * tanFovHalf * near * ratio;
const glm::vec3 farUpCenter = farCenter + up * tanFovHalf * far;
const glm::vec3 farDownCenter = farCenter - up * tanFovHalf * far;
const glm::vec3 farRightCenter = farCenter + right * tanFovHalf * far * ratio;
const glm::vec3 farLeftCenter = farCenter - right * tanFovHalf * far * ratio;
CameraPlanes cameraPlanes;
// near
cameraPlanes.planes[0].pointOnPlane = nearCenter;
cameraPlanes.planes[0].normal = -forward;
// far
cameraPlanes.planes[1].pointOnPlane = farCenter;
cameraPlanes.planes[1].normal = forward;
// top
cameraPlanes.planes[2].pointOnPlane = nearUpCenter;
cameraPlanes.planes[2].normal = glm::normalize(glm::cross(farUpCenter - nearUpCenter, right));
// bot
cameraPlanes.planes[3].pointOnPlane = nearDownCenter;
cameraPlanes.planes[3].normal = glm::normalize(glm::cross(right, farDownCenter - nearDownCenter));
// right
cameraPlanes.planes[4].pointOnPlane = nearRightCenter;
cameraPlanes.planes[4].normal = glm::normalize(glm::cross(up, farRightCenter - nearRightCenter));
// left
cameraPlanes.planes[5].pointOnPlane = nearLeftCenter;
cameraPlanes.planes[5].normal = glm::normalize(glm::cross(farLeftCenter - nearLeftCenter, up));
return cameraPlanes;
}
int main(int argc, const char** argv) {
const char* applicationName = "Mesh shader";
......@@ -194,11 +258,25 @@ int main(int argc, const char** argv) {
return EXIT_FAILURE;
}
vkcv::Buffer<CameraPlanes> cameraPlaneBuffer = core.createBuffer<CameraPlanes>(vkcv::BufferType::UNIFORM, 1);
struct ObjectMatrices {
glm::mat4 model;
glm::mat4 mvp;
};
const size_t objectCount = 1;
vkcv::Buffer<ObjectMatrices> matrixBuffer = core.createBuffer<ObjectMatrices>(vkcv::BufferType::STORAGE, objectCount);
vkcv::DescriptorWrites meshShaderWrites;
meshShaderWrites.storageBufferWrites = {
vkcv::StorageBufferDescriptorWrite(0, meshShaderVertexBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(0, meshShaderVertexBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(1, meshShaderIndexBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(2, meshletBuffer.getHandle()) };
vkcv::StorageBufferDescriptorWrite(2, meshletBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(4, matrixBuffer.getHandle())
};
meshShaderWrites.uniformBufferWrites = {
vkcv::UniformBufferDescriptorWrite(3, cameraPlaneBuffer.getHandle())
};
core.writeDescriptorSet( meshShaderDescriptorSet, meshShaderWrites);
......@@ -212,14 +290,14 @@ int main(int argc, const char** argv) {
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
vkcv::camera::CameraManager cameraManager(window);
uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
vkcv::camera::CameraManager cameraManager(window);
uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2));
while (window.isWindowOpen())
{
vkcv::Window::pollEvents();
vkcv::Window::pollEvents();
uint32_t swapchainWidth, swapchainHeight; // No resizing = No problem
if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
......@@ -232,14 +310,22 @@ int main(int argc, const char** argv) {
cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
glm::mat4 modelMatrix = *reinterpret_cast<glm::mat4*>(&mesh.meshes.front().modelMatrix);
glm::mat4 mvp = cameraManager.getActiveCamera().getMVP() * modelMatrix;
const vkcv::camera::Camera& camera = cameraManager.getActiveCamera();
ObjectMatrices objectMatrices;
objectMatrices.model = *reinterpret_cast<glm::mat4*>(&mesh.meshes.front().modelMatrix);
objectMatrices.mvp = camera.getMVP() * objectMatrices.model;
matrixBuffer.fill({ objectMatrices });
struct PushConstants {
glm::mat4 mvp;
uint32_t meshletCount;
uint32_t matrixIndex;
};
PushConstants pushConstants{ mvp, meshShaderModelData.meshlets.size() };
PushConstants pushConstants{ meshShaderModelData.meshlets.size(), 0 };
const CameraPlanes cameraPlanes = computeCameraPlanes(camera);
cameraPlaneBuffer.fill({ cameraPlanes });
const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment