diff --git a/projects/mesh_shader/resources/shaders/common.inc b/projects/mesh_shader/resources/shaders/common.inc
new file mode 100644
index 0000000000000000000000000000000000000000..280ffee215a8b8342b78d1f5558d63a05e16859b
--- /dev/null
+++ b/projects/mesh_shader/resources/shaders/common.inc
@@ -0,0 +1,4 @@
+struct ObjectMatrices{
+    mat4 model;
+    mat4 mvp;
+};
\ No newline at end of file
diff --git a/projects/mesh_shader/resources/shaders/shader.frag b/projects/mesh_shader/resources/shaders/shader.frag
index f4f6982f2089e6c8e102027f3b8763bb38f8e59c..17bf8f960bb6996f039c4e73e547db802f1ceab4 100644
--- a/projects/mesh_shader/resources/shaders/shader.frag
+++ b/projects/mesh_shader/resources/shaders/shader.frag
@@ -28,5 +28,5 @@ vec3 colorFromIndex(uint i){
 
 void main() {
 	outColor = normalize(passNormal) * 0.5 + 0.5;
-    outColor = colorFromIndex(passTaskIndex);
+    //outColor = colorFromIndex(passTaskIndex);
 }
\ No newline at end of file
diff --git a/projects/mesh_shader/resources/shaders/shader.task b/projects/mesh_shader/resources/shaders/shader.task
index 3f666fbbe6e4031ff2063171992c375301e45c7e..f00e749f911b080450cb4912fbf0c6354b378f43 100644
--- a/projects/mesh_shader/resources/shaders/shader.task
+++ b/projects/mesh_shader/resources/shaders/shader.task
@@ -4,6 +4,7 @@
 #extension GL_GOOGLE_include_directive      : enable
 
 #include "meshlet.inc"
+#include "common.inc"
 
 layout(local_size_x=32) in;
 
@@ -13,31 +14,27 @@ taskNV out Task {
 } OUT;
 
 layout( push_constant ) uniform constants{
-    uint meshletCount;
     uint matrixIndex;
+    uint meshletCount;
 };
 
-layout(std430, binding = 2) readonly buffer meshletBuffer
+// TODO: reuse mesh stage binding at location 2 after required fix in framework
+layout(std430, binding = 5) readonly buffer meshletBuffer
 {
     Meshlet meshlets[];
 };
 
 struct Plane{
-    vec3 pointOnPlane;
-    float padding0;
-    vec3 normal;
-    float padding1;
+    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[];
@@ -49,7 +46,8 @@ bool isSphereInsideFrustum(vec3 spherePos, float sphereRadius, Plane cameraPlane
     bool isInside = true;
     for(int i = 0; i < 6; i++){
         Plane p     = cameraPlanes[i];
-        isInside    = isInside && dot(p.normal, spherePos - p.pointOnPlane) + sphereRadius < 0;
+        isInside    = isInside && dot(p.normal, spherePos - p.pointOnPlane) - sphereRadius < 0;
+        //break;
     }
     return isInside;
 }
@@ -67,7 +65,9 @@ void main() {
         taskCount = 0;
     }
     
-    if(isSphereInsideFrustum(meshlet.meanPosition, meshlet.boundingSphereRadius, cameraPlanes)){
+    // TODO: scaling support
+    vec3 meshletPositionWorld = (vec4(meshlet.meanPosition, 1) * objectMatrices[matrixIndex].model).xyz;
+    if(isSphereInsideFrustum(meshletPositionWorld, meshlet.boundingSphereRadius, cameraPlanes)){
         uint outIndex = atomicAdd(taskCount, 1);
         OUT.meshletIndices[outIndex] = gl_GlobalInvocationID.x;
     }
diff --git a/projects/mesh_shader/resources/shaders/shader.vert b/projects/mesh_shader/resources/shaders/shader.vert
index 636545262a70a490a6aabfd5809a61f226c84a30..fca5057976f995183c040195bdbd592c63f1074e 100644
--- a/projects/mesh_shader/resources/shaders/shader.vert
+++ b/projects/mesh_shader/resources/shaders/shader.vert
@@ -1,5 +1,8 @@
 #version 450
-#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_separate_shader_objects   : enable
+#extension GL_GOOGLE_include_directive      : enable
+
+#include "common.inc"
 
 layout(location = 0) in vec3 inPosition;
 layout(location = 1) in vec3 inNormal;
@@ -7,13 +10,19 @@ layout(location = 1) in vec3 inNormal;
 layout(location = 0) out vec3 passNormal;
 layout(location = 1) out uint dummyOutput;
 
+layout(std430, binding = 0) readonly buffer matrixBuffer
+{
+    ObjectMatrices objectMatrices[];
+};
+
 layout( push_constant ) uniform constants{
-    mat4 mvp;
+    uint matrixIndex;
     uint padding; // pad to same size as mesh shader constants
 };
 
+
 void main()	{
-	gl_Position = mvp * vec4(inPosition, 1.0);
+	gl_Position = objectMatrices[matrixIndex].mvp * vec4(inPosition, 1.0);
 	passNormal  = inNormal;
     
     dummyOutput = padding * 0;  // padding must be used, else compiler shrinks constant size
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index d08564f3f85eb34b08945fd2039ab308dbfc7f0e..d7441d0dd9f0a875e70fd01e4182454977d981a8 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -30,7 +30,7 @@ CameraPlanes computeCameraPlanes(const vkcv::camera::Camera& camera) {
 	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 up    = glm::vec3(0, -1, 0);
 	glm::vec3 right = glm::normalize(glm::cross(forward, up));
 	up              = glm::cross(forward, right);
 
@@ -51,25 +51,25 @@ CameraPlanes computeCameraPlanes(const vkcv::camera::Camera& camera) {
 
 	CameraPlanes cameraPlanes;
 	// near
-	cameraPlanes.planes[0].pointOnPlane  = nearCenter;
-	cameraPlanes.planes[0].normal           = -forward;
+	cameraPlanes.planes[0].pointOnPlane = nearCenter;
+	cameraPlanes.planes[0].normal       = -forward;
 	// far
-	cameraPlanes.planes[1].pointOnPlane  = farCenter;
-	cameraPlanes.planes[1].normal           = forward;
+	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));
+	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));
+	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));
+	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));
+	cameraPlanes.planes[5].pointOnPlane = nearLeftCenter;
+	cameraPlanes.planes[5].normal       = glm::normalize(glm::cross(farLeftCenter - nearLeftCenter, up));
 
 	return cameraPlanes;
 }
@@ -201,16 +201,29 @@ int main(int argc, const char** argv) {
     }
     const vkcv::VertexLayout bunnyLayout (bindings);
 
+	vkcv::DescriptorSetHandle vertexShaderDescriptorSet = core.createDescriptorSet(bunnyShaderProgram.getReflectedDescriptors()[0]);
+
 	const vkcv::PipelineConfig bunnyPipelineDefinition {
-            bunnyShaderProgram,
-            (uint32_t)windowWidth,
-            (uint32_t)windowHeight,
-            renderPass,
-            { bunnyLayout },
-            {},
-            false
+			bunnyShaderProgram,
+			(uint32_t)windowWidth,
+			(uint32_t)windowHeight,
+			renderPass,
+			{ bunnyLayout },
+			{ core.getDescriptorSet(vertexShaderDescriptorSet).layout },
+			false
 	};
 
+	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 vertexShaderDescriptorWrites;
+	vertexShaderDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, matrixBuffer.getHandle()) };
+	core.writeDescriptorSet(vertexShaderDescriptorSet, vertexShaderDescriptorWrites);
+
 	vkcv::PipelineHandle bunnyPipeline = core.createGraphicsPipeline(bunnyPipelineDefinition);
 
 	if (!bunnyPipeline)
@@ -236,9 +249,9 @@ int main(int argc, const char** argv) {
 		meshShaderProgram.addShader(shaderStage, path);
 	});
 
-    uint32_t setID = 0;
-    vkcv::DescriptorSetHandle meshShaderDescriptorSet = core.createDescriptorSet( meshShaderProgram.getReflectedDescriptors()[setID]);
-    const vkcv::VertexLayout meshShaderLayout(bindings);
+	uint32_t setID = 0;
+	vkcv::DescriptorSetHandle meshShaderDescriptorSet = core.createDescriptorSet( meshShaderProgram.getReflectedDescriptors()[setID]);
+	const vkcv::VertexLayout meshShaderLayout(bindings);
 
 	const vkcv::PipelineConfig meshShaderPipelineDefinition{
 		meshShaderProgram,
@@ -260,19 +273,13 @@ int main(int argc, const char** argv) {
 
 	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;
+	vkcv::DescriptorWrites meshShaderWrites;
 	meshShaderWrites.storageBufferWrites = {
 		vkcv::StorageBufferDescriptorWrite(0, meshShaderVertexBuffer.getHandle()),
 		vkcv::StorageBufferDescriptorWrite(1, meshShaderIndexBuffer.getHandle()),
 		vkcv::StorageBufferDescriptorWrite(2, meshletBuffer.getHandle()),
-		vkcv::StorageBufferDescriptorWrite(4, matrixBuffer.getHandle()) 
+		vkcv::StorageBufferDescriptorWrite(4, matrixBuffer.getHandle()),
+		vkcv::StorageBufferDescriptorWrite(5, meshletBuffer.getHandle()),
 	};
 	meshShaderWrites.uniformBufferWrites = {
 		vkcv::UniformBufferDescriptorWrite(3, cameraPlaneBuffer.getHandle())
@@ -295,6 +302,9 @@ int main(int argc, const char** argv) {
 	
 	cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -2));
 
+	bool useMeshShader          = true;
+	bool updateFrustumPlanes    = true;
+
 	while (window.isWindowOpen())
 	{
 		vkcv::Window::pollEvents();
@@ -319,19 +329,19 @@ int main(int argc, const char** argv) {
 		matrixBuffer.fill({ objectMatrices });
 
 		struct PushConstants {
-			uint32_t meshletCount;
 			uint32_t matrixIndex;
+			uint32_t meshletCount;
 		};
-		PushConstants pushConstants{ meshShaderModelData.meshlets.size(), 0 };
+		PushConstants pushConstants{ 0, meshShaderModelData.meshlets.size() };
 
-		const CameraPlanes cameraPlanes = computeCameraPlanes(camera);
-		cameraPlaneBuffer.fill({ cameraPlanes });
+		if (updateFrustumPlanes) {
+			const CameraPlanes cameraPlanes = computeCameraPlanes(camera);
+			cameraPlaneBuffer.fill({ cameraPlanes });
+		}
 
 		const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
 
-		const bool useMeshShader = true;
-
 		vkcv::PushConstants pushConstantData(sizeof(pushConstants));
 		pushConstantData.appendDrawcall(pushConstants);
 
@@ -350,26 +360,31 @@ int main(int argc, const char** argv) {
 		}
 		else {
 
+			vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(vertexShaderDescriptorSet).vulkanHandle);
+
 			core.recordDrawcallsToCmdStream(
 				cmdStream,
 				renderPass,
 				bunnyPipeline,
 				pushConstantData,
-				{ vkcv::DrawcallInfo(renderMesh, {}) },
+				{ vkcv::DrawcallInfo(renderMesh, { descriptorUsage }) },
 				{ renderTargets });
 		}
 
 		core.prepareSwapchainImageForPresent(cmdStream);
 		core.submitCommandStream(cmdStream);
 		
-		// gui.beginGUI();
-		// 
-		// ImGui::Begin("Settings");
-		// ImGui::End();
-		// 
-		// gui.endGUI();
-	    
-	    core.endFrame();
+		gui.beginGUI();
+		
+		ImGui::Begin("Settings");
+		ImGui::Checkbox("Use mesh shader", &useMeshShader);
+		ImGui::Checkbox("Upadte frustum culling", &updateFrustumPlanes);
+
+		ImGui::End();
+		
+		gui.endGUI();
+
+		core.endFrame();
 	}
 	return 0;
 }